summaryrefslogtreecommitdiff
path: root/Source/ThirdParty/ANGLE/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/compiler')
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h148
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.cpp406
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.h93
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/CodeGen.cpp38
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp452
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h257
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.cpp185
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.h80
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.cpp139
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.h52
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.cpp161
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.h46
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp215
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h48
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp564
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Initialize.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.cpp61
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.h33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.cpp40
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp259
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp1500
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp115
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h58
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp26
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp35
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h26
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp817
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h79
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp3133
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h167
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ParseContext.cpp1602
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ParseContext.h134
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Pragma.h19
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp58
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h7
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp77
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h7
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/RenameFunction.h36
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ShHandle.h170
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp387
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp217
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h382
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp43
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp44
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp24
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h27
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Types.h307
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.cpp184
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.h39
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.cpp81
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.h51
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Uniform.cpp21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Uniform.h35
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp512
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h59
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp308
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h51
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VariablePacker.h41
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp140
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h56
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/debug.cpp37
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/debug.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.cpp97
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.h212
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.cpp227
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.h181
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.cpp65
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.h30
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphTraverse.cpp69
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/fuzz/translator_fuzzer.cpp162
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang.l365
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang.y2003
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp424
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/intermediate.h635
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/localintermediate.h57
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/osinclude.h65
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp64
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp57
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp245
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/64bit-tokenizer-safety.patch79
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.cpp182
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.h106
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.cpp2
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.h26
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.cpp502
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.h79
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.cpp555
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.h33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.y459
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.cpp73
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.h37
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.cpp2
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.h8
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.cpp22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.h8
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp182
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.h69
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.cpp79
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.h29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/SourceLocation.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.cpp23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.h38
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.cpp1010
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.l357
-rwxr-xr-xSource/ThirdParty/ANGLE/src/compiler/preprocessor/generate_parser.sh27
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/length_limits.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/numeric_lex.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/pp_utils.h18
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.cpp127
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.h40
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.cpp17
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.h33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/64bit-lexer-safety.patch40
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.cpp452
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.h58
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.cpp59
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.cpp76
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.h22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.cpp212
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BaseTypes.h531
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp106
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.cpp244
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.h85
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp250
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h32
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp494
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Cache.cpp100
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Cache.h90
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.cpp343
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.h75
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp76
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Common.h (renamed from Source/ThirdParty/ANGLE/src/compiler/Common.h)46
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp979
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h260
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp622
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h86
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.cpp189
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/Diagnostics.cpp)34
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.h (renamed from Source/ThirdParty/ANGLE/src/compiler/Diagnostics.h)24
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.cpp197
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.cpp132
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.h29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.cpp718
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.h66
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.cpp154
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.h28
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionBehavior.h (renamed from Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h)12
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.cpp100
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.h39
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.cpp77
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.h43
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.cpp97
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/HashNames.h (renamed from Source/ThirdParty/ANGLE/src/compiler/HashNames.h)9
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp)2
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.h (renamed from Source/ThirdParty/ANGLE/src/compiler/InfoSink.h)8
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.cpp736
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.h29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp)14
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.h (renamed from Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h)6
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeGlobals.h (renamed from Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h)6
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.cpp42
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.h (renamed from Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h)8
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.cpp105
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.h19
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp2863
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h1175
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.cpp104
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/IntermTraverse.cpp792
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.cpp382
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.h74
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.cpp211
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.h80
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/MMap.h (renamed from Source/ThirdParty/ANGLE/src/compiler/MMap.h)6
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/NodeSearch.h (renamed from Source/ThirdParty/ANGLE/src/compiler/NodeSearch.h)33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Operator.cpp227
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Operator.h230
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.cpp38
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.h30
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.cpp102
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.h29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.cpp1264
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.h102
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.cpp2897
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.h226
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.cpp3965
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.h450
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp)139
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.h (renamed from Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h)55
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Pragma.h32
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.cpp111
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.h15
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.cpp646
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.h170
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.cpp162
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.cpp71
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.h41
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.cpp508
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.cpp94
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.h18
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.cpp169
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.h45
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.cpp154
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.cpp124
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.h22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.cpp170
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.h30
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp112
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp276
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h49
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp)9
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.h (renamed from Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h)12
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.cpp91
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.cpp78
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.cpp139
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.h19
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ShaderLang.cpp410
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ShaderVars.cpp488
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.cpp280
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.cpp153
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.h24
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.cpp539
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.h85
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.cpp323
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.h541
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.cpp1274
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.h76
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.cpp109
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.cpp291
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.h30
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.cpp143
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.h36
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Types.cpp487
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/Types.h715
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.cpp54
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.h31
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.cpp184
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.h18
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.cpp473
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.h92
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.cpp153
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.h25
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.cpp414
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.h81
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.cpp112
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.cpp498
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.h63
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.cpp35
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.h29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.cpp108
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.h36
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.cpp210
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.h55
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.cpp693
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.h87
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.cpp (renamed from Source/ThirdParty/ANGLE/src/compiler/VariablePacker.cpp)196
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.h40
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.cpp136
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.h68
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.cpp126
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.h103
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.cpp171
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.h62
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/generate_parser.sh29
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang.h (renamed from Source/ThirdParty/ANGLE/src/compiler/glslang.h)6
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang.l586
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang.y1491
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang_lex.cpp3424
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.cpp4917
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.h253
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/intermOut.cpp723
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/length_limits.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp646
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/translator/util.h76
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/util.cpp28
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/util.h20
296 files changed, 52975 insertions, 20965 deletions
diff --git a/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h b/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h
deleted file mode 100644
index 1631f4f77..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h
+++ /dev/null
@@ -1,148 +0,0 @@
-//
-// 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 _BASICTYPES_INCLUDED_
-#define _BASICTYPES_INCLUDED_
-
-//
-// Precision qualifiers
-//
-enum TPrecision
-{
- // These need to be kept sorted
- EbpUndefined,
- EbpLow,
- EbpMedium,
- EbpHigh
-};
-
-inline const char* getPrecisionString(TPrecision p)
-{
- switch(p)
- {
- case EbpHigh: return "highp"; break;
- case EbpMedium: return "mediump"; break;
- case EbpLow: return "lowp"; break;
- default: return "mediump"; break; // Safest fallback
- }
-}
-
-//
-// Basic type. Arrays, vectors, etc., are orthogonal to this.
-//
-enum TBasicType
-{
- EbtVoid,
- EbtFloat,
- EbtInt,
- EbtBool,
- EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
- EbtSampler2D,
- EbtSamplerCube,
- EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
- EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
- EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
- EbtStruct,
- EbtAddress, // should be deprecated??
- EbtInvariant // used as a type when qualifying a previously declared variable as being invariant
-};
-
-inline const char* getBasicString(TBasicType t)
-{
- switch (t)
- {
- case EbtVoid: return "void"; break;
- case EbtFloat: return "float"; break;
- case EbtInt: return "int"; break;
- case EbtBool: return "bool"; break;
- case EbtSampler2D: return "sampler2D"; break;
- case EbtSamplerCube: return "samplerCube"; break;
- case EbtSamplerExternalOES: return "samplerExternalOES"; break;
- case EbtSampler2DRect: return "sampler2DRect"; break;
- case EbtStruct: return "structure"; break;
- default: return "unknown type";
- }
-}
-
-inline bool IsSampler(TBasicType type)
-{
- return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
-}
-
-//
-// 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
- EvqInvariantVaryingIn, // readonly, fragment shaders only
- EvqInvariantVaryingOut, // vertex shaders only read/write
- EvqUniform, // Readonly, vertex and fragment
-
- // parameters
- EvqIn,
- EvqOut,
- EvqInOut,
- EvqConstReadOnly,
-
- // built-ins written by vertex shader
- EvqPosition,
- EvqPointSize,
-
- // built-ins read by fragment shader
- EvqFragCoord,
- EvqFrontFacing,
- EvqPointCoord,
-
- // built-ins written by fragment shader
- EvqFragColor,
- EvqFragData,
- EvqFragDepth,
-
- // end of list
- EvqLast
-};
-
-//
-// This is just for debug print out, carried along with the definitions above.
-//
-inline const char* getQualifierString(TQualifier q)
-{
- switch(q)
- {
- case EvqTemporary: return "Temporary"; break;
- case EvqGlobal: return "Global"; break;
- case EvqConst: return "const"; break;
- case EvqConstReadOnly: return "const"; break;
- case EvqAttribute: return "attribute"; break;
- case EvqVaryingIn: return "varying"; break;
- case EvqVaryingOut: return "varying"; break;
- case EvqInvariantVaryingIn: return "invariant varying"; break;
- case EvqInvariantVaryingOut:return "invariant varying"; break;
- case EvqUniform: return "uniform"; break;
- case EvqIn: return "in"; break;
- case EvqOut: return "out"; break;
- case EvqInOut: return "inout"; break;
- case EvqPosition: return "Position"; break;
- case EvqPointSize: return "PointSize"; break;
- case EvqFragCoord: return "FragCoord"; break;
- case EvqFrontFacing: return "FrontFacing"; break;
- case EvqFragColor: return "FragColor"; break;
- case EvqFragData: return "FragData"; break;
- case EvqFragDepth: return "FragDepth"; break;
- default: return "unknown qualifier";
- }
-}
-
-#endif // _BASICTYPES_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.cpp b/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.cpp
deleted file mode 100644
index 1c4b25f13..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-//
-// 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/BuiltInFunctionEmulator.h"
-
-#include "compiler/SymbolTable.h"
-
-namespace {
-
-// we use macros here instead of function definitions to work around more GLSL
-// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
-// problematic because if the argument has side-effects they will be repeatedly
-// evaluated. This is unlikely to show up in real shaders, but is something to
-// consider.
-const char* kFunctionEmulationVertexSource[] = {
- "#error no emulation for cos(float)",
- "#error no emulation for cos(vec2)",
- "#error no emulation for cos(vec3)",
- "#error no emulation for cos(vec4)",
-
- "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
- "#error no emulation for distance(vec2, vec2)",
- "#error no emulation for distance(vec3, vec3)",
- "#error no emulation for distance(vec4, vec4)",
-
- "#define webgl_dot_emu(x, y) ((x) * (y))",
- "#error no emulation for dot(vec2, vec2)",
- "#error no emulation for dot(vec3, vec3)",
- "#error no emulation for dot(vec4, vec4)",
-
- "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
- "#error no emulation for length(vec2)",
- "#error no emulation for length(vec3)",
- "#error no emulation for length(vec4)",
-
- "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
- "#error no emulation for normalize(vec2)",
- "#error no emulation for normalize(vec3)",
- "#error no emulation for normalize(vec4)",
-
- "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
- "#error no emulation for reflect(vec2, vec2)",
- "#error no emulation for reflect(vec3, vec3)",
- "#error no emulation for reflect(vec4, vec4)"
-};
-
-const char* kFunctionEmulationFragmentSource[] = {
- "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
- "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
- "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
- "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
-
- "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
- "#error no emulation for distance(vec2, vec2)",
- "#error no emulation for distance(vec3, vec3)",
- "#error no emulation for distance(vec4, vec4)",
-
- "#define webgl_dot_emu(x, y) ((x) * (y))",
- "#error no emulation for dot(vec2, vec2)",
- "#error no emulation for dot(vec3, vec3)",
- "#error no emulation for dot(vec4, vec4)",
-
- "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
- "#error no emulation for length(vec2)",
- "#error no emulation for length(vec3)",
- "#error no emulation for length(vec4)",
-
- "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
- "#error no emulation for normalize(vec2)",
- "#error no emulation for normalize(vec3)",
- "#error no emulation for normalize(vec4)",
-
- "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
- "#error no emulation for reflect(vec2, vec2)",
- "#error no emulation for reflect(vec3, vec3)",
- "#error no emulation for reflect(vec4, vec4)"
-};
-
-const bool kFunctionEmulationVertexMask[] = {
-#if defined(__APPLE__)
- // Work around ATI driver bugs in Mac.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- true, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- true, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- true, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- true, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- true, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#else
- // Work around D3D driver bug in Win.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- false, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- false, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- false, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- false, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- false, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#endif
- false // TFunctionUnknown
-};
-
-const bool kFunctionEmulationFragmentMask[] = {
-#if defined(__APPLE__)
- // Work around ATI driver bugs in Mac.
- true, // TFunctionCos1
- true, // TFunctionCos2
- true, // TFunctionCos3
- true, // TFunctionCos4
- true, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- true, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- true, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- true, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- true, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#else
- // Work around D3D driver bug in Win.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- false, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- false, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- false, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- false, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- false, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#endif
- false // TFunctionUnknown
-};
-
-class BuiltInFunctionEmulationMarker : public TIntermTraverser {
-public:
- BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
- : mEmulator(emulator)
- {
- }
-
- virtual bool visitUnary(Visit visit, TIntermUnary* node)
- {
- if (visit == PreVisit) {
- bool needToEmulate = mEmulator.SetFunctionCalled(
- node->getOp(), node->getOperand()->getType());
- if (needToEmulate)
- node->setUseEmulatedFunction();
- }
- return true;
- }
-
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
- {
- if (visit == PreVisit) {
- // Here we handle all the built-in functions instead of the ones we
- // currently identified as problematic.
- switch (node->getOp()) {
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpVectorEqual:
- case EOpVectorNotEqual:
- case EOpMod:
- case EOpPow:
- case EOpAtan:
- case EOpMin:
- case EOpMax:
- case EOpClamp:
- case EOpMix:
- case EOpStep:
- case EOpSmoothStep:
- case EOpDistance:
- case EOpDot:
- case EOpCross:
- case EOpFaceForward:
- case EOpReflect:
- case EOpRefract:
- case EOpMul:
- break;
- default:
- return true;
- };
- const TIntermSequence& sequence = node->getSequence();
- // Right now we only handle built-in functions with two parameters.
- if (sequence.size() != 2)
- return true;
- TIntermTyped* param1 = sequence[0]->getAsTyped();
- TIntermTyped* param2 = sequence[1]->getAsTyped();
- if (!param1 || !param2)
- return true;
- bool needToEmulate = mEmulator.SetFunctionCalled(
- node->getOp(), param1->getType(), param2->getType());
- if (needToEmulate)
- node->setUseEmulatedFunction();
- }
- return true;
- }
-
-private:
- BuiltInFunctionEmulator& mEmulator;
-};
-
-} // anonymous namepsace
-
-BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
-{
- if (shaderType == SH_FRAGMENT_SHADER) {
- mFunctionMask = kFunctionEmulationFragmentMask;
- mFunctionSource = kFunctionEmulationFragmentSource;
- } else {
- mFunctionMask = kFunctionEmulationVertexMask;
- mFunctionSource = kFunctionEmulationVertexSource;
- }
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- TOperator op, const TType& param)
-{
- TBuiltInFunction function = IdentifyFunction(op, param);
- return SetFunctionCalled(function);
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- TOperator op, const TType& param1, const TType& param2)
-{
- TBuiltInFunction function = IdentifyFunction(op, param1, param2);
- return SetFunctionCalled(function);
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- BuiltInFunctionEmulator::TBuiltInFunction function) {
- if (function == TFunctionUnknown || mFunctionMask[function] == false)
- return false;
- for (size_t i = 0; i < mFunctions.size(); ++i) {
- if (mFunctions[i] == function)
- return true;
- }
- mFunctions.push_back(function);
- return true;
-}
-
-void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
- TInfoSinkBase& out, bool withPrecision) const
-{
- if (mFunctions.size() == 0)
- return;
- out << "// BEGIN: Generated code for built-in function emulation\n\n";
- if (withPrecision) {
- out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
- << "#define webgl_emu_precision highp\n"
- << "#else\n"
- << "#define webgl_emu_precision mediump\n"
- << "#endif\n\n";
- } else {
- out << "#define webgl_emu_precision\n\n";
- }
- for (size_t i = 0; i < mFunctions.size(); ++i) {
- out << mFunctionSource[mFunctions[i]] << "\n\n";
- }
- out << "// END: Generated code for built-in function emulation\n\n";
-}
-
-BuiltInFunctionEmulator::TBuiltInFunction
-BuiltInFunctionEmulator::IdentifyFunction(
- TOperator op, const TType& param)
-{
- if (param.getNominalSize() > 4)
- return TFunctionUnknown;
- unsigned int function = TFunctionUnknown;
- switch (op) {
- case EOpCos:
- function = TFunctionCos1;
- break;
- case EOpLength:
- function = TFunctionLength1;
- break;
- case EOpNormalize:
- function = TFunctionNormalize1;
- break;
- default:
- break;
- }
- if (function == TFunctionUnknown)
- return TFunctionUnknown;
- if (param.isVector())
- function += param.getNominalSize() - 1;
- return static_cast<TBuiltInFunction>(function);
-}
-
-BuiltInFunctionEmulator::TBuiltInFunction
-BuiltInFunctionEmulator::IdentifyFunction(
- TOperator op, const TType& param1, const TType& param2)
-{
- // Right now for all the emulated functions with two parameters, the two
- // parameters have the same type.
- if (param1.isVector() != param2.isVector() ||
- param1.getNominalSize() != param2.getNominalSize() ||
- param1.getNominalSize() > 4)
- return TFunctionUnknown;
-
- unsigned int function = TFunctionUnknown;
- switch (op) {
- case EOpDistance:
- function = TFunctionDistance1_1;
- break;
- case EOpDot:
- function = TFunctionDot1_1;
- break;
- case EOpReflect:
- function = TFunctionReflect1_1;
- break;
- default:
- break;
- }
- if (function == TFunctionUnknown)
- return TFunctionUnknown;
- if (param1.isVector())
- function += param1.getNominalSize() - 1;
- return static_cast<TBuiltInFunction>(function);
-}
-
-void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
- TIntermNode* root)
-{
- ASSERT(root);
-
- BuiltInFunctionEmulationMarker marker(*this);
- root->traverse(&marker);
-}
-
-void BuiltInFunctionEmulator::Cleanup()
-{
- mFunctions.clear();
-}
-
-//static
-TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
- const TString& name)
-{
- ASSERT(name[name.length() - 1] == '(');
- return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.h b/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.h
deleted file mode 100644
index 0d904f41d..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/BuiltInFunctionEmulator.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//
-// 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 COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
-#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/InfoSink.h"
-#include "compiler/intermediate.h"
-
-//
-// This class decides which built-in functions need to be replaced with the
-// emulated ones.
-// It's only a workaround for OpenGL driver bugs, and isn't needed in general.
-//
-class BuiltInFunctionEmulator {
-public:
- BuiltInFunctionEmulator(ShShaderType shaderType);
- // Records that a function is called by the shader and might needs to be
- // emulated. If the function's group is not in mFunctionGroupFilter, this
- // becomes an no-op.
- // Returns true if the function call needs to be replaced with an emulated
- // one.
- bool SetFunctionCalled(TOperator op, const TType& param);
- bool SetFunctionCalled(
- TOperator op, const TType& param1, const TType& param2);
-
- // Output function emulation definition. This should be before any other
- // shader source.
- void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const;
-
- void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
-
- void Cleanup();
-
- // "name(" becomes "webgl_name_emu(".
- static TString GetEmulatedFunctionName(const TString& name);
-
-private:
- //
- // Built-in functions.
- //
- enum TBuiltInFunction {
- TFunctionCos1 = 0, // float cos(float);
- TFunctionCos2, // vec2 cos(vec2);
- TFunctionCos3, // vec3 cos(vec3);
- TFunctionCos4, // vec4 cos(vec4);
-
- TFunctionDistance1_1, // float distance(float, float);
- TFunctionDistance2_2, // vec2 distance(vec2, vec2);
- TFunctionDistance3_3, // vec3 distance(vec3, vec3);
- TFunctionDistance4_4, // vec4 distance(vec4, vec4);
-
- TFunctionDot1_1, // float dot(float, float);
- TFunctionDot2_2, // vec2 dot(vec2, vec2);
- TFunctionDot3_3, // vec3 dot(vec3, vec3);
- TFunctionDot4_4, // vec4 dot(vec4, vec4);
-
- TFunctionLength1, // float length(float);
- TFunctionLength2, // float length(vec2);
- TFunctionLength3, // float length(vec3);
- TFunctionLength4, // float length(vec4);
-
- TFunctionNormalize1, // float normalize(float);
- TFunctionNormalize2, // vec2 normalize(vec2);
- TFunctionNormalize3, // vec3 normalize(vec3);
- TFunctionNormalize4, // vec4 normalize(vec4);
-
- TFunctionReflect1_1, // float reflect(float, float);
- TFunctionReflect2_2, // vec2 reflect(vec2, vec2);
- TFunctionReflect3_3, // vec3 reflect(vec3, vec3);
- TFunctionReflect4_4, // vec4 reflect(vec4, vec4);
-
- TFunctionUnknown
- };
-
- TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
- TBuiltInFunction IdentifyFunction(
- TOperator op, const TType& param1, const TType& param2);
-
- bool SetFunctionCalled(TBuiltInFunction function);
-
- std::vector<TBuiltInFunction> mFunctions;
-
- const bool* mFunctionMask; // a boolean flag for each function.
- const char** mFunctionSource;
-};
-
-#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/CodeGen.cpp b/Source/ThirdParty/ANGLE/src/compiler/CodeGen.cpp
deleted file mode 100644
index 24f21b876..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/CodeGen.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// 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/TranslatorESSL.h"
-#include "compiler/TranslatorGLSL.h"
-#include "compiler/TranslatorHLSL.h"
-
-//
-// This function must be provided to create the actual
-// compile object used by higher level code. It returns
-// a subclass of TCompiler.
-//
-TCompiler* ConstructCompiler(
- ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
-{
- switch (output) {
- case SH_ESSL_OUTPUT:
- return new TranslatorESSL(type, spec);
- case SH_GLSL_OUTPUT:
- return new TranslatorGLSL(type, spec);
- case SH_HLSL9_OUTPUT:
- case SH_HLSL11_OUTPUT:
- return new TranslatorHLSL(type, spec, output);
- default:
- return NULL;
- }
-}
-
-//
-// Delete the compiler made by ConstructCompiler
-//
-void DeleteCompiler(TCompiler* compiler)
-{
- delete compiler;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp b/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp
deleted file mode 100644
index c2b4ef602..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp
+++ /dev/null
@@ -1,452 +0,0 @@
-//
-// 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/BuiltInFunctionEmulator.h"
-#include "compiler/DetectCallDepth.h"
-#include "compiler/ForLoopUnroll.h"
-#include "compiler/Initialize.h"
-#include "compiler/InitializeGLPosition.h"
-#include "compiler/InitializeParseContext.h"
-#include "compiler/MapLongVariableNames.h"
-#include "compiler/ParseContext.h"
-#include "compiler/RenameFunction.h"
-#include "compiler/ShHandle.h"
-#include "compiler/UnfoldShortCircuitAST.h"
-#include "compiler/ValidateLimitations.h"
-#include "compiler/VariablePacker.h"
-#include "compiler/depgraph/DependencyGraph.h"
-#include "compiler/depgraph/DependencyGraphOutput.h"
-#include "compiler/timing/RestrictFragmentShaderTiming.h"
-#include "compiler/timing/RestrictVertexShaderTiming.h"
-#include "third_party/compiler/ArrayBoundsClamper.h"
-
-bool isWebGLBasedSpec(ShShaderSpec spec)
-{
- return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
-}
-
-namespace {
-class TScopedPoolAllocator {
-public:
- TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) {
- mAllocator->push();
- SetGlobalPoolAllocator(mAllocator);
- }
- ~TScopedPoolAllocator() {
- SetGlobalPoolAllocator(NULL);
- mAllocator->pop();
- }
-
-private:
- TPoolAllocator* mAllocator;
-};
-
-class TScopedSymbolTableLevel {
-public:
- TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) {
- ASSERT(mTable->atBuiltInLevel());
- mTable->push();
- }
- ~TScopedSymbolTableLevel() {
- while (!mTable->atBuiltInLevel())
- mTable->pop();
- }
-
-private:
- TSymbolTable* mTable;
-};
-} // namespace
-
-TShHandleBase::TShHandleBase() {
- allocator.push();
- SetGlobalPoolAllocator(&allocator);
-}
-
-TShHandleBase::~TShHandleBase() {
- SetGlobalPoolAllocator(NULL);
- allocator.popAll();
-}
-
-TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
- : shaderType(type),
- shaderSpec(spec),
- maxUniformVectors(0),
- maxVaryingVectors(0),
- maxExpressionComplexity(0),
- maxCallStackDepth(0),
- fragmentPrecisionHigh(false),
- clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
- builtInFunctionEmulator(type)
-{
- longNameMap = LongNameMap::GetInstance();
-}
-
-TCompiler::~TCompiler()
-{
- ASSERT(longNameMap);
- longNameMap->Release();
-}
-
-bool TCompiler::Init(const ShBuiltInResources& resources)
-{
- maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
- resources.MaxVertexUniformVectors :
- resources.MaxFragmentUniformVectors;
- maxVaryingVectors = resources.MaxVaryingVectors;
- maxExpressionComplexity = resources.MaxExpressionComplexity;
- maxCallStackDepth = resources.MaxCallStackDepth;
-
- SetGlobalPoolAllocator(&allocator);
-
- // Generate built-in symbol table.
- if (!InitBuiltInSymbolTable(resources))
- return false;
- InitExtensionBehavior(resources, extensionBehavior);
- fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
-
- arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
- clampingStrategy = resources.ArrayIndexClampingStrategy;
-
- hashFunction = resources.HashFunction;
-
- return true;
-}
-
-bool TCompiler::compile(const char* const shaderStrings[],
- size_t numStrings,
- int compileOptions)
-{
- TScopedPoolAllocator scopedAlloc(&allocator);
- clearResults();
-
- if (numStrings == 0)
- return true;
-
- // If compiling for WebGL, validate loop and indexing as well.
- if (isWebGLBasedSpec(shaderSpec))
- compileOptions |= SH_VALIDATE_LOOP_INDEXING;
-
- // First string is path of source file if flag is set. The actual source follows.
- const char* sourcePath = NULL;
- size_t firstSource = 0;
- if (compileOptions & SH_SOURCE_PATH)
- {
- sourcePath = shaderStrings[0];
- ++firstSource;
- }
-
- TIntermediate intermediate(infoSink);
- TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
- shaderType, shaderSpec, compileOptions, true,
- sourcePath, infoSink);
- parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
- SetGlobalParseContext(&parseContext);
-
- // We preserve symbols at the built-in level from compile-to-compile.
- // Start pushing the user-defined symbols at global level.
- TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
-
- // Parse shader.
- bool success =
- (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
- (parseContext.treeRoot != NULL);
- if (success) {
- TIntermNode* root = parseContext.treeRoot;
- success = intermediate.postProcess(root);
-
- if (success)
- success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
-
- if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
- success = validateLimitations(root);
-
- if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
- success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
-
- if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
- rewriteCSSShader(root);
-
- // Unroll for-loop markup needs to happen after validateLimitations pass.
- if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
- ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
-
- // Built-in function emulation needs to happen after validateLimitations pass.
- if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
- builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
-
- // Clamping uniform array bounds needs to happen after validateLimitations pass.
- if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
- arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
-
- // Disallow expressions deemed too complex.
- if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
- success = limitExpressionComplexity(root);
-
- // Call mapLongVariableNames() before collectAttribsUniforms() so in
- // collectAttribsUniforms() we already have the mapped symbol names and
- // we could composite mapped and original variable names.
- // Also, if we hash all the names, then no need to do this for long names.
- if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
- mapLongVariableNames(root);
-
- if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) {
- InitializeGLPosition initGLPosition;
- root->traverse(&initGLPosition);
- }
-
- if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) {
- UnfoldShortCircuitAST unfoldShortCircuit;
- root->traverse(&unfoldShortCircuit);
- unfoldShortCircuit.updateTree();
- }
-
- if (success && (compileOptions & SH_VARIABLES)) {
- collectVariables(root);
- if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
- success = enforcePackingRestrictions();
- }
-
- if (success && (compileOptions & SH_INTERMEDIATE_TREE))
- intermediate.outputTree(root);
-
- if (success && (compileOptions & SH_OBJECT_CODE))
- translate(root);
- }
-
- // Cleanup memory.
- intermediate.remove(parseContext.treeRoot);
-
- return success;
-}
-
-bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
-{
- compileResources = resources;
-
- assert(symbolTable.isEmpty());
- symbolTable.push();
-
- TPublicType integer;
- integer.type = EbtInt;
- integer.size = 1;
- integer.matrix = false;
- integer.array = false;
-
- TPublicType floatingPoint;
- floatingPoint.type = EbtFloat;
- floatingPoint.size = 1;
- floatingPoint.matrix = false;
- floatingPoint.array = false;
-
- TPublicType sampler;
- sampler.size = 1;
- sampler.matrix = false;
- sampler.array = false;
-
- switch(shaderType)
- {
- case SH_FRAGMENT_SHADER:
- symbolTable.setDefaultPrecision(integer, EbpMedium);
- break;
- case SH_VERTEX_SHADER:
- symbolTable.setDefaultPrecision(integer, EbpHigh);
- symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
- break;
- default: assert(false && "Language not supported");
- }
- // We set defaults for all the sampler types, even those that are
- // only available if an extension exists.
- for (int samplerType = EbtGuardSamplerBegin + 1;
- samplerType < EbtGuardSamplerEnd; ++samplerType) {
- sampler.type = static_cast<TBasicType>(samplerType);
- symbolTable.setDefaultPrecision(sampler, EbpLow);
- }
-
- InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
-
- IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
-
- return true;
-}
-
-void TCompiler::clearResults()
-{
- arrayBoundsClamper.Cleanup();
- infoSink.info.erase();
- infoSink.obj.erase();
- infoSink.debug.erase();
-
- attribs.clear();
- uniforms.clear();
- varyings.clear();
-
- builtInFunctionEmulator.Cleanup();
-
- nameMap.clear();
-}
-
-bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
-{
- DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
- root->traverse(&detect);
- switch (detect.detectCallDepth()) {
- case DetectCallDepth::kErrorNone:
- return true;
- case DetectCallDepth::kErrorMissingMain:
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Missing main()";
- return false;
- case DetectCallDepth::kErrorRecursion:
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Function recursion detected";
- return false;
- case DetectCallDepth::kErrorMaxDepthExceeded:
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Function call stack too deep";
- return false;
- default:
- UNREACHABLE();
- return false;
- }
-}
-
-void TCompiler::rewriteCSSShader(TIntermNode* root)
-{
- RenameFunction renamer("main(", "css_main(");
- root->traverse(&renamer);
-}
-
-bool TCompiler::validateLimitations(TIntermNode* root) {
- ValidateLimitations validate(shaderType, infoSink.info);
- root->traverse(&validate);
- return validate.numErrors() == 0;
-}
-
-bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
-{
- if (shaderSpec != SH_WEBGL_SPEC) {
- infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
- return false;
- }
-
- if (shaderType == SH_FRAGMENT_SHADER) {
- TDependencyGraph graph(root);
-
- // Output any errors first.
- bool success = enforceFragmentShaderTimingRestrictions(graph);
-
- // Then, output the dependency graph.
- if (outputGraph) {
- TDependencyGraphOutput output(infoSink.info);
- output.outputAllSpanningTrees(graph);
- }
-
- return success;
- }
- else {
- return enforceVertexShaderTimingRestrictions(root);
- }
-}
-
-bool TCompiler::limitExpressionComplexity(TIntermNode* root)
-{
- TIntermTraverser traverser;
- root->traverse(&traverser);
- TDependencyGraph graph(root);
-
- for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
- iter != graph.endUserDefinedFunctionCalls();
- ++iter)
- {
- TGraphFunctionCall* samplerSymbol = *iter;
- TDependencyGraphTraverser graphTraverser;
- samplerSymbol->traverse(&graphTraverser);
- }
-
- if (traverser.getMaxDepth() > maxExpressionComplexity) {
- infoSink.info << "Expression too complex.";
- return false;
- }
- return true;
-}
-
-bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
-{
- RestrictFragmentShaderTiming restrictor(infoSink.info);
- restrictor.enforceRestrictions(graph);
- return restrictor.numErrors() == 0;
-}
-
-bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
-{
- RestrictVertexShaderTiming restrictor(infoSink.info);
- restrictor.enforceRestrictions(root);
- return restrictor.numErrors() == 0;
-}
-
-void TCompiler::collectVariables(TIntermNode* root)
-{
- CollectVariables collect(attribs, uniforms, varyings, hashFunction);
- root->traverse(&collect);
-}
-
-bool TCompiler::enforcePackingRestrictions()
-{
- VariablePacker packer;
- bool success = packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
- if (!success) {
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "too many uniforms";
- return false;
- }
-
- success = packer.CheckVariablesWithinPackingLimits(maxVaryingVectors, varyings);
-
- if (!success) {
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "too many varyings";
- return false;
- }
-
- return true;
-}
-
-void TCompiler::mapLongVariableNames(TIntermNode* root)
-{
- ASSERT(longNameMap);
- MapLongVariableNames map(longNameMap);
- root->traverse(&map);
-}
-
-int TCompiler::getMappedNameMaxLength() const
-{
- return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
-}
-
-const TExtensionBehavior& TCompiler::getExtensionBehavior() const
-{
- return extensionBehavior;
-}
-
-const ShBuiltInResources& TCompiler::getResources() const
-{
- return compileResources;
-}
-
-const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
-{
- return arrayBoundsClamper;
-}
-
-ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
-{
- return clampingStrategy;
-}
-
-const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
-{
- return builtInFunctionEmulator;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h b/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h
deleted file mode 100644
index b1e37885f..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h
+++ /dev/null
@@ -1,257 +0,0 @@
-//
-// 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 _CONSTANT_UNION_INCLUDED_
-#define _CONSTANT_UNION_INCLUDED_
-
-#include <assert.h>
-
-class ConstantUnion {
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- ConstantUnion()
- {
- iConst = 0;
- type = EbtVoid;
- }
-
- void setIConst(int i) {iConst = i; type = EbtInt; }
- void setFConst(float f) {fConst = f; type = EbtFloat; }
- void setBConst(bool b) {bConst = b; type = EbtBool; }
-
- int getIConst() { return iConst; }
- float getFConst() { return fConst; }
- bool getBConst() { return bConst; }
- int getIConst() const { return iConst; }
- float getFConst() const { return fConst; }
- bool getBConst() const { return bConst; }
-
- bool operator==(const int i) const
- {
- return i == iConst;
- }
-
- bool operator==(const float f) const
- {
- return f == fConst;
- }
-
- bool operator==(const bool b) const
- {
- return b == bConst;
- }
-
- bool operator==(const ConstantUnion& constant) const
- {
- if (constant.type != type)
- return false;
-
- switch (type) {
- case EbtInt:
- return constant.iConst == iConst;
- case EbtFloat:
- return constant.fConst == fConst;
- case EbtBool:
- return constant.bConst == bConst;
- default:
- return false;
- }
- }
-
- bool operator!=(const int i) const
- {
- return !operator==(i);
- }
-
- bool operator!=(const float f) const
- {
- return !operator==(f);
- }
-
- bool operator!=(const bool b) const
- {
- return !operator==(b);
- }
-
- bool operator!=(const ConstantUnion& constant) const
- {
- return !operator==(constant);
- }
-
- bool operator>(const ConstantUnion& constant) const
- {
- assert(type == constant.type);
- switch (type) {
- case EbtInt:
- return iConst > constant.iConst;
- case EbtFloat:
- return fConst > constant.fConst;
- default:
- return false; // Invalid operation, handled at semantic analysis
- }
- }
-
- bool operator<(const ConstantUnion& constant) const
- {
- assert(type == constant.type);
- switch (type) {
- case EbtInt:
- return iConst < constant.iConst;
- case EbtFloat:
- return fConst < constant.fConst;
- default:
- return false; // Invalid operation, handled at semantic analysis
- }
- }
-
- ConstantUnion operator+(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
- case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator-(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
- case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator*(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
- case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator%(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator>>(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator<<(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator&(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator|(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator^(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator&&(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- ConstantUnion operator||(const ConstantUnion& constant) const
- {
- ConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- TBasicType getType() const { return type; }
-private:
-
- union {
- int iConst; // used for ivec, scalar ints
- bool bConst; // used for bvec, scalar bools
- float fConst; // used for vec, mat, scalar floats
- } ;
-
- TBasicType type;
-};
-
-#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.cpp b/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.cpp
deleted file mode 100644
index 60df52c71..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-// 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/DetectCallDepth.h"
-#include "compiler/InfoSink.h"
-
-DetectCallDepth::FunctionNode::FunctionNode(const TString& fname)
- : name(fname),
- visit(PreVisit)
-{
-}
-
-const TString& DetectCallDepth::FunctionNode::getName() const
-{
- return name;
-}
-
-void DetectCallDepth::FunctionNode::addCallee(
- DetectCallDepth::FunctionNode* callee)
-{
- for (size_t i = 0; i < callees.size(); ++i) {
- if (callees[i] == callee)
- return;
- }
- callees.push_back(callee);
-}
-
-int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth)
-{
- ASSERT(visit == PreVisit);
- ASSERT(detectCallDepth);
-
- int maxDepth = depth;
- visit = InVisit;
- for (size_t i = 0; i < callees.size(); ++i) {
- switch (callees[i]->visit) {
- case InVisit:
- // cycle detected, i.e., recursion detected.
- return kInfiniteCallDepth;
- case PostVisit:
- break;
- case PreVisit: {
- // Check before we recurse so we don't go too depth
- if (detectCallDepth->checkExceedsMaxDepth(depth))
- return depth;
- int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1);
- // Check after we recurse so we can exit immediately and provide info.
- if (detectCallDepth->checkExceedsMaxDepth(callDepth)) {
- detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName();
- return callDepth;
- }
- maxDepth = std::max(callDepth, maxDepth);
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
- }
- visit = PostVisit;
- return maxDepth;
-}
-
-void DetectCallDepth::FunctionNode::reset()
-{
- visit = PreVisit;
-}
-
-DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth)
- : TIntermTraverser(true, false, true, false),
- currentFunction(NULL),
- infoSink(infoSink),
- maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth)
-{
-}
-
-DetectCallDepth::~DetectCallDepth()
-{
- for (size_t i = 0; i < functions.size(); ++i)
- delete functions[i];
-}
-
-bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- switch (node->getOp())
- {
- case EOpPrototype:
- // Function declaration.
- // Don't add FunctionNode here because node->getName() is the
- // unmangled function name.
- break;
- case EOpFunction: {
- // Function definition.
- if (visit == PreVisit) {
- currentFunction = findFunctionByName(node->getName());
- if (currentFunction == NULL) {
- currentFunction = new FunctionNode(node->getName());
- functions.push_back(currentFunction);
- }
- } else if (visit == PostVisit) {
- currentFunction = NULL;
- }
- break;
- }
- case EOpFunctionCall: {
- // Function call.
- if (visit == PreVisit) {
- FunctionNode* func = findFunctionByName(node->getName());
- if (func == NULL) {
- func = new FunctionNode(node->getName());
- functions.push_back(func);
- }
- if (currentFunction)
- currentFunction->addCallee(func);
- }
- break;
- }
- default:
- break;
- }
- return true;
-}
-
-bool DetectCallDepth::checkExceedsMaxDepth(int depth)
-{
- return depth >= maxDepth;
-}
-
-void DetectCallDepth::resetFunctionNodes()
-{
- for (size_t i = 0; i < functions.size(); ++i) {
- functions[i]->reset();
- }
-}
-
-DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func)
-{
- currentFunction = NULL;
- resetFunctionNodes();
-
- int maxCallDepth = func->detectCallDepth(this, 1);
-
- if (maxCallDepth == FunctionNode::kInfiniteCallDepth)
- return kErrorRecursion;
-
- if (maxCallDepth >= maxDepth)
- return kErrorMaxDepthExceeded;
-
- return kErrorNone;
-}
-
-DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth()
-{
- if (maxDepth != FunctionNode::kInfiniteCallDepth) {
- // Check all functions because the driver may fail on them
- // TODO: Before detectingRecursion, strip unused functions.
- for (size_t i = 0; i < functions.size(); ++i) {
- ErrorCode error = detectCallDepthForFunction(functions[i]);
- if (error != kErrorNone)
- return error;
- }
- } else {
- FunctionNode* main = findFunctionByName("main(");
- if (main == NULL)
- return kErrorMissingMain;
-
- return detectCallDepthForFunction(main);
- }
-
- return kErrorNone;
-}
-
-DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName(
- const TString& name)
-{
- for (size_t i = 0; i < functions.size(); ++i) {
- if (functions[i]->getName() == name)
- return functions[i];
- }
- return NULL;
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.h b/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.h
deleted file mode 100644
index 89e85f88f..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DetectCallDepth.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// 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_DETECT_RECURSION_H_
-#define COMPILER_DETECT_RECURSION_H_
-
-#include "GLSLANG/ShaderLang.h"
-
-#include <limits.h>
-#include "compiler/intermediate.h"
-#include "compiler/VariableInfo.h"
-
-class TInfoSink;
-
-// Traverses intermediate tree to detect function recursion.
-class DetectCallDepth : public TIntermTraverser {
-public:
- enum ErrorCode {
- kErrorMissingMain,
- kErrorRecursion,
- kErrorMaxDepthExceeded,
- kErrorNone
- };
-
- DetectCallDepth(TInfoSink& infoSync, bool limitCallStackDepth, int maxCallStackDepth);
- ~DetectCallDepth();
-
- virtual bool visitAggregate(Visit, TIntermAggregate*);
-
- bool checkExceedsMaxDepth(int depth);
-
- ErrorCode detectCallDepth();
-
-private:
- class FunctionNode {
- public:
- static const int kInfiniteCallDepth = INT_MAX;
-
- FunctionNode(const TString& fname);
-
- const TString& getName() const;
-
- // If a function is already in the callee list, this becomes a no-op.
- void addCallee(FunctionNode* callee);
-
- // Returns kInifinityCallDepth if recursive function calls are detected.
- int detectCallDepth(DetectCallDepth* detectCallDepth, int depth);
-
- // Reset state.
- void reset();
-
- private:
- // mangled function name is unique.
- TString name;
-
- // functions that are directly called by this function.
- TVector<FunctionNode*> callees;
-
- Visit visit;
- };
-
- ErrorCode detectCallDepthForFunction(FunctionNode* func);
- FunctionNode* findFunctionByName(const TString& name);
- void resetFunctionNodes();
-
- TInfoSink& getInfoSink() { return infoSink; }
-
- TVector<FunctionNode*> functions;
- FunctionNode* currentFunction;
- TInfoSink& infoSink;
- int maxDepth;
-
- DetectCallDepth(const DetectCallDepth&);
- void operator=(const DetectCallDepth&);
-};
-
-#endif // COMPILER_DETECT_RECURSION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.cpp b/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.cpp
deleted file mode 100644
index 8cfe49ba2..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// 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.
-//
-// Contains analysis utilities for dealing with HLSL's lack of support for
-// the use of intrinsic functions which (implicitly or explicitly) compute
-// gradients of functions with discontinuities.
-//
-
-#include "compiler/DetectDiscontinuity.h"
-
-#include "compiler/ParseContext.h"
-
-namespace sh
-{
-bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
-{
- mLoopDepth = 0;
- mLoopDiscontinuity = false;
- node->traverse(this);
- return mLoopDiscontinuity;
-}
-
-bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
-{
- if (visit == PreVisit)
- {
- ++mLoopDepth;
- }
- else if (visit == PostVisit)
- {
- --mLoopDepth;
- }
-
- return true;
-}
-
-bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
-{
- if (mLoopDiscontinuity)
- {
- return false;
- }
-
- if (!mLoopDepth)
- {
- return true;
- }
-
- switch (node->getFlowOp())
- {
- case EOpKill:
- break;
- case EOpBreak:
- case EOpContinue:
- case EOpReturn:
- mLoopDiscontinuity = true;
- break;
- default: UNREACHABLE();
- }
-
- return !mLoopDiscontinuity;
-}
-
-bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
-{
- return !mLoopDiscontinuity;
-}
-
-bool containsLoopDiscontinuity(TIntermNode *node)
-{
- DetectLoopDiscontinuity detectLoopDiscontinuity;
- return detectLoopDiscontinuity.traverse(node);
-}
-
-bool DetectGradientOperation::traverse(TIntermNode *node)
-{
- mGradientOperation = false;
- node->traverse(this);
- return mGradientOperation;
-}
-
-bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
-{
- if (mGradientOperation)
- {
- return false;
- }
-
- switch (node->getOp())
- {
- case EOpDFdx:
- case EOpDFdy:
- mGradientOperation = true;
- default:
- break;
- }
-
- return !mGradientOperation;
-}
-
-bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
-{
- if (mGradientOperation)
- {
- return false;
- }
-
- if (node->getOp() == EOpFunctionCall)
- {
- if (!node->isUserDefined())
- {
- TString name = TFunction::unmangleName(node->getName());
-
- if (name == "texture2D" ||
- name == "texture2DProj" ||
- name == "textureCube")
- {
- mGradientOperation = true;
- }
- }
- else
- {
- // When a user defined function is called, we have to
- // conservatively assume it to contain gradient operations
- mGradientOperation = true;
- }
- }
-
- return !mGradientOperation;
-}
-
-bool containsGradientOperation(TIntermNode *node)
-{
- DetectGradientOperation detectGradientOperation;
- return detectGradientOperation.traverse(node);
-}
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.h b/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.h
deleted file mode 100644
index e5520bd5b..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DetectDiscontinuity.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// 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.
-//
-// Contains analysis utilities for dealing with HLSL's lack of support for
-// the use of intrinsic functions which (implicitly or explicitly) compute
-// gradients of functions with discontinuities.
-//
-
-#ifndef COMPILER_DETECTDISCONTINUITY_H_
-#define COMPILER_DETECTDISCONTINUITY_H_
-
-#include "compiler/intermediate.h"
-
-namespace sh
-{
-// Checks whether a loop can run for a variable number of iterations
-class DetectLoopDiscontinuity : public TIntermTraverser
-{
- public:
- bool traverse(TIntermNode *node);
-
- protected:
- bool visitBranch(Visit visit, TIntermBranch *node);
- bool visitLoop(Visit visit, TIntermLoop *loop);
- bool visitAggregate(Visit visit, TIntermAggregate *node);
-
- int mLoopDepth;
- bool mLoopDiscontinuity;
-};
-
-bool containsLoopDiscontinuity(TIntermNode *node);
-
-// Checks for intrinsic functions which compute gradients
-class DetectGradientOperation : public TIntermTraverser
-{
- public:
- bool traverse(TIntermNode *node);
-
- protected:
- bool visitUnary(Visit visit, TIntermUnary *node);
- bool visitAggregate(Visit visit, TIntermAggregate *node);
-
- bool mGradientOperation;
-};
-
-bool containsGradientOperation(TIntermNode *node);
-
-}
-
-#endif // COMPILER_DETECTDISCONTINUITY_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.cpp b/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.cpp
deleted file mode 100644
index d1f6ab3af..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/DirectiveHandler.h"
-
-#include <sstream>
-
-#include "compiler/debug.h"
-#include "compiler/Diagnostics.h"
-
-static TBehavior getBehavior(const std::string& str)
-{
- static const std::string kRequire("require");
- static const std::string kEnable("enable");
- static const std::string kDisable("disable");
- static const std::string 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)
- : mExtensionBehavior(extBehavior),
- mDiagnostics(diagnostics)
-{
-}
-
-TDirectiveHandler::~TDirectiveHandler()
-{
-}
-
-void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
- const std::string& msg)
-{
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, msg, "", "");
-}
-
-void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& value)
-{
- static const std::string kSTDGL("STDGL");
- static const std::string kOptimize("optimize");
- static const std::string kDebug("debug");
- static const std::string kOn("on");
- static const std::string kOff("off");
-
- bool invalidValue = false;
- if (name == kSTDGL)
- {
- // The STDGL pragma is used to reserve pragmas for use by future
- // revisions of GLSL. Ignore it.
- return;
- }
- else 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
- {
- mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name);
- return;
- }
-
- if (invalidValue)
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
- "invalid pragma value", value,
- "'on' or 'off' expected");
-}
-
-void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& behavior)
-{
- static const std::string kExtAll("all");
-
- TBehavior behaviorVal = getBehavior(behavior);
- if (behaviorVal == EBhUndefined)
- {
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
- "behavior", name, "invalid");
- return;
- }
-
- if (name == kExtAll)
- {
- if (behaviorVal == EBhRequire)
- {
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
- "extension", name,
- "cannot have 'require' behavior");
- }
- else if (behaviorVal == EBhEnable)
- {
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
- "extension", name,
- "cannot have 'enable' behavior");
- }
- else
- {
- for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
- iter != mExtensionBehavior.end(); ++iter)
- iter->second = behaviorVal;
- }
- return;
- }
-
- TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
- if (iter != mExtensionBehavior.end())
- {
- iter->second = behaviorVal;
- return;
- }
-
- pp::Diagnostics::Severity severity = pp::Diagnostics::ERROR;
- switch (behaviorVal) {
- case EBhRequire:
- severity = pp::Diagnostics::ERROR;
- break;
- case EBhEnable:
- case EBhWarn:
- case EBhDisable:
- severity = pp::Diagnostics::WARNING;
- break;
- default:
- UNREACHABLE();
- break;
- }
- mDiagnostics.writeInfo(severity, loc,
- "extension", name, "is not supported");
-}
-
-void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
- int version)
-{
- static const int kVersion = 100;
-
- if (version != kVersion)
- {
- std::stringstream stream;
- stream << version;
- std::string str = stream.str();
- mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
- "version number", str, "not supported");
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.h b/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.h
deleted file mode 100644
index 95ca59d6f..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/DirectiveHandler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// 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_DIRECTIVE_HANDLER_H_
-#define COMPILER_DIRECTIVE_HANDLER_H_
-
-#include "compiler/ExtensionBehavior.h"
-#include "compiler/Pragma.h"
-#include "compiler/preprocessor/DirectiveHandlerBase.h"
-
-class TDiagnostics;
-
-class TDirectiveHandler : public pp::DirectiveHandler
-{
- public:
- TDirectiveHandler(TExtensionBehavior& extBehavior,
- TDiagnostics& diagnostics);
- virtual ~TDirectiveHandler();
-
- const TPragma& pragma() const { return mPragma; }
- const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; }
-
- virtual void handleError(const pp::SourceLocation& loc,
- const std::string& msg);
-
- virtual void handlePragma(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& value);
-
- virtual void handleExtension(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& behavior);
-
- virtual void handleVersion(const pp::SourceLocation& loc,
- int version);
-
- private:
- TPragma mPragma;
- TExtensionBehavior& mExtensionBehavior;
- TDiagnostics& mDiagnostics;
-};
-
-#endif // COMPILER_DIRECTIVE_HANDLER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp
deleted file mode 100644
index 27a13eaba..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-//
-// 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/ForLoopUnroll.h"
-
-namespace {
-
-class IntegerForLoopUnrollMarker : public TIntermTraverser {
-public:
-
- virtual bool visitLoop(Visit, TIntermLoop* node)
- {
- // This is called after ValidateLimitations pass, so all the ASSERT
- // should never fail.
- // See ValidateLimitations::validateForLoopInit().
- ASSERT(node);
- ASSERT(node->getType() == ELoopFor);
- ASSERT(node->getInit());
- TIntermAggregate* decl = node->getInit()->getAsAggregate();
- ASSERT(decl && decl->getOp() == EOpDeclaration);
- TIntermSequence& declSeq = decl->getSequence();
- ASSERT(declSeq.size() == 1);
- TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
- ASSERT(declInit && declInit->getOp() == EOpInitialize);
- ASSERT(declInit->getLeft());
- TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
- ASSERT(symbol);
- TBasicType type = symbol->getBasicType();
- ASSERT(type == EbtInt || type == EbtFloat);
- if (type == EbtInt)
- node->setUnrollFlag(true);
- return true;
- }
-
-};
-
-} // anonymous namepsace
-
-void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
-{
- ASSERT(node->getType() == ELoopFor);
- ASSERT(node->getUnrollFlag());
-
- TIntermNode* init = node->getInit();
- ASSERT(init != NULL);
- TIntermAggregate* decl = init->getAsAggregate();
- ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
- TIntermSequence& declSeq = decl->getSequence();
- ASSERT(declSeq.size() == 1);
- TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
- ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
- TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
- ASSERT(symbol != NULL);
- ASSERT(symbol->getBasicType() == EbtInt);
-
- info.id = symbol->getId();
-
- ASSERT(declInit->getRight() != NULL);
- TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
- ASSERT(initNode != NULL);
-
- info.initValue = evaluateIntConstant(initNode);
- info.currentValue = info.initValue;
-
- TIntermNode* cond = node->getCondition();
- ASSERT(cond != NULL);
- TIntermBinary* binOp = cond->getAsBinaryNode();
- ASSERT(binOp != NULL);
- ASSERT(binOp->getRight() != NULL);
- ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
-
- info.incrementValue = getLoopIncrement(node);
- info.stopValue = evaluateIntConstant(
- binOp->getRight()->getAsConstantUnion());
- info.op = binOp->getOp();
-}
-
-void ForLoopUnroll::Step()
-{
- ASSERT(mLoopIndexStack.size() > 0);
- TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
- info.currentValue += info.incrementValue;
-}
-
-bool ForLoopUnroll::SatisfiesLoopCondition()
-{
- ASSERT(mLoopIndexStack.size() > 0);
- TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
- // Relational operator is one of: > >= < <= == or !=.
- switch (info.op) {
- case EOpEqual:
- return (info.currentValue == info.stopValue);
- case EOpNotEqual:
- return (info.currentValue != info.stopValue);
- case EOpLessThan:
- return (info.currentValue < info.stopValue);
- case EOpGreaterThan:
- return (info.currentValue > info.stopValue);
- case EOpLessThanEqual:
- return (info.currentValue <= info.stopValue);
- case EOpGreaterThanEqual:
- return (info.currentValue >= info.stopValue);
- default:
- UNREACHABLE();
- }
- return false;
-}
-
-bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
-{
- for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
- i != mLoopIndexStack.end();
- ++i) {
- if (i->id == symbol->getId())
- return true;
- }
- return false;
-}
-
-int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
-{
- for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
- i != mLoopIndexStack.end();
- ++i) {
- if (i->id == symbol->getId())
- return i->currentValue;
- }
- UNREACHABLE();
- return false;
-}
-
-void ForLoopUnroll::Push(TLoopIndexInfo& info)
-{
- mLoopIndexStack.push_back(info);
-}
-
-void ForLoopUnroll::Pop()
-{
- mLoopIndexStack.pop_back();
-}
-
-// static
-void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(
- TIntermNode* root)
-{
- ASSERT(root);
-
- IntegerForLoopUnrollMarker marker;
- root->traverse(&marker);
-}
-
-int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
-{
- TIntermNode* expr = node->getExpression();
- ASSERT(expr != NULL);
- // 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 ? NULL : expr->getAsBinaryNode();
-
- TOperator op = EOpNull;
- TIntermConstantUnion* incrementNode = NULL;
- if (unOp != NULL) {
- op = unOp->getOp();
- } else if (binOp != NULL) {
- op = binOp->getOp();
- ASSERT(binOp->getRight() != NULL);
- incrementNode = binOp->getRight()->getAsConstantUnion();
- ASSERT(incrementNode != NULL);
- }
-
- int increment = 0;
- // The operator is one of: ++ -- += -=.
- switch (op) {
- case EOpPostIncrement:
- case EOpPreIncrement:
- ASSERT((unOp != NULL) && (binOp == NULL));
- increment = 1;
- break;
- case EOpPostDecrement:
- case EOpPreDecrement:
- ASSERT((unOp != NULL) && (binOp == NULL));
- increment = -1;
- break;
- case EOpAddAssign:
- ASSERT((unOp == NULL) && (binOp != NULL));
- increment = evaluateIntConstant(incrementNode);
- break;
- case EOpSubAssign:
- ASSERT((unOp == NULL) && (binOp != NULL));
- increment = - evaluateIntConstant(incrementNode);
- break;
- default:
- ASSERT(false);
- }
-
- return increment;
-}
-
-int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
-{
- ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
- return node->getIConst(0);
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h
deleted file mode 100644
index e800e25b1..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/intermediate.h"
-
-struct TLoopIndexInfo {
- int id;
- int initValue;
- int stopValue;
- int incrementValue;
- TOperator op;
- int currentValue;
-};
-
-class ForLoopUnroll {
-public:
- ForLoopUnroll() { }
-
- void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info);
-
- // Update the info.currentValue for the next loop iteration.
- void Step();
-
- // Return false if loop condition is no longer satisfied.
- bool SatisfiesLoopCondition();
-
- // Check if the symbol is the index of a loop that's unrolled.
- bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol);
-
- // Return the current value of a given loop index symbol.
- int GetLoopIndexValue(TIntermSymbol* symbol);
-
- void Push(TLoopIndexInfo& info);
- void Pop();
-
- static void MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode* root);
-
-private:
- int getLoopIncrement(TIntermLoop* node);
-
- int evaluateIntConstant(TIntermConstantUnion* node);
-
- TVector<TLoopIndexInfo> mLoopIndexStack;
-};
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp b/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp
deleted file mode 100644
index 2cdbe17aa..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp
+++ /dev/null
@@ -1,564 +0,0 @@
-//
-// 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.
-//
-
-//
-// Create strings that declare built-in definitions, add built-ins that
-// cannot be expressed in the files, and establish mappings between
-// built-in functions and operators.
-//
-
-#include "compiler/Initialize.h"
-
-#include "compiler/intermediate.h"
-
-void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
-{
- TType *float1 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 1);
- TType *float2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2);
- TType *float3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3);
- TType *float4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4);
-
- TType *int2 = new TType(EbtInt, EbpUndefined, EvqGlobal, 2);
- TType *int3 = new TType(EbtInt, EbpUndefined, EvqGlobal, 3);
- TType *int4 = new TType(EbtInt, EbpUndefined, EvqGlobal, 4);
-
- //
- // Angle and Trigonometric Functions.
- //
- symbolTable.insertBuiltIn(float1, "radians", float1);
- symbolTable.insertBuiltIn(float2, "radians", float2);
- symbolTable.insertBuiltIn(float3, "radians", float3);
- symbolTable.insertBuiltIn(float4, "radians", float4);
-
- symbolTable.insertBuiltIn(float1, "degrees", float1);
- symbolTable.insertBuiltIn(float2, "degrees", float2);
- symbolTable.insertBuiltIn(float3, "degrees", float3);
- symbolTable.insertBuiltIn(float4, "degrees", float4);
-
- symbolTable.insertBuiltIn(float1, "sin", float1);
- symbolTable.insertBuiltIn(float2, "sin", float2);
- symbolTable.insertBuiltIn(float3, "sin", float3);
- symbolTable.insertBuiltIn(float4, "sin", float4);
-
- symbolTable.insertBuiltIn(float1, "cos", float1);
- symbolTable.insertBuiltIn(float2, "cos", float2);
- symbolTable.insertBuiltIn(float3, "cos", float3);
- symbolTable.insertBuiltIn(float4, "cos", float4);
-
- symbolTable.insertBuiltIn(float1, "tan", float1);
- symbolTable.insertBuiltIn(float2, "tan", float2);
- symbolTable.insertBuiltIn(float3, "tan", float3);
- symbolTable.insertBuiltIn(float4, "tan", float4);
-
- symbolTable.insertBuiltIn(float1, "asin", float1);
- symbolTable.insertBuiltIn(float2, "asin", float2);
- symbolTable.insertBuiltIn(float3, "asin", float3);
- symbolTable.insertBuiltIn(float4, "asin", float4);
-
- symbolTable.insertBuiltIn(float1, "acos", float1);
- symbolTable.insertBuiltIn(float2, "acos", float2);
- symbolTable.insertBuiltIn(float3, "acos", float3);
- symbolTable.insertBuiltIn(float4, "acos", float4);
-
- symbolTable.insertBuiltIn(float1, "atan", float1, float1);
- symbolTable.insertBuiltIn(float2, "atan", float2, float2);
- symbolTable.insertBuiltIn(float3, "atan", float3, float3);
- symbolTable.insertBuiltIn(float4, "atan", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "atan", float1);
- symbolTable.insertBuiltIn(float2, "atan", float2);
- symbolTable.insertBuiltIn(float3, "atan", float3);
- symbolTable.insertBuiltIn(float4, "atan", float4);
-
- //
- // Exponential Functions.
- //
- symbolTable.insertBuiltIn(float1, "pow", float1, float1);
- symbolTable.insertBuiltIn(float2, "pow", float2, float2);
- symbolTable.insertBuiltIn(float3, "pow", float3, float3);
- symbolTable.insertBuiltIn(float4, "pow", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "exp", float1);
- symbolTable.insertBuiltIn(float2, "exp", float2);
- symbolTable.insertBuiltIn(float3, "exp", float3);
- symbolTable.insertBuiltIn(float4, "exp", float4);
-
- symbolTable.insertBuiltIn(float1, "log", float1);
- symbolTable.insertBuiltIn(float2, "log", float2);
- symbolTable.insertBuiltIn(float3, "log", float3);
- symbolTable.insertBuiltIn(float4, "log", float4);
-
- symbolTable.insertBuiltIn(float1, "exp2", float1);
- symbolTable.insertBuiltIn(float2, "exp2", float2);
- symbolTable.insertBuiltIn(float3, "exp2", float3);
- symbolTable.insertBuiltIn(float4, "exp2", float4);
-
- symbolTable.insertBuiltIn(float1, "log2", float1);
- symbolTable.insertBuiltIn(float2, "log2", float2);
- symbolTable.insertBuiltIn(float3, "log2", float3);
- symbolTable.insertBuiltIn(float4, "log2", float4);
-
- symbolTable.insertBuiltIn(float1, "sqrt", float1);
- symbolTable.insertBuiltIn(float2, "sqrt", float2);
- symbolTable.insertBuiltIn(float3, "sqrt", float3);
- symbolTable.insertBuiltIn(float4, "sqrt", float4);
-
- symbolTable.insertBuiltIn(float1, "inversesqrt", float1);
- symbolTable.insertBuiltIn(float2, "inversesqrt", float2);
- symbolTable.insertBuiltIn(float3, "inversesqrt", float3);
- symbolTable.insertBuiltIn(float4, "inversesqrt", float4);
-
- //
- // Common Functions.
- //
- symbolTable.insertBuiltIn(float1, "abs", float1);
- symbolTable.insertBuiltIn(float2, "abs", float2);
- symbolTable.insertBuiltIn(float3, "abs", float3);
- symbolTable.insertBuiltIn(float4, "abs", float4);
-
- symbolTable.insertBuiltIn(float1, "sign", float1);
- symbolTable.insertBuiltIn(float2, "sign", float2);
- symbolTable.insertBuiltIn(float3, "sign", float3);
- symbolTable.insertBuiltIn(float4, "sign", float4);
-
- symbolTable.insertBuiltIn(float1, "floor", float1);
- symbolTable.insertBuiltIn(float2, "floor", float2);
- symbolTable.insertBuiltIn(float3, "floor", float3);
- symbolTable.insertBuiltIn(float4, "floor", float4);
-
- symbolTable.insertBuiltIn(float1, "ceil", float1);
- symbolTable.insertBuiltIn(float2, "ceil", float2);
- symbolTable.insertBuiltIn(float3, "ceil", float3);
- symbolTable.insertBuiltIn(float4, "ceil", float4);
-
- symbolTable.insertBuiltIn(float1, "fract", float1);
- symbolTable.insertBuiltIn(float2, "fract", float2);
- symbolTable.insertBuiltIn(float3, "fract", float3);
- symbolTable.insertBuiltIn(float4, "fract", float4);
-
- symbolTable.insertBuiltIn(float1, "mod", float1, float1);
- symbolTable.insertBuiltIn(float2, "mod", float2, float1);
- symbolTable.insertBuiltIn(float3, "mod", float3, float1);
- symbolTable.insertBuiltIn(float4, "mod", float4, float1);
- symbolTable.insertBuiltIn(float2, "mod", float2, float2);
- symbolTable.insertBuiltIn(float3, "mod", float3, float3);
- symbolTable.insertBuiltIn(float4, "mod", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "min", float1, float1);
- symbolTable.insertBuiltIn(float2, "min", float2, float1);
- symbolTable.insertBuiltIn(float3, "min", float3, float1);
- symbolTable.insertBuiltIn(float4, "min", float4, float1);
- symbolTable.insertBuiltIn(float2, "min", float2, float2);
- symbolTable.insertBuiltIn(float3, "min", float3, float3);
- symbolTable.insertBuiltIn(float4, "min", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "max", float1, float1);
- symbolTable.insertBuiltIn(float2, "max", float2, float1);
- symbolTable.insertBuiltIn(float3, "max", float3, float1);
- symbolTable.insertBuiltIn(float4, "max", float4, float1);
- symbolTable.insertBuiltIn(float2, "max", float2, float2);
- symbolTable.insertBuiltIn(float3, "max", float3, float3);
- symbolTable.insertBuiltIn(float4, "max", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "clamp", float1, float1, float1);
- symbolTable.insertBuiltIn(float2, "clamp", float2, float1, float1);
- symbolTable.insertBuiltIn(float3, "clamp", float3, float1, float1);
- symbolTable.insertBuiltIn(float4, "clamp", float4, float1, float1);
- symbolTable.insertBuiltIn(float2, "clamp", float2, float2, float2);
- symbolTable.insertBuiltIn(float3, "clamp", float3, float3, float3);
- symbolTable.insertBuiltIn(float4, "clamp", float4, float4, float4);
-
- symbolTable.insertBuiltIn(float1, "mix", float1, float1, float1);
- symbolTable.insertBuiltIn(float2, "mix", float2, float2, float1);
- symbolTable.insertBuiltIn(float3, "mix", float3, float3, float1);
- symbolTable.insertBuiltIn(float4, "mix", float4, float4, float1);
- symbolTable.insertBuiltIn(float2, "mix", float2, float2, float2);
- symbolTable.insertBuiltIn(float3, "mix", float3, float3, float3);
- symbolTable.insertBuiltIn(float4, "mix", float4, float4, float4);
-
- symbolTable.insertBuiltIn(float1, "step", float1, float1);
- symbolTable.insertBuiltIn(float2, "step", float2, float2);
- symbolTable.insertBuiltIn(float3, "step", float3, float3);
- symbolTable.insertBuiltIn(float4, "step", float4, float4);
- symbolTable.insertBuiltIn(float2, "step", float1, float2);
- symbolTable.insertBuiltIn(float3, "step", float1, float3);
- symbolTable.insertBuiltIn(float4, "step", float1, float4);
-
- symbolTable.insertBuiltIn(float1, "smoothstep", float1, float1, float1);
- symbolTable.insertBuiltIn(float2, "smoothstep", float2, float2, float2);
- symbolTable.insertBuiltIn(float3, "smoothstep", float3, float3, float3);
- symbolTable.insertBuiltIn(float4, "smoothstep", float4, float4, float4);
- symbolTable.insertBuiltIn(float2, "smoothstep", float1, float1, float2);
- symbolTable.insertBuiltIn(float3, "smoothstep", float1, float1, float3);
- symbolTable.insertBuiltIn(float4, "smoothstep", float1, float1, float4);
-
- //
- // Geometric Functions.
- //
- symbolTable.insertBuiltIn(float1, "length", float1);
- symbolTable.insertBuiltIn(float1, "length", float2);
- symbolTable.insertBuiltIn(float1, "length", float3);
- symbolTable.insertBuiltIn(float1, "length", float4);
-
- symbolTable.insertBuiltIn(float1, "distance", float1, float1);
- symbolTable.insertBuiltIn(float1, "distance", float2, float2);
- symbolTable.insertBuiltIn(float1, "distance", float3, float3);
- symbolTable.insertBuiltIn(float1, "distance", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "dot", float1, float1);
- symbolTable.insertBuiltIn(float1, "dot", float2, float2);
- symbolTable.insertBuiltIn(float1, "dot", float3, float3);
- symbolTable.insertBuiltIn(float1, "dot", float4, float4);
-
- symbolTable.insertBuiltIn(float3, "cross", float3, float3);
- symbolTable.insertBuiltIn(float1, "normalize", float1);
- symbolTable.insertBuiltIn(float2, "normalize", float2);
- symbolTable.insertBuiltIn(float3, "normalize", float3);
- symbolTable.insertBuiltIn(float4, "normalize", float4);
-
- symbolTable.insertBuiltIn(float1, "faceforward", float1, float1, float1);
- symbolTable.insertBuiltIn(float2, "faceforward", float2, float2, float2);
- symbolTable.insertBuiltIn(float3, "faceforward", float3, float3, float3);
- symbolTable.insertBuiltIn(float4, "faceforward", float4, float4, float4);
-
- symbolTable.insertBuiltIn(float1, "reflect", float1, float1);
- symbolTable.insertBuiltIn(float2, "reflect", float2, float2);
- symbolTable.insertBuiltIn(float3, "reflect", float3, float3);
- symbolTable.insertBuiltIn(float4, "reflect", float4, float4);
-
- symbolTable.insertBuiltIn(float1, "refract", float1, float1, float1);
- symbolTable.insertBuiltIn(float2, "refract", float2, float2, float1);
- symbolTable.insertBuiltIn(float3, "refract", float3, float3, float1);
- symbolTable.insertBuiltIn(float4, "refract", float4, float4, float1);
-
- TType *mat2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2, true);
- TType *mat3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3, true);
- TType *mat4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4, true);
-
- //
- // Matrix Functions.
- //
- symbolTable.insertBuiltIn(mat2, "matrixCompMult", mat2, mat2);
- symbolTable.insertBuiltIn(mat3, "matrixCompMult", mat3, mat3);
- symbolTable.insertBuiltIn(mat4, "matrixCompMult", mat4, mat4);
-
- TType *bool1 = new TType(EbtBool, EbpUndefined, EvqGlobal, 1);
- TType *bool2 = new TType(EbtBool, EbpUndefined, EvqGlobal, 2);
- TType *bool3 = new TType(EbtBool, EbpUndefined, EvqGlobal, 3);
- TType *bool4 = new TType(EbtBool, EbpUndefined, EvqGlobal, 4);
-
- //
- // Vector relational functions.
- //
- symbolTable.insertBuiltIn(bool2, "lessThan", float2, float2);
- symbolTable.insertBuiltIn(bool3, "lessThan", float3, float3);
- symbolTable.insertBuiltIn(bool4, "lessThan", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "lessThan", int2, int2);
- symbolTable.insertBuiltIn(bool3, "lessThan", int3, int3);
- symbolTable.insertBuiltIn(bool4, "lessThan", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "lessThanEqual", float2, float2);
- symbolTable.insertBuiltIn(bool3, "lessThanEqual", float3, float3);
- symbolTable.insertBuiltIn(bool4, "lessThanEqual", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "lessThanEqual", int2, int2);
- symbolTable.insertBuiltIn(bool3, "lessThanEqual", int3, int3);
- symbolTable.insertBuiltIn(bool4, "lessThanEqual", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "greaterThan", float2, float2);
- symbolTable.insertBuiltIn(bool3, "greaterThan", float3, float3);
- symbolTable.insertBuiltIn(bool4, "greaterThan", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "greaterThan", int2, int2);
- symbolTable.insertBuiltIn(bool3, "greaterThan", int3, int3);
- symbolTable.insertBuiltIn(bool4, "greaterThan", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "greaterThanEqual", float2, float2);
- symbolTable.insertBuiltIn(bool3, "greaterThanEqual", float3, float3);
- symbolTable.insertBuiltIn(bool4, "greaterThanEqual", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "greaterThanEqual", int2, int2);
- symbolTable.insertBuiltIn(bool3, "greaterThanEqual", int3, int3);
- symbolTable.insertBuiltIn(bool4, "greaterThanEqual", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "equal", float2, float2);
- symbolTable.insertBuiltIn(bool3, "equal", float3, float3);
- symbolTable.insertBuiltIn(bool4, "equal", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "equal", int2, int2);
- symbolTable.insertBuiltIn(bool3, "equal", int3, int3);
- symbolTable.insertBuiltIn(bool4, "equal", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "equal", bool2, bool2);
- symbolTable.insertBuiltIn(bool3, "equal", bool3, bool3);
- symbolTable.insertBuiltIn(bool4, "equal", bool4, bool4);
-
- symbolTable.insertBuiltIn(bool2, "notEqual", float2, float2);
- symbolTable.insertBuiltIn(bool3, "notEqual", float3, float3);
- symbolTable.insertBuiltIn(bool4, "notEqual", float4, float4);
-
- symbolTable.insertBuiltIn(bool2, "notEqual", int2, int2);
- symbolTable.insertBuiltIn(bool3, "notEqual", int3, int3);
- symbolTable.insertBuiltIn(bool4, "notEqual", int4, int4);
-
- symbolTable.insertBuiltIn(bool2, "notEqual", bool2, bool2);
- symbolTable.insertBuiltIn(bool3, "notEqual", bool3, bool3);
- symbolTable.insertBuiltIn(bool4, "notEqual", bool4, bool4);
-
- symbolTable.insertBuiltIn(bool1, "any", bool2);
- symbolTable.insertBuiltIn(bool1, "any", bool3);
- symbolTable.insertBuiltIn(bool1, "any", bool4);
-
- symbolTable.insertBuiltIn(bool1, "all", bool2);
- symbolTable.insertBuiltIn(bool1, "all", bool3);
- symbolTable.insertBuiltIn(bool1, "all", bool4);
-
- symbolTable.insertBuiltIn(bool2, "not", bool2);
- symbolTable.insertBuiltIn(bool3, "not", bool3);
- symbolTable.insertBuiltIn(bool4, "not", bool4);
-
- TType *sampler2D = new TType(EbtSampler2D, EbpUndefined, EvqGlobal, 1);
- TType *samplerCube = new TType(EbtSamplerCube, EbpUndefined, EvqGlobal, 1);
-
- //
- // Texture Functions for GLSL ES 1.0
- //
- symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2);
- symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3);
- symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4);
- symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3);
-
- if (resources.OES_EGL_image_external)
- {
- TType *samplerExternalOES = new TType(EbtSamplerExternalOES, EbpUndefined, EvqGlobal, 1);
-
- symbolTable.insertBuiltIn(float4, "texture2D", samplerExternalOES, float2);
- symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float3);
- symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float4);
- }
-
- if (resources.ARB_texture_rectangle)
- {
- TType *sampler2DRect = new TType(EbtSampler2DRect, EbpUndefined, EvqGlobal, 1);
-
- symbolTable.insertBuiltIn(float4, "texture2DRect", sampler2DRect, float2);
- symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float3);
- symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float4);
- }
-
- if (type == SH_FRAGMENT_SHADER)
- {
- symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2, float1);
- symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3, float1);
- symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4, float1);
- symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3, float1);
-
- if (resources.OES_standard_derivatives)
- {
- symbolTable.insertBuiltIn(float1, "dFdx", float1);
- symbolTable.insertBuiltIn(float2, "dFdx", float2);
- symbolTable.insertBuiltIn(float3, "dFdx", float3);
- symbolTable.insertBuiltIn(float4, "dFdx", float4);
-
- symbolTable.insertBuiltIn(float1, "dFdy", float1);
- symbolTable.insertBuiltIn(float2, "dFdy", float2);
- symbolTable.insertBuiltIn(float3, "dFdy", float3);
- symbolTable.insertBuiltIn(float4, "dFdy", float4);
-
- symbolTable.insertBuiltIn(float1, "fwidth", float1);
- symbolTable.insertBuiltIn(float2, "fwidth", float2);
- symbolTable.insertBuiltIn(float3, "fwidth", float3);
- symbolTable.insertBuiltIn(float4, "fwidth", float4);
- }
- }
-
- if(type == SH_VERTEX_SHADER)
- {
- symbolTable.insertBuiltIn(float4, "texture2DLod", sampler2D, float2, float1);
- symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float3, float1);
- symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float4, float1);
- symbolTable.insertBuiltIn(float4, "textureCubeLod", samplerCube, float3, float1);
- }
-
- //
- // Depth range in window coordinates
- //
- TFieldList *fields = NewPoolTFieldList();
- TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"));
- TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"));
- TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"));
- fields->push_back(near);
- fields->push_back(far);
- fields->push_back(diff);
- TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields);
- TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true);
- symbolTable.insert(*depthRangeParameters);
- TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct));
- depthRange->setQualifier(EvqUniform);
- symbolTable.insert(*depthRange);
-
- //
- // Implementation dependent built-in constants.
- //
- symbolTable.insertConstInt("gl_MaxVertexAttribs", resources.MaxVertexAttribs);
- symbolTable.insertConstInt("gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors);
- symbolTable.insertConstInt("gl_MaxVaryingVectors", resources.MaxVaryingVectors);
- symbolTable.insertConstInt("gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits);
- symbolTable.insertConstInt("gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits);
- symbolTable.insertConstInt("gl_MaxTextureImageUnits", resources.MaxTextureImageUnits);
- symbolTable.insertConstInt("gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors);
-
- if (spec != SH_CSS_SHADERS_SPEC)
- {
- symbolTable.insertConstInt("gl_MaxDrawBuffers", resources.MaxDrawBuffers);
- }
-}
-
-void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
- const ShBuiltInResources &resources,
- TSymbolTable &symbolTable)
-{
- //
- // First, insert some special built-in variables that are not in
- // the built-in header files.
- //
- switch(type) {
- case SH_FRAGMENT_SHADER:
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
- symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
-
- //
- // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
- // Instead, css_MixColor and css_ColorMatrix are available.
- //
- if (spec != SH_CSS_SHADERS_SPEC) {
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
- if (resources.EXT_frag_depth) {
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1)));
- symbolTable.relateToExtension("gl_FragDepthEXT", "GL_EXT_frag_depth");
- }
- } else {
- symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
- symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, true)));
- }
-
- break;
-
- case SH_VERTEX_SHADER:
- symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
- symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
- break;
-
- default: assert(false && "Language not supported");
- }
-
- //
- // Next, identify which built-ins from the already loaded headers have
- // a mapping to an operator. Those that are not identified as such are
- // expected to be resolved through a library of functions, versus as
- // operations.
- //
- symbolTable.relateToOperator("matrixCompMult", EOpMul);
-
- symbolTable.relateToOperator("equal", EOpVectorEqual);
- symbolTable.relateToOperator("notEqual", EOpVectorNotEqual);
- symbolTable.relateToOperator("lessThan", EOpLessThan);
- symbolTable.relateToOperator("greaterThan", EOpGreaterThan);
- symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual);
- symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual);
-
- symbolTable.relateToOperator("radians", EOpRadians);
- symbolTable.relateToOperator("degrees", EOpDegrees);
- symbolTable.relateToOperator("sin", EOpSin);
- symbolTable.relateToOperator("cos", EOpCos);
- symbolTable.relateToOperator("tan", EOpTan);
- symbolTable.relateToOperator("asin", EOpAsin);
- symbolTable.relateToOperator("acos", EOpAcos);
- symbolTable.relateToOperator("atan", EOpAtan);
-
- symbolTable.relateToOperator("pow", EOpPow);
- symbolTable.relateToOperator("exp2", EOpExp2);
- symbolTable.relateToOperator("log", EOpLog);
- symbolTable.relateToOperator("exp", EOpExp);
- symbolTable.relateToOperator("log2", EOpLog2);
- symbolTable.relateToOperator("sqrt", EOpSqrt);
- symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt);
-
- symbolTable.relateToOperator("abs", EOpAbs);
- symbolTable.relateToOperator("sign", EOpSign);
- symbolTable.relateToOperator("floor", EOpFloor);
- symbolTable.relateToOperator("ceil", EOpCeil);
- symbolTable.relateToOperator("fract", EOpFract);
- symbolTable.relateToOperator("mod", EOpMod);
- symbolTable.relateToOperator("min", EOpMin);
- symbolTable.relateToOperator("max", EOpMax);
- symbolTable.relateToOperator("clamp", EOpClamp);
- symbolTable.relateToOperator("mix", EOpMix);
- symbolTable.relateToOperator("step", EOpStep);
- symbolTable.relateToOperator("smoothstep", EOpSmoothStep);
-
- symbolTable.relateToOperator("length", EOpLength);
- symbolTable.relateToOperator("distance", EOpDistance);
- symbolTable.relateToOperator("dot", EOpDot);
- symbolTable.relateToOperator("cross", EOpCross);
- symbolTable.relateToOperator("normalize", EOpNormalize);
- symbolTable.relateToOperator("faceforward", EOpFaceForward);
- symbolTable.relateToOperator("reflect", EOpReflect);
- symbolTable.relateToOperator("refract", EOpRefract);
-
- symbolTable.relateToOperator("any", EOpAny);
- symbolTable.relateToOperator("all", EOpAll);
- symbolTable.relateToOperator("not", EOpVectorLogicalNot);
-
- // Map language-specific operators.
- switch(type) {
- case SH_VERTEX_SHADER:
- break;
- case SH_FRAGMENT_SHADER:
- if (resources.OES_standard_derivatives) {
- symbolTable.relateToOperator("dFdx", EOpDFdx);
- symbolTable.relateToOperator("dFdy", EOpDFdy);
- symbolTable.relateToOperator("fwidth", EOpFwidth);
-
- symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives");
- symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives");
- symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives");
- }
- break;
- default: break;
- }
-
- // Finally add resource-specific variables.
- switch(type) {
- case SH_FRAGMENT_SHADER:
- if (spec != SH_CSS_SHADERS_SPEC) {
- // Set up gl_FragData. The array size.
- TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true);
- fragData.setArraySize(resources.MaxDrawBuffers);
- symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
- }
- break;
- default: break;
- }
-}
-
-void InitExtensionBehavior(const ShBuiltInResources& resources,
- TExtensionBehavior& extBehavior)
-{
- if (resources.OES_standard_derivatives)
- extBehavior["GL_OES_standard_derivatives"] = EBhUndefined;
- if (resources.OES_EGL_image_external)
- extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
- if (resources.ARB_texture_rectangle)
- extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
- if (resources.EXT_draw_buffers)
- extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
- if (resources.EXT_frag_depth)
- extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Initialize.h b/Source/ThirdParty/ANGLE/src/compiler/Initialize.h
deleted file mode 100644
index 4aa13466a..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Initialize.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// 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 _INITIALIZE_INCLUDED_
-#define _INITIALIZE_INCLUDED_
-
-#include "compiler/Common.h"
-#include "compiler/ShHandle.h"
-#include "compiler/SymbolTable.h"
-
-void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table);
-
-void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
- const ShBuiltInResources& resources,
- TSymbolTable& symbolTable);
-
-void InitExtensionBehavior(const ShBuiltInResources& resources,
- TExtensionBehavior& extensionBehavior);
-
-#endif // _INITIALIZE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.cpp b/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.cpp
deleted file mode 100644
index e0193e39d..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// 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/InitializeGLPosition.h"
-#include "compiler/debug.h"
-
-bool InitializeGLPosition::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- bool visitChildren = !mCodeInserted;
- switch (node->getOp())
- {
- case EOpSequence: break;
- case EOpFunction:
- {
- // Function definition.
- ASSERT(visit == PreVisit);
- if (node->getName() == "main(")
- {
- TIntermSequence &sequence = node->getSequence();
- ASSERT((sequence.size() == 1) || (sequence.size() == 2));
- TIntermAggregate *body = NULL;
- if (sequence.size() == 1)
- {
- body = new TIntermAggregate(EOpSequence);
- sequence.push_back(body);
- }
- else
- {
- body = sequence[1]->getAsAggregate();
- }
- ASSERT(body);
- insertCode(body->getSequence());
- mCodeInserted = true;
- }
- break;
- }
- default: visitChildren = false; break;
- }
- return visitChildren;
-}
-
-void InitializeGLPosition::insertCode(TIntermSequence& sequence)
-{
- TIntermBinary *binary = new TIntermBinary(EOpAssign);
- sequence.insert(sequence.begin(), binary);
-
- TIntermSymbol *left = new TIntermSymbol(
- 0, "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
- binary->setLeft(left);
-
- ConstantUnion *u = new ConstantUnion[4];
- for (int ii = 0; ii < 3; ++ii)
- u[ii].setFConst(0.0f);
- u[3].setFConst(1.0f);
- TIntermConstantUnion *right = new TIntermConstantUnion(
- u, TType(EbtFloat, EbpUndefined, EvqConst, 4));
- binary->setRight(right);
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.h b/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.h
deleted file mode 100644
index 1b11075a1..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeGLPosition.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// 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_INITIALIZE_GL_POSITION_H_
-#define COMPILER_INITIALIZE_GL_POSITION_H_
-
-#include "compiler/intermediate.h"
-
-class InitializeGLPosition : public TIntermTraverser
-{
-public:
- InitializeGLPosition() : mCodeInserted(false) { }
-
-protected:
- virtual bool visitBinary(Visit visit, TIntermBinary* node) { return false; }
- virtual bool visitUnary(Visit visit, TIntermUnary* node) { return false; }
- virtual bool visitSelection(Visit visit, TIntermSelection* node) { return false; }
- virtual bool visitLoop(Visit visit, TIntermLoop* node) { return false; }
- virtual bool visitBranch(Visit visit, TIntermBranch* node) { return false; }
-
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
-
-private:
- // Insert AST node in the beginning of main() for "gl_Position = vec4(0.0, 0.0, 0.0, 1.0);".
- void insertCode(TIntermSequence& sequence);
-
- bool mCodeInserted;
-};
-
-#endif // COMPILER_INITIALIZE_GL_POSITION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.cpp b/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.cpp
deleted file mode 100644
index dfab02733..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/InitializeParseContext.h"
-
-#include "compiler/osinclude.h"
-
-OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
-
-bool InitializeParseContextIndex()
-{
- assert(GlobalParseContextIndex == OS_INVALID_TLS_INDEX);
-
- GlobalParseContextIndex = OS_AllocTLSIndex();
- return GlobalParseContextIndex != OS_INVALID_TLS_INDEX;
-}
-
-void FreeParseContextIndex()
-{
- assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
-
- OS_FreeTLSIndex(GlobalParseContextIndex);
- GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
-}
-
-void SetGlobalParseContext(TParseContext* context)
-{
- assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
- OS_SetTLSValue(GlobalParseContextIndex, context);
-}
-
-TParseContext* GetGlobalParseContext()
-{
- assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
- return static_cast<TParseContext*>(OS_GetTLSValue(GlobalParseContextIndex));
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp b/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp
deleted file mode 100644
index 9a691da71..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-//
-// 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/intermediate.h"
-
-//
-// Traverse the intermediate representation tree, and
-// call a node type specific function for each node.
-// Done recursively through the member function Traverse().
-// Node types can be skipped if their function to call is 0,
-// but their subtree will still be traversed.
-// Nodes with children can have their whole subtree skipped
-// if preVisit is turned on and the type specific function
-// returns false.
-//
-// preVisit, postVisit, and rightToLeft control what order
-// nodes are visited in.
-//
-
-//
-// Traversal functions for terminals are straighforward....
-//
-void TIntermSymbol::traverse(TIntermTraverser *it)
-{
- it->visitSymbol(this);
-}
-
-void TIntermConstantUnion::traverse(TIntermTraverser *it)
-{
- it->visitConstantUnion(this);
-}
-
-//
-// Traverse a binary node.
-//
-void TIntermBinary::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- //
- // visit the node before children if pre-visiting.
- //
- if (it->preVisit)
- visit = it->visitBinary(PreVisit, this);
-
- //
- // Visit the children, in the right order.
- //
- if (visit)
- {
- it->incrementDepth(this);
-
- if (it->rightToLeft)
- {
- if (right)
- right->traverse(it);
-
- if (it->inVisit)
- visit = it->visitBinary(InVisit, this);
-
- if (visit && left)
- left->traverse(it);
- }
- else
- {
- if (left)
- left->traverse(it);
-
- if (it->inVisit)
- visit = it->visitBinary(InVisit, this);
-
- if (visit && right)
- right->traverse(it);
- }
-
- it->decrementDepth();
- }
-
- //
- // Visit the node after the children, if requested and the traversal
- // hasn't been cancelled yet.
- //
- if (visit && it->postVisit)
- it->visitBinary(PostVisit, this);
-}
-
-//
-// Traverse a unary node. Same comments in binary node apply here.
-//
-void TIntermUnary::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- if (it->preVisit)
- visit = it->visitUnary(PreVisit, this);
-
- if (visit) {
- it->incrementDepth(this);
- operand->traverse(it);
- it->decrementDepth();
- }
-
- if (visit && it->postVisit)
- it->visitUnary(PostVisit, this);
-}
-
-//
-// Traverse an aggregate node. Same comments in binary node apply here.
-//
-void TIntermAggregate::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- if (it->preVisit)
- visit = it->visitAggregate(PreVisit, this);
-
- if (visit)
- {
- it->incrementDepth(this);
-
- if (it->rightToLeft)
- {
- for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++)
- {
- (*sit)->traverse(it);
-
- if (visit && it->inVisit)
- {
- if (*sit != sequence.front())
- visit = it->visitAggregate(InVisit, this);
- }
- }
- }
- else
- {
- for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
- {
- (*sit)->traverse(it);
-
- if (visit && it->inVisit)
- {
- if (*sit != sequence.back())
- visit = it->visitAggregate(InVisit, this);
- }
- }
- }
-
- it->decrementDepth();
- }
-
- if (visit && it->postVisit)
- it->visitAggregate(PostVisit, this);
-}
-
-//
-// Traverse a selection node. Same comments in binary node apply here.
-//
-void TIntermSelection::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- if (it->preVisit)
- visit = it->visitSelection(PreVisit, this);
-
- if (visit) {
- it->incrementDepth(this);
- if (it->rightToLeft) {
- if (falseBlock)
- falseBlock->traverse(it);
- if (trueBlock)
- trueBlock->traverse(it);
- condition->traverse(it);
- } else {
- condition->traverse(it);
- if (trueBlock)
- trueBlock->traverse(it);
- if (falseBlock)
- falseBlock->traverse(it);
- }
- it->decrementDepth();
- }
-
- if (visit && it->postVisit)
- it->visitSelection(PostVisit, this);
-}
-
-//
-// Traverse a loop node. Same comments in binary node apply here.
-//
-void TIntermLoop::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- if (it->preVisit)
- visit = it->visitLoop(PreVisit, this);
-
- if (visit)
- {
- it->incrementDepth(this);
-
- if (it->rightToLeft)
- {
- if (expr)
- expr->traverse(it);
-
- if (body)
- body->traverse(it);
-
- if (cond)
- cond->traverse(it);
-
- if (init)
- init->traverse(it);
- }
- else
- {
- if (init)
- init->traverse(it);
-
- if (cond)
- cond->traverse(it);
-
- if (body)
- body->traverse(it);
-
- if (expr)
- expr->traverse(it);
- }
-
- it->decrementDepth();
- }
-
- if (visit && it->postVisit)
- it->visitLoop(PostVisit, this);
-}
-
-//
-// Traverse a branch node. Same comments in binary node apply here.
-//
-void TIntermBranch::traverse(TIntermTraverser *it)
-{
- bool visit = true;
-
- if (it->preVisit)
- visit = it->visitBranch(PreVisit, this);
-
- if (visit && expression) {
- it->incrementDepth(this);
- expression->traverse(it);
- it->decrementDepth();
- }
-
- if (visit && it->postVisit)
- it->visitBranch(PostVisit, this);
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp b/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp
deleted file mode 100644
index 47e4e3951..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp
+++ /dev/null
@@ -1,1500 +0,0 @@
-//
-// 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.
-//
-
-//
-// Build the intermediate representation.
-//
-
-#include <float.h>
-#include <limits.h>
-#include <algorithm>
-
-#include "compiler/HashNames.h"
-#include "compiler/localintermediate.h"
-#include "compiler/QualifierAlive.h"
-#include "compiler/RemoveTree.h"
-
-bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
-
-static TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
-{
- return left > right ? left : right;
-}
-
-const char* getOperatorString(TOperator op)
-{
- switch (op) {
- case EOpInitialize: return "=";
- case EOpAssign: return "=";
- case EOpAddAssign: return "+=";
- case EOpSubAssign: return "-=";
- case EOpDivAssign: return "/=";
-
- // Fall-through.
- case EOpMulAssign:
- case EOpVectorTimesMatrixAssign:
- case EOpVectorTimesScalarAssign:
- case EOpMatrixTimesScalarAssign:
- case EOpMatrixTimesMatrixAssign: return "*=";
-
- // Fall-through.
- case EOpIndexDirect:
- case EOpIndexIndirect: return "[]";
-
- case EOpIndexDirectStruct: return ".";
- case EOpVectorSwizzle: return ".";
- case EOpAdd: return "+";
- case EOpSub: return "-";
- case EOpMul: return "*";
- case EOpDiv: return "/";
- case EOpMod: UNIMPLEMENTED(); break;
- case EOpEqual: return "==";
- case EOpNotEqual: return "!=";
- case EOpLessThan: return "<";
- case EOpGreaterThan: return ">";
- case EOpLessThanEqual: return "<=";
- case EOpGreaterThanEqual: return ">=";
-
- // Fall-through.
- case EOpVectorTimesScalar:
- case EOpVectorTimesMatrix:
- case EOpMatrixTimesVector:
- case EOpMatrixTimesScalar:
- case EOpMatrixTimesMatrix: return "*";
-
- case EOpLogicalOr: return "||";
- case EOpLogicalXor: return "^^";
- case EOpLogicalAnd: return "&&";
- case EOpNegative: return "-";
- case EOpVectorLogicalNot: return "not";
- case EOpLogicalNot: return "!";
- case EOpPostIncrement: return "++";
- case EOpPostDecrement: return "--";
- case EOpPreIncrement: return "++";
- case EOpPreDecrement: return "--";
-
- // Fall-through.
- case EOpConvIntToBool:
- case EOpConvFloatToBool: return "bool";
-
- // Fall-through.
- case EOpConvBoolToFloat:
- case EOpConvIntToFloat: return "float";
-
- // Fall-through.
- case EOpConvFloatToInt:
- case EOpConvBoolToInt: return "int";
-
- 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 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 EOpCeil: return "ceil";
- case EOpFract: return "fract";
- case EOpLength: return "length";
- case EOpNormalize: return "normalize";
- case EOpDFdx: return "dFdx";
- case EOpDFdy: return "dFdy";
- case EOpFwidth: return "fwidth";
- case EOpAny: return "any";
- case EOpAll: return "all";
-
- default: break;
- }
- return "";
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// First set of functions are to help build the intermediate representation.
-// These functions are not member functions of the nodes.
-// They are called from parser productions.
-//
-/////////////////////////////////////////////////////////////////////////////
-
-//
-// Add a terminal node for an identifier in an expression.
-//
-// Returns the added node.
-//
-TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
-{
- TIntermSymbol* node = new TIntermSymbol(id, name, type);
- node->setLine(line);
-
- return node;
-}
-
-//
-// Connect two nodes with a new parent that does a binary operation on the nodes.
-//
-// Returns the added node.
-//
-TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable)
-{
- switch (op) {
- case EOpEqual:
- case EOpNotEqual:
- if (left->isArray())
- return 0;
- break;
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
- return 0;
- }
- break;
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpLogicalAnd:
- if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
- return 0;
- }
- break;
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpMul:
- if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
- return 0;
- default: break;
- }
-
- //
- // First try converting the children to compatible types.
- //
- if (left->getType().getStruct() && right->getType().getStruct()) {
- if (left->getType() != right->getType())
- return 0;
- } else {
- TIntermTyped* child = addConversion(op, left->getType(), right);
- if (child)
- right = child;
- else {
- child = addConversion(op, right->getType(), left);
- if (child)
- left = child;
- else
- return 0;
- }
- }
-
- //
- // Need a new node holding things together then. Make
- // one and promote it to the right type.
- //
- TIntermBinary* node = new TIntermBinary(op);
- node->setLine(line);
-
- node->setLeft(left);
- node->setRight(right);
- if (!node->promote(infoSink))
- return 0;
-
- //
- // See if we can fold constants.
- //
- TIntermTyped* typedReturnNode = 0;
- TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
- TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
- if (leftTempConstant && rightTempConstant) {
- typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
-
- if (typedReturnNode)
- return typedReturnNode;
- }
-
- return node;
-}
-
-//
-// Connect two nodes through an assignment.
-//
-// Returns the added node.
-//
-TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
-{
- //
- // Like adding binary math, except the conversion can only go
- // from right to left.
- //
- TIntermBinary* node = new TIntermBinary(op);
- node->setLine(line);
-
- TIntermTyped* child = addConversion(op, left->getType(), right);
- if (child == 0)
- return 0;
-
- node->setLeft(left);
- node->setRight(child);
- if (! node->promote(infoSink))
- return 0;
-
- return node;
-}
-
-//
-// Connect two nodes through an index operator, where the left node is the base
-// of an array or struct, and the right node is a direct or indirect offset.
-//
-// Returns the added node.
-// The caller should set the type of the returned node.
-//
-TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
-{
- TIntermBinary* node = new TIntermBinary(op);
- node->setLine(line);
- node->setLeft(base);
- node->setRight(index);
-
- // caller should set the type
-
- return node;
-}
-
-//
-// Add one node as the parent of another that it operates on.
-//
-// Returns the added node.
-//
-TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable)
-{
- TIntermUnary* node;
- TIntermTyped* child = childNode->getAsTyped();
-
- if (child == 0) {
- infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
- return 0;
- }
-
- switch (op) {
- case EOpLogicalNot:
- if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
- return 0;
- }
- break;
-
- case EOpPostIncrement:
- case EOpPreIncrement:
- case EOpPostDecrement:
- case EOpPreDecrement:
- case EOpNegative:
- if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
- return 0;
- default: break;
- }
-
- //
- // Do we need to promote the operand?
- //
- // Note: Implicit promotions were removed from the language.
- //
- TBasicType newType = EbtVoid;
- switch (op) {
- case EOpConstructInt: newType = EbtInt; break;
- case EOpConstructBool: newType = EbtBool; break;
- case EOpConstructFloat: newType = EbtFloat; break;
- default: break;
- }
-
- if (newType != EbtVoid) {
- child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
- child->getNominalSize(),
- child->isMatrix(),
- child->isArray()),
- child);
- if (child == 0)
- return 0;
- }
-
- //
- // For constructors, we are now done, it's all in the conversion.
- //
- switch (op) {
- case EOpConstructInt:
- case EOpConstructBool:
- case EOpConstructFloat:
- return child;
- default: break;
- }
-
- TIntermConstantUnion *childTempConstant = 0;
- if (child->getAsConstantUnion())
- childTempConstant = child->getAsConstantUnion();
-
- //
- // Make a new node for the operator.
- //
- node = new TIntermUnary(op);
- node->setLine(line);
- node->setOperand(child);
-
- if (! node->promote(infoSink))
- return 0;
-
- if (childTempConstant) {
- TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
-
- if (newChild)
- return newChild;
- }
-
- return node;
-}
-
-//
-// This is the safe way to change the operator on an aggregate, as it
-// does lots of error checking and fixing. Especially for establishing
-// a function call's operation on it's set of parameters. Sequences
-// of instructions are also aggregates, but they just direnctly set
-// their operator to EOpSequence.
-//
-// Returns an aggregate node, which could be the one passed in if
-// it was already an aggregate but no operator was set.
-//
-TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
-{
- TIntermAggregate* aggNode;
-
- //
- // Make sure we have an aggregate. If not turn it into one.
- //
- if (node) {
- aggNode = node->getAsAggregate();
- if (aggNode == 0 || aggNode->getOp() != EOpNull) {
- //
- // Make an aggregate containing this node.
- //
- aggNode = new TIntermAggregate();
- aggNode->getSequence().push_back(node);
- }
- } else
- aggNode = new TIntermAggregate();
-
- //
- // Set the operator.
- //
- aggNode->setOp(op);
- aggNode->setLine(line);
-
- return aggNode;
-}
-
-//
-// Convert one type to another.
-//
-// Returns the node representing the conversion, which could be the same
-// node passed in if no conversion was needed.
-//
-// Return 0 if a conversion can't be done.
-//
-TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
-{
- //
- // Does the base type allow operation?
- //
- switch (node->getBasicType()) {
- case EbtVoid:
- case EbtSampler2D:
- case EbtSamplerCube:
- return 0;
- default: break;
- }
-
- //
- // Otherwise, if types are identical, no problem
- //
- if (type == node->getType())
- return node;
-
- //
- // If one's a structure, then no conversions.
- //
- if (type.getStruct() || node->getType().getStruct())
- return 0;
-
- //
- // If one's an array, then no conversions.
- //
- if (type.isArray() || node->getType().isArray())
- return 0;
-
- TBasicType promoteTo;
-
- switch (op) {
- //
- // Explicit conversions
- //
- case EOpConstructBool:
- promoteTo = EbtBool;
- break;
- case EOpConstructFloat:
- promoteTo = EbtFloat;
- break;
- case EOpConstructInt:
- promoteTo = EbtInt;
- break;
- default:
- //
- // implicit conversions were removed from the language.
- //
- if (type.getBasicType() != node->getType().getBasicType())
- return 0;
- //
- // Size and structure could still differ, but that's
- // handled by operator promotion.
- //
- return node;
- }
-
- if (node->getAsConstantUnion()) {
-
- return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
- } else {
-
- //
- // Add a new newNode for the conversion.
- //
- TIntermUnary* newNode = 0;
-
- TOperator newOp = EOpNull;
- switch (promoteTo) {
- case EbtFloat:
- switch (node->getBasicType()) {
- case EbtInt: newOp = EOpConvIntToFloat; break;
- case EbtBool: newOp = EOpConvBoolToFloat; break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
- return 0;
- }
- break;
- case EbtBool:
- switch (node->getBasicType()) {
- case EbtInt: newOp = EOpConvIntToBool; break;
- case EbtFloat: newOp = EOpConvFloatToBool; break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
- return 0;
- }
- break;
- case EbtInt:
- switch (node->getBasicType()) {
- case EbtBool: newOp = EOpConvBoolToInt; break;
- case EbtFloat: newOp = EOpConvFloatToInt; break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
- return 0;
- }
- break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
- return 0;
- }
-
- TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
- newNode = new TIntermUnary(newOp, type);
- newNode->setLine(node->getLine());
- newNode->setOperand(node);
-
- return newNode;
- }
-}
-
-//
-// Safe way to combine two nodes into an aggregate. Works with null pointers,
-// a node that's not a aggregate yet, etc.
-//
-// Returns the resulting aggregate, unless 0 was passed in for
-// both existing nodes.
-//
-TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
-{
- if (left == 0 && right == 0)
- return 0;
-
- TIntermAggregate* aggNode = 0;
- if (left)
- aggNode = left->getAsAggregate();
- if (!aggNode || aggNode->getOp() != EOpNull) {
- aggNode = new TIntermAggregate;
- if (left)
- aggNode->getSequence().push_back(left);
- }
-
- if (right)
- aggNode->getSequence().push_back(right);
-
- aggNode->setLine(line);
-
- return aggNode;
-}
-
-//
-// Turn an existing node into an aggregate.
-//
-// Returns an aggregate, unless 0 was passed in for the existing node.
-//
-TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
-{
- if (node == 0)
- return 0;
-
- TIntermAggregate* aggNode = new TIntermAggregate;
- aggNode->getSequence().push_back(node);
- aggNode->setLine(line);
-
- return aggNode;
-}
-
-//
-// For "if" test nodes. There are three children; a condition,
-// a true path, and a false path. The two paths are in the
-// nodePair.
-//
-// Returns the selection node created.
-//
-TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
-{
- //
- // For compile time constant selections, prune the code and
- // test now.
- //
-
- if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
- if (cond->getAsConstantUnion()->getBConst(0) == true)
- return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
- else
- return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
- }
-
- TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
- node->setLine(line);
-
- return node;
-}
-
-
-TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
-{
- if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
- return right;
- } else {
- TIntermTyped *commaAggregate = growAggregate(left, right, line);
- commaAggregate->getAsAggregate()->setOp(EOpComma);
- commaAggregate->setType(right->getType());
- commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
- return commaAggregate;
- }
-}
-
-//
-// For "?:" test nodes. There are three children; a condition,
-// a true path, and a false path. The two paths are specified
-// as separate parameters.
-//
-// Returns the selection node created, or 0 if one could not be.
-//
-TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
-{
- //
- // Get compatible types.
- //
- TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
- if (child)
- falseBlock = child;
- else {
- child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
- if (child)
- trueBlock = child;
- else
- return 0;
- }
-
- //
- // See if all the operands are constant, then fold it otherwise not.
- //
-
- if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
- if (cond->getAsConstantUnion()->getBConst(0))
- return trueBlock;
- else
- return falseBlock;
- }
-
- //
- // Make a selection node.
- //
- TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
- node->getTypePointer()->setQualifier(EvqTemporary);
- node->setLine(line);
-
- return node;
-}
-
-//
-// Constant terminal nodes. Has a union that contains bool, float or int constants
-//
-// Returns the constant union node created.
-//
-
-TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
-{
- TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
- node->setLine(line);
-
- return node;
-}
-
-TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
-{
-
- TIntermAggregate* node = new TIntermAggregate(EOpSequence);
-
- node->setLine(line);
- TIntermConstantUnion* constIntNode;
- TIntermSequence &sequenceVector = node->getSequence();
- ConstantUnion* unionArray;
-
- for (int i = 0; i < fields.num; i++) {
- unionArray = new ConstantUnion[1];
- unionArray->setIConst(fields.offsets[i]);
- constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
- sequenceVector.push_back(constIntNode);
- }
-
- return node;
-}
-
-//
-// Create loop nodes.
-//
-TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
-{
- TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
- node->setLine(line);
-
- return node;
-}
-
-//
-// Add branches.
-//
-TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
-{
- return addBranch(branchOp, 0, line);
-}
-
-TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
-{
- TIntermBranch* node = new TIntermBranch(branchOp, expression);
- node->setLine(line);
-
- return node;
-}
-
-//
-// This is to be executed once the final root is put on top by the parsing
-// process.
-//
-bool TIntermediate::postProcess(TIntermNode* root)
-{
- if (root == 0)
- return true;
-
- //
- // First, finish off the top level sequence, if any
- //
- TIntermAggregate* aggRoot = root->getAsAggregate();
- if (aggRoot && aggRoot->getOp() == EOpNull)
- aggRoot->setOp(EOpSequence);
-
- return true;
-}
-
-//
-// This deletes the tree.
-//
-void TIntermediate::remove(TIntermNode* root)
-{
- if (root)
- RemoveAllTreeNodes(root);
-}
-
-////////////////////////////////////////////////////////////////
-//
-// Member functions of the nodes used for building the tree.
-//
-////////////////////////////////////////////////////////////////
-
-#define REPLACE_IF_IS(node, type, original, replacement) \
- if (node == original) { \
- node = static_cast<type *>(replacement); \
- return true; \
- }
-
-bool TIntermLoop::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- REPLACE_IF_IS(init, TIntermNode, original, replacement);
- REPLACE_IF_IS(cond, TIntermTyped, original, replacement);
- REPLACE_IF_IS(expr, TIntermTyped, original, replacement);
- REPLACE_IF_IS(body, TIntermNode, original, replacement);
- return false;
-}
-
-bool TIntermBranch::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- REPLACE_IF_IS(expression, TIntermTyped, original, replacement);
- return false;
-}
-
-bool TIntermBinary::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- REPLACE_IF_IS(left, TIntermTyped, original, replacement);
- REPLACE_IF_IS(right, TIntermTyped, original, replacement);
- return false;
-}
-
-bool TIntermUnary::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- REPLACE_IF_IS(operand, TIntermTyped, original, replacement);
- return false;
-}
-
-bool TIntermAggregate::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- for (size_t ii = 0; ii < sequence.size(); ++ii)
- {
- REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement);
- }
- return false;
-}
-
-bool TIntermSelection::replaceChildNode(
- TIntermNode *original, TIntermNode *replacement)
-{
- REPLACE_IF_IS(condition, TIntermTyped, original, replacement);
- REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement);
- REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement);
- return false;
-}
-
-//
-// Say whether or not an operation node changes the value of a variable.
-//
-bool TIntermOperator::isAssignment() const
-{
- 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:
- return true;
- default:
- return false;
- }
-}
-
-//
-// returns true if the operator is for one of the constructors
-//
-bool TIntermOperator::isConstructor() const
-{
- switch (op) {
- case EOpConstructVec2:
- case EOpConstructVec3:
- case EOpConstructVec4:
- case EOpConstructMat2:
- case EOpConstructMat3:
- case EOpConstructMat4:
- case EOpConstructFloat:
- case EOpConstructIVec2:
- case EOpConstructIVec3:
- case EOpConstructIVec4:
- case EOpConstructInt:
- case EOpConstructBVec2:
- case EOpConstructBVec3:
- case EOpConstructBVec4:
- case EOpConstructBool:
- case EOpConstructStruct:
- return true;
- default:
- return false;
- }
-}
-
-//
-// Make sure the type of a unary operator is appropriate for its
-// combination of operation and operand type.
-//
-// Returns false in nothing makes sense.
-//
-bool TIntermUnary::promote(TInfoSink&)
-{
- switch (op) {
- case EOpLogicalNot:
- if (operand->getBasicType() != EbtBool)
- return false;
- break;
- case EOpNegative:
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- if (operand->getBasicType() == EbtBool)
- return false;
- break;
-
- // operators for built-ins are already type checked against their prototype
- case EOpAny:
- case EOpAll:
- case EOpVectorLogicalNot:
- return true;
-
- default:
- if (operand->getBasicType() != EbtFloat)
- return false;
- }
-
- setType(operand->getType());
- type.setQualifier(EvqTemporary);
-
- return true;
-}
-
-//
-// Establishes the type of the resultant operation, as well as
-// makes the operator the correct one for the operands.
-//
-// Returns false if operator can't work on operands.
-//
-bool TIntermBinary::promote(TInfoSink& infoSink)
-{
- // This function only handles scalars, vectors, and matrices.
- if (left->isArray() || right->isArray()) {
- infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
- return false;
- }
-
- // GLSL ES 2.0 does not support implicit type casting.
- // So the basic type should always match.
- if (left->getBasicType() != right->getBasicType())
- return false;
-
- //
- // Base assumption: just make the type the same as the left
- // operand. Then only deviations from this need be coded.
- //
- setType(left->getType());
-
- // The result gets promoted to the highest precision.
- TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
- getTypePointer()->setPrecision(higherPrecision);
-
- // Binary operations results in temporary variables unless both
- // operands are const.
- if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
- getTypePointer()->setQualifier(EvqTemporary);
- }
-
- int size = std::max(left->getNominalSize(), right->getNominalSize());
-
- //
- // All scalars. Code after this test assumes this case is removed!
- //
- if (size == 1) {
- switch (op) {
- //
- // Promote to conditional
- //
- case EOpEqual:
- case EOpNotEqual:
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- setType(TType(EbtBool, EbpUndefined));
- break;
-
- //
- // And and Or operate on conditionals
- //
- case EOpLogicalAnd:
- case EOpLogicalOr:
- // Both operands must be of type bool.
- if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
- return false;
- setType(TType(EbtBool, EbpUndefined));
- break;
-
- default:
- break;
- }
- return true;
- }
-
- // If we reach here, at least one of the operands is vector or matrix.
- // The other operand could be a scalar, vector, or matrix.
- // Are the sizes compatible?
- //
- if (left->getNominalSize() != right->getNominalSize()) {
- // If the nominal size of operands do not match:
- // One of them must be scalar.
- if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
- return false;
- // Operator cannot be of type pure assignment.
- if (op == EOpAssign || op == EOpInitialize)
- return false;
- }
-
- //
- // Can these two operands be combined?
- //
- TBasicType basicType = left->getBasicType();
- switch (op) {
- case EOpMul:
- if (!left->isMatrix() && right->isMatrix()) {
- if (left->isVector())
- op = EOpVectorTimesMatrix;
- else {
- op = EOpMatrixTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
- }
- } else if (left->isMatrix() && !right->isMatrix()) {
- if (right->isVector()) {
- op = EOpMatrixTimesVector;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
- } else {
- op = EOpMatrixTimesScalar;
- }
- } else if (left->isMatrix() && right->isMatrix()) {
- op = EOpMatrixTimesMatrix;
- } else if (!left->isMatrix() && !right->isMatrix()) {
- if (left->isVector() && right->isVector()) {
- // leave as component product
- } else if (left->isVector() || right->isVector()) {
- op = EOpVectorTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
- }
- } else {
- infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
- return false;
- }
- break;
- case EOpMulAssign:
- if (!left->isMatrix() && right->isMatrix()) {
- if (left->isVector())
- op = EOpVectorTimesMatrixAssign;
- else {
- return false;
- }
- } else if (left->isMatrix() && !right->isMatrix()) {
- if (right->isVector()) {
- return false;
- } else {
- op = EOpMatrixTimesScalarAssign;
- }
- } else if (left->isMatrix() && right->isMatrix()) {
- op = EOpMatrixTimesMatrixAssign;
- } else if (!left->isMatrix() && !right->isMatrix()) {
- if (left->isVector() && right->isVector()) {
- // leave as component product
- } else if (left->isVector() || right->isVector()) {
- if (! left->isVector())
- return false;
- op = EOpVectorTimesScalarAssign;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
- }
- } else {
- infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
- return false;
- }
- break;
-
- case EOpAssign:
- case EOpInitialize:
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpDivAssign:
- if ((left->isMatrix() && right->isVector()) ||
- (left->isVector() && right->isMatrix()))
- return false;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
- break;
-
- case EOpEqual:
- case EOpNotEqual:
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- if ((left->isMatrix() && right->isVector()) ||
- (left->isVector() && right->isMatrix()))
- return false;
- setType(TType(EbtBool, EbpUndefined));
- break;
-
- default:
- return false;
- }
-
- return true;
-}
-
-bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
-{
- const TFieldList& fields = leftNodeType.getStruct()->fields();
-
- size_t structSize = fields.size();
- size_t index = 0;
-
- for (size_t j = 0; j < structSize; j++) {
- size_t size = fields[j]->type()->getObjectSize();
- for (size_t i = 0; i < size; i++) {
- if (fields[j]->type()->getBasicType() == EbtStruct) {
- if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
- return false;
- } else {
- if (leftUnionArray[index] != rightUnionArray[index])
- return false;
- index++;
- }
- }
- }
- return true;
-}
-
-bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
-{
- if (leftNodeType.isArray()) {
- TType typeWithoutArrayness = leftNodeType;
- typeWithoutArrayness.clearArrayness();
-
- size_t arraySize = leftNodeType.getArraySize();
-
- for (size_t i = 0; i < arraySize; ++i) {
- size_t offset = typeWithoutArrayness.getObjectSize() * i;
- if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
- return false;
- }
- } else
- return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
-
- return true;
-}
-
-//
-// The fold functions see if an operation on a constant can be done in place,
-// without generating run-time code.
-//
-// Returns the node to keep using, which may or may not be the node passed in.
-//
-
-TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
-{
- ConstantUnion *unionArray = getUnionArrayPointer();
- size_t objectSize = getType().getObjectSize();
-
- if (constantNode) { // binary operations
- TIntermConstantUnion *node = constantNode->getAsConstantUnion();
- ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
- TType returnType = getType();
-
- // for a case like float f = 1.2 + vec4(2,3,4,5);
- if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
- rightUnionArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; ++i)
- rightUnionArray[i] = *node->getUnionArrayPointer();
- returnType = getType();
- } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
- // for a case like float f = vec4(2,3,4,5) + 1.2;
- unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
- for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
- unionArray[i] = *getUnionArrayPointer();
- returnType = node->getType();
- objectSize = constantNode->getType().getObjectSize();
- }
-
- ConstantUnion* tempConstArray = 0;
- TIntermConstantUnion *tempNode;
-
- bool boolNodeFlag = false;
- switch(op) {
- case EOpAdd:
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] + rightUnionArray[i];
- }
- break;
- case EOpSub:
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] - rightUnionArray[i];
- }
- break;
-
- case EOpMul:
- case EOpVectorTimesScalar:
- case EOpMatrixTimesScalar:
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] * rightUnionArray[i];
- }
- break;
- case EOpMatrixTimesMatrix:
- if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
- infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
- return 0;
- }
- {// support MSVC++6.0
- int size = getNominalSize();
- tempConstArray = new ConstantUnion[size*size];
- for (int row = 0; row < size; row++) {
- for (int column = 0; column < size; column++) {
- tempConstArray[size * column + row].setFConst(0.0f);
- for (int i = 0; i < size; i++) {
- tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
- }
- }
- }
- }
- break;
- case EOpDiv:
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++) {
- switch (getType().getBasicType()) {
- case EbtFloat:
- if (rightUnionArray[i] == 0.0f) {
- infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
- tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
- } else
- tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
- break;
-
- case EbtInt:
- if (rightUnionArray[i] == 0) {
- infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
- tempConstArray[i].setIConst(INT_MAX);
- } else
- tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
- break;
- default:
- infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
- return 0;
- }
- }
- }
- break;
-
- case EOpMatrixTimesVector:
- if (node->getBasicType() != EbtFloat) {
- infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
- return 0;
- }
- tempConstArray = new ConstantUnion[getNominalSize()];
-
- {// support MSVC++6.0
- for (int size = getNominalSize(), i = 0; i < size; i++) {
- tempConstArray[i].setFConst(0.0f);
- for (int j = 0; j < size; j++) {
- tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
- }
- }
- }
-
- tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
- tempNode->setLine(getLine());
-
- return tempNode;
-
- case EOpVectorTimesMatrix:
- if (getType().getBasicType() != EbtFloat) {
- infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
- return 0;
- }
-
- tempConstArray = new ConstantUnion[getNominalSize()];
- {// support MSVC++6.0
- for (int size = getNominalSize(), i = 0; i < size; i++) {
- tempConstArray[i].setFConst(0.0f);
- for (int j = 0; j < size; j++) {
- tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
- }
- }
- }
- break;
-
- case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] && rightUnionArray[i];
- }
- break;
-
- case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] || rightUnionArray[i];
- }
- break;
-
- case EOpLogicalXor:
- tempConstArray = new ConstantUnion[objectSize];
- {// support MSVC++6.0
- for (size_t i = 0; i < objectSize; i++)
- switch (getType().getBasicType()) {
- case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
- default: assert(false && "Default missing");
- }
- }
- break;
-
- case EOpLessThan:
- assert(objectSize == 1);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(*unionArray < *rightUnionArray);
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
- break;
- case EOpGreaterThan:
- assert(objectSize == 1);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(*unionArray > *rightUnionArray);
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
- break;
- case EOpLessThanEqual:
- {
- assert(objectSize == 1);
- ConstantUnion constant;
- constant.setBConst(*unionArray > *rightUnionArray);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
- break;
- }
- case EOpGreaterThanEqual:
- {
- assert(objectSize == 1);
- ConstantUnion constant;
- constant.setBConst(*unionArray < *rightUnionArray);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
- break;
- }
-
- case EOpEqual:
- if (getType().getBasicType() == EbtStruct) {
- if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
- boolNodeFlag = true;
- } else {
- for (size_t i = 0; i < objectSize; i++) {
- if (unionArray[i] != rightUnionArray[i]) {
- boolNodeFlag = true;
- break; // break out of for loop
- }
- }
- }
-
- tempConstArray = new ConstantUnion[1];
- if (!boolNodeFlag) {
- tempConstArray->setBConst(true);
- }
- else {
- tempConstArray->setBConst(false);
- }
-
- tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
- tempNode->setLine(getLine());
-
- return tempNode;
-
- case EOpNotEqual:
- if (getType().getBasicType() == EbtStruct) {
- if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
- boolNodeFlag = true;
- } else {
- for (size_t i = 0; i < objectSize; i++) {
- if (unionArray[i] == rightUnionArray[i]) {
- boolNodeFlag = true;
- break; // break out of for loop
- }
- }
- }
-
- tempConstArray = new ConstantUnion[1];
- if (!boolNodeFlag) {
- tempConstArray->setBConst(true);
- }
- else {
- tempConstArray->setBConst(false);
- }
-
- tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
- tempNode->setLine(getLine());
-
- return tempNode;
-
- default:
- infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
- return 0;
- }
- tempNode = new TIntermConstantUnion(tempConstArray, returnType);
- tempNode->setLine(getLine());
-
- return tempNode;
- } else {
- //
- // Do unary operations
- //
- TIntermConstantUnion *newNode = 0;
- ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++) {
- switch(op) {
- case EOpNegative:
- switch (getType().getBasicType()) {
- case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
- case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
- default:
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return 0;
- }
- break;
- case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
- switch (getType().getBasicType()) {
- case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
- default:
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return 0;
- }
- break;
- default:
- return 0;
- }
- }
- newNode = new TIntermConstantUnion(tempConstArray, getType());
- newNode->setLine(getLine());
- return newNode;
- }
-}
-
-TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
-{
- size_t size = node->getType().getObjectSize();
-
- ConstantUnion *leftUnionArray = new ConstantUnion[size];
-
- for (size_t i = 0; i < size; i++) {
- int index = static_cast<int>(i);
- switch (promoteTo) {
- case EbtFloat:
- switch (node->getType().getBasicType()) {
- case EbtInt:
- leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(index)));
- break;
- case EbtBool:
- leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(index)));
- break;
- case EbtFloat:
- leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(index)));
- break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
- return 0;
- }
- break;
- case EbtInt:
- switch (node->getType().getBasicType()) {
- case EbtInt:
- leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(index)));
- break;
- case EbtBool:
- leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(index)));
- break;
- case EbtFloat:
- leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(index)));
- break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
- return 0;
- }
- break;
- case EbtBool:
- switch (node->getType().getBasicType()) {
- case EbtInt:
- leftUnionArray[i].setBConst(node->getIConst(index) != 0);
- break;
- case EbtBool:
- leftUnionArray[i].setBConst(node->getBConst(index));
- break;
- case EbtFloat:
- leftUnionArray[i].setBConst(node->getFConst(index) != 0.0f);
- break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
- return 0;
- }
-
- break;
- default:
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
- return 0;
- }
-
- }
-
- const TType& t = node->getType();
-
- return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
-}
-
-// static
-TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
-{
- if (hashFunction == NULL || name.empty())
- return name;
- khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
- TStringStream stream;
- stream << HASHED_NAME_PREFIX << std::hex << number;
- TString hashedName = stream.str();
- return hashedName;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp
deleted file mode 100644
index 077ef5d72..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-// 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/MapLongVariableNames.h"
-
-namespace {
-
-TString mapLongName(size_t id, const TString& name, bool isGlobal)
-{
- ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
- TStringStream stream;
- stream << "webgl_";
- if (isGlobal)
- stream << "g";
- stream << id;
- if (name[0] != '_')
- stream << "_";
- stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
- return stream.str();
-}
-
-LongNameMap* gLongNameMapInstance = NULL;
-
-} // anonymous namespace
-
-LongNameMap::LongNameMap()
- : refCount(0)
-{
-}
-
-LongNameMap::~LongNameMap()
-{
-}
-
-// static
-LongNameMap* LongNameMap::GetInstance()
-{
- if (gLongNameMapInstance == NULL)
- gLongNameMapInstance = new LongNameMap;
- gLongNameMapInstance->refCount++;
- return gLongNameMapInstance;
-}
-
-void LongNameMap::Release()
-{
- ASSERT(gLongNameMapInstance == this);
- ASSERT(refCount > 0);
- refCount--;
- if (refCount == 0) {
- delete gLongNameMapInstance;
- gLongNameMapInstance = NULL;
- }
-}
-
-const char* LongNameMap::Find(const char* originalName) const
-{
- std::map<std::string, std::string>::const_iterator it = mLongNameMap.find(
- originalName);
- if (it != mLongNameMap.end())
- return (*it).second.c_str();
- return NULL;
-}
-
-void LongNameMap::Insert(const char* originalName, const char* mappedName)
-{
- mLongNameMap.insert(std::map<std::string, std::string>::value_type(
- originalName, mappedName));
-}
-
-size_t LongNameMap::Size() const
-{
- return mLongNameMap.size();
-}
-
-MapLongVariableNames::MapLongVariableNames(LongNameMap* globalMap)
-{
- ASSERT(globalMap);
- mGlobalMap = globalMap;
-}
-
-void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol)
-{
- ASSERT(symbol != NULL);
- if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) {
- switch (symbol->getQualifier()) {
- case EvqVaryingIn:
- case EvqVaryingOut:
- case EvqInvariantVaryingIn:
- case EvqInvariantVaryingOut:
- case EvqUniform:
- symbol->setSymbol(
- mapGlobalLongName(symbol->getSymbol()));
- break;
- default:
- symbol->setSymbol(
- mapLongName(symbol->getId(), symbol->getSymbol(), false));
- break;
- };
- }
-}
-
-TString MapLongVariableNames::mapGlobalLongName(const TString& name)
-{
- ASSERT(mGlobalMap);
- const char* mappedName = mGlobalMap->Find(name.c_str());
- if (mappedName != NULL)
- return mappedName;
- size_t id = mGlobalMap->Size();
- TString rt = mapLongName(id, name, true);
- mGlobalMap->Insert(name.c_str(), rt.c_str());
- return rt;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h
deleted file mode 100644
index fd2ff8261..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// 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_MAP_LONG_VARIABLE_NAMES_H_
-#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/intermediate.h"
-#include "compiler/VariableInfo.h"
-
-// This size does not include '\0' in the end.
-#define MAX_SHORTENED_IDENTIFIER_SIZE 32
-
-// This is a ref-counted singleton. GetInstance() returns a pointer to the
-// singleton, and after use, call Release(). GetInstance() and Release() should
-// be paired.
-class LongNameMap {
-public:
- static LongNameMap* GetInstance();
- void Release();
-
- // Return the mapped name if <originalName, mappedName> is in the map;
- // otherwise, return NULL.
- const char* Find(const char* originalName) const;
-
- // Insert a pair into the map.
- void Insert(const char* originalName, const char* mappedName);
-
- // Return the number of entries in the map.
- size_t Size() const;
-
-private:
- LongNameMap();
- ~LongNameMap();
-
- size_t refCount;
- std::map<std::string, std::string> mLongNameMap;
-};
-
-// Traverses intermediate tree to map attributes and uniforms names that are
-// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE.
-class MapLongVariableNames : public TIntermTraverser {
-public:
- MapLongVariableNames(LongNameMap* globalMap);
-
- virtual void visitSymbol(TIntermSymbol*);
-
-private:
- TString mapGlobalLongName(const TString& name);
-
- LongNameMap* mGlobalMap;
-};
-
-#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp
deleted file mode 100644
index c2048f1ce..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// 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/OutputESSL.h"
-
-TOutputESSL::TOutputESSL(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable)
- : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable)
-{
-}
-
-bool TOutputESSL::writeVariablePrecision(TPrecision precision)
-{
- if (precision == EbpUndefined)
- return false;
-
- TInfoSinkBase& out = objSink();
- out << getPrecisionString(precision);
- return true;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h
deleted file mode 100644
index 05db96e49..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// 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 CROSSCOMPILERGLSL_OUTPUTESSL_H_
-#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
-
-#include "compiler/OutputGLSLBase.h"
-
-class TOutputESSL : public TOutputGLSLBase
-{
-public:
- TOutputESSL(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable);
-
-protected:
- virtual bool writeVariablePrecision(TPrecision precision);
-};
-
-#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp
deleted file mode 100644
index 10a451c0d..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// 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/OutputGLSL.h"
-
-TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable)
- : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable)
-{
-}
-
-bool TOutputGLSL::writeVariablePrecision(TPrecision)
-{
- return false;
-}
-
-void TOutputGLSL::visitSymbol(TIntermSymbol* node)
-{
- TInfoSinkBase& out = objSink();
-
- if (node->getSymbol() == "gl_FragDepthEXT")
- {
- out << "gl_FragDepth";
- }
- else
- {
- TOutputGLSLBase::visitSymbol(node);
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h
deleted file mode 100644
index fa68ac810..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// 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 CROSSCOMPILERGLSL_OUTPUTGLSL_H_
-#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
-
-#include "compiler/OutputGLSLBase.h"
-
-class TOutputGLSL : public TOutputGLSLBase
-{
-public:
- TOutputGLSL(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable);
-
-protected:
- virtual bool writeVariablePrecision(TPrecision);
- virtual void visitSymbol(TIntermSymbol* node);
-};
-
-#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp
deleted file mode 100644
index b90bd67ec..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp
+++ /dev/null
@@ -1,817 +0,0 @@
-//
-// 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/OutputGLSLBase.h"
-#include "compiler/debug.h"
-
-#include <cfloat>
-
-namespace
-{
-TString arrayBrackets(const TType& type)
-{
- ASSERT(type.isArray());
- TInfoSinkBase out;
- out << "[" << type.getArraySize() << "]";
- return TString(out.c_str());
-}
-
-bool isSingleStatement(TIntermNode* node) {
- if (const TIntermAggregate* aggregate = node->getAsAggregate())
- {
- return (aggregate->getOp() != EOpFunction) &&
- (aggregate->getOp() != EOpSequence);
- }
- else if (const TIntermSelection* selection = node->getAsSelectionNode())
- {
- // Ternary operators are usually part of an assignment operator.
- // This handles those rare cases in which they are all by themselves.
- return selection->usesTernaryOperator();
- }
- else if (node->getAsLoopNode())
- {
- return false;
- }
- return true;
-}
-} // namespace
-
-TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable)
- : TIntermTraverser(true, true, true),
- mObjSink(objSink),
- mDeclaringVariables(false),
- mClampingStrategy(clampingStrategy),
- mHashFunction(hashFunction),
- mNameMap(nameMap),
- mSymbolTable(symbolTable)
-{
-}
-
-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::writeVariableType(const TType& type)
-{
- TInfoSinkBase& out = objSink();
- TQualifier qualifier = type.getQualifier();
- // TODO(alokp): Validate qualifier for variable declarations.
- if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
- out << type.getQualifierString() << " ";
- // Declare the struct if we have not done so already.
- if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
- {
- declareStruct(type.getStruct());
- }
- else
- {
- if (writeVariablePrecision(type.getPrecision()))
- out << " ";
- out << getTypeName(type);
- }
-}
-
-void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
-{
- TInfoSinkBase& out = objSink();
- for (TIntermSequence::const_iterator iter = args.begin();
- iter != args.end(); ++iter)
- {
- const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
- ASSERT(arg != NULL);
-
- const TType& type = arg->getType();
- writeVariableType(type);
-
- const TString& name = arg->getSymbol();
- if (!name.empty())
- out << " " << hashName(name);
- if (type.isArray())
- out << arrayBrackets(type);
-
- // Put a comma if this is not the last argument.
- if (iter != args.end() - 1)
- out << ", ";
- }
-}
-
-const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
- const ConstantUnion* pConstUnion)
-{
- TInfoSinkBase& out = objSink();
-
- if (type.getBasicType() == EbtStruct)
- {
- const TStructure* structure = type.getStruct();
- out << hashName(structure->name()) << "(";
-
- const TFieldList& fields = structure->fields();
- for (size_t i = 0; i < fields.size(); ++i)
- {
- const TType* fieldType = fields[i]->type();
- ASSERT(fieldType != NULL);
- 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: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
- case EbtInt: out << pConstUnion->getIConst(); break;
- case EbtBool: out << pConstUnion->getBConst(); break;
- default: UNREACHABLE();
- }
- if (i != size - 1) out << ", ";
- }
- if (writeType) out << ")";
- }
- return pConstUnion;
-}
-
-void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
-{
- TInfoSinkBase& out = objSink();
- if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
- out << mLoopUnroll.GetLoopIndexValue(node);
- else
- out << hashVariableName(node->getSymbol());
-
- if (mDeclaringVariables && node->getType().isArray())
- out << arrayBrackets(node->getType());
-}
-
-void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
-{
- writeConstantUnion(node->getType(), node->getUnionArrayPointer());
-}
-
-bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
-{
- bool visitChildren = true;
- TInfoSinkBase& out = objSink();
- switch (node->getOp())
- {
- case EOpInitialize:
- if (visit == InVisit)
- {
- out << " = ";
- // RHS of initialize is not being declared.
- mDeclaringVariables = false;
- }
- break;
- case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
- case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
- case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
- case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
- // Notice the fall-through.
- case EOpMulAssign:
- case EOpVectorTimesMatrixAssign:
- case EOpVectorTimesScalarAssign:
- case EOpMatrixTimesScalarAssign:
- case EOpMatrixTimesMatrixAssign:
- writeTriplet(visit, "(", " *= ", ")");
- break;
-
- case EOpIndexDirect:
- writeTriplet(visit, NULL, "[", "]");
- 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)
- {
- int maxSize;
- TIntermTyped *left = node->getLeft();
- TType leftType = left->getType();
-
- if (left->isArray())
- {
- // The shader will fail validation if the array length is not > 0.
- maxSize = leftType.getArraySize() - 1;
- }
- else
- {
- maxSize = leftType.getNominalSize() - 1;
- }
-
- if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
- out << "), 0.0, float(" << maxSize << ")))]";
- } else {
- out << ", 0, " << maxSize << ")]";
- }
- }
- }
- else
- {
- writeTriplet(visit, NULL, "[", "]");
- }
- 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)];
-
- TString fieldName = field->name();
- if (!mSymbolTable.findBuiltIn(structure->name()))
- fieldName = hashName(fieldName);
-
- out << fieldName;
- visitChildren = false;
- }
- break;
- case EOpVectorSwizzle:
- if (visit == InVisit)
- {
- out << ".";
- TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
- TIntermSequence& sequence = rightChild->getSequence();
- for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
- {
- TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
- ASSERT(element->getBasicType() == EbtInt);
- ASSERT(element->getNominalSize() == 1);
- const ConstantUnion& data = element->getUnionArrayPointer()[0];
- ASSERT(data.getType() == EbtInt);
- switch (data.getIConst())
- {
- case 0: out << "x"; break;
- case 1: out << "y"; break;
- case 2: out << "z"; break;
- case 3: out << "w"; break;
- default: UNREACHABLE(); break;
- }
- }
- visitChildren = false;
- }
- break;
-
- case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
- case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
- case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
- case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
- case EOpMod: UNIMPLEMENTED(); 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(); break;
- }
-
- return visitChildren;
-}
-
-bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
-{
- TString preString;
- TString postString = ")";
-
- switch (node->getOp())
- {
- case EOpNegative: preString = "(-"; break;
- case EOpVectorLogicalNot: preString = "not("; break;
- case EOpLogicalNot: preString = "(!"; break;
-
- case EOpPostIncrement: preString = "("; postString = "++)"; break;
- case EOpPostDecrement: preString = "("; postString = "--)"; break;
- case EOpPreIncrement: preString = "(++"; break;
- case EOpPreDecrement: preString = "(--"; break;
-
- case EOpConvIntToBool:
- case EOpConvFloatToBool:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: preString = "bool("; break;
- case 2: preString = "bvec2("; break;
- case 3: preString = "bvec3("; break;
- case 4: preString = "bvec4("; break;
- default: UNREACHABLE();
- }
- break;
- case EOpConvBoolToFloat:
- case EOpConvIntToFloat:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: preString = "float("; break;
- case 2: preString = "vec2("; break;
- case 3: preString = "vec3("; break;
- case 4: preString = "vec4("; break;
- default: UNREACHABLE();
- }
- break;
- case EOpConvFloatToInt:
- case EOpConvBoolToInt:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: preString = "int("; break;
- case 2: preString = "ivec2("; break;
- case 3: preString = "ivec3("; break;
- case 4: preString = "ivec4("; break;
- default: UNREACHABLE();
- }
- break;
-
- case EOpRadians: preString = "radians("; break;
- case EOpDegrees: preString = "degrees("; break;
- case EOpSin: preString = "sin("; break;
- case EOpCos: preString = "cos("; break;
- case EOpTan: preString = "tan("; break;
- case EOpAsin: preString = "asin("; break;
- case EOpAcos: preString = "acos("; break;
- case EOpAtan: preString = "atan("; break;
-
- case EOpExp: preString = "exp("; break;
- case EOpLog: preString = "log("; break;
- case EOpExp2: preString = "exp2("; break;
- case EOpLog2: preString = "log2("; break;
- case EOpSqrt: preString = "sqrt("; break;
- case EOpInverseSqrt: preString = "inversesqrt("; break;
-
- case EOpAbs: preString = "abs("; break;
- case EOpSign: preString = "sign("; break;
- case EOpFloor: preString = "floor("; break;
- case EOpCeil: preString = "ceil("; break;
- case EOpFract: preString = "fract("; break;
-
- case EOpLength: preString = "length("; break;
- case EOpNormalize: preString = "normalize("; break;
-
- case EOpDFdx: preString = "dFdx("; break;
- case EOpDFdy: preString = "dFdy("; break;
- case EOpFwidth: preString = "fwidth("; break;
-
- case EOpAny: preString = "any("; break;
- case EOpAll: preString = "all("; break;
-
- default: UNREACHABLE(); break;
- }
-
- if (visit == PreVisit && node->getUseEmulatedFunction())
- preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
- writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
-
- return true;
-}
-
-bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
-{
- TInfoSinkBase& out = objSink();
-
- if (node->usesTernaryOperator())
- {
- // 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->getTrueBlock()->traverse(this);
- out << ") : (";
- node->getFalseBlock()->traverse(this);
- out << "))";
- }
- else
- {
- out << "if (";
- node->getCondition()->traverse(this);
- out << ")\n";
-
- incrementDepth(node);
- visitCodeBlock(node->getTrueBlock());
-
- if (node->getFalseBlock())
- {
- out << "else\n";
- visitCodeBlock(node->getFalseBlock());
- }
- decrementDepth();
- }
- return false;
-}
-
-bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- bool visitChildren = true;
- TInfoSinkBase& out = objSink();
- TString preString;
- bool delayedWrite = false;
- switch (node->getOp())
- {
- case EOpSequence: {
- // Scope the sequences except when at the global scope.
- if (depth > 0) out << "{\n";
-
- incrementDepth(node);
- const TIntermSequence& sequence = node->getSequence();
- for (TIntermSequence::const_iterator iter = sequence.begin();
- iter != sequence.end(); ++iter)
- {
- TIntermNode* node = *iter;
- ASSERT(node != NULL);
- node->traverse(this);
-
- if (isSingleStatement(node))
- out << ";\n";
- }
- decrementDepth();
-
- // Scope the sequences except when at the global scope.
- if (depth > 0) out << "}\n";
- visitChildren = false;
- break;
- }
- case EOpPrototype: {
- // Function declaration.
- ASSERT(visit == PreVisit);
- writeVariableType(node->getType());
- out << " " << hashName(node->getName());
-
- out << "(";
- writeFunctionParameters(node->getSequence());
- out << ")";
-
- visitChildren = false;
- break;
- }
- case EOpFunction: {
- // Function definition.
- ASSERT(visit == PreVisit);
- writeVariableType(node->getType());
- out << " " << hashFunctionName(node->getName());
-
- incrementDepth(node);
- // Function definition node contains one or two children nodes
- // representing function parameters and function body. The latter
- // is not present in case of empty function bodies.
- const TIntermSequence& sequence = node->getSequence();
- ASSERT((sequence.size() == 1) || (sequence.size() == 2));
- TIntermSequence::const_iterator seqIter = sequence.begin();
-
- // Traverse function parameters.
- TIntermAggregate* params = (*seqIter)->getAsAggregate();
- ASSERT(params != NULL);
- ASSERT(params->getOp() == EOpParameters);
- params->traverse(this);
-
- // Traverse function body.
- TIntermAggregate* body = ++seqIter != sequence.end() ?
- (*seqIter)->getAsAggregate() : NULL;
- visitCodeBlock(body);
- decrementDepth();
-
- // Fully processed; no need to visit children.
- visitChildren = false;
- break;
- }
- case EOpFunctionCall:
- // Function call.
- if (visit == PreVisit)
- {
- out << hashFunctionName(node->getName()) << "(";
- }
- else if (visit == InVisit)
- {
- out << ", ";
- }
- else
- {
- out << ")";
- }
- break;
- case EOpParameters: {
- // Function parameters.
- ASSERT(visit == PreVisit);
- out << "(";
- writeFunctionParameters(node->getSequence());
- out << ")";
- visitChildren = false;
- break;
- }
- case EOpDeclaration: {
- // Variable declaration.
- if (visit == PreVisit)
- {
- const TIntermSequence& sequence = node->getSequence();
- const TIntermTyped* variable = sequence.front()->getAsTyped();
- writeVariableType(variable->getType());
- out << " ";
- mDeclaringVariables = true;
- }
- else if (visit == InVisit)
- {
- out << ", ";
- mDeclaringVariables = true;
- }
- else
- {
- mDeclaringVariables = false;
- }
- break;
- }
- case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
- case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
- case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
- case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
- case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
- case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
- case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
- case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
- case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
- case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
- case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
- case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
- case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
- case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
- case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
- case EOpConstructStruct:
- if (visit == PreVisit)
- {
- const TType& type = node->getType();
- ASSERT(type.getBasicType() == EbtStruct);
- out << hashName(type.getStruct()->name()) << "(";
- }
- else if (visit == InVisit)
- {
- out << ", ";
- }
- else
- {
- out << ")";
- }
- break;
-
- case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
- case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
- case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
- case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
- case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
- case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
- case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
-
- case EOpMod: preString = "mod("; delayedWrite = true; break;
- case EOpPow: preString = "pow("; delayedWrite = true; break;
- case EOpAtan: preString = "atan("; delayedWrite = true; break;
- case EOpMin: preString = "min("; delayedWrite = true; break;
- case EOpMax: preString = "max("; delayedWrite = true; break;
- case EOpClamp: preString = "clamp("; delayedWrite = true; break;
- case EOpMix: preString = "mix("; delayedWrite = true; break;
- case EOpStep: preString = "step("; delayedWrite = true; break;
- case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
-
- case EOpDistance: preString = "distance("; delayedWrite = true; break;
- case EOpDot: preString = "dot("; delayedWrite = true; break;
- case EOpCross: preString = "cross("; delayedWrite = true; break;
- case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
- case EOpReflect: preString = "reflect("; delayedWrite = true; break;
- case EOpRefract: preString = "refract("; delayedWrite = true; break;
- case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
-
- default: UNREACHABLE(); break;
- }
- if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
- preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
- if (delayedWrite)
- writeTriplet(visit, preString.c_str(), ", ", ")");
- return visitChildren;
-}
-
-bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
-{
- TInfoSinkBase& out = objSink();
-
- incrementDepth(node);
- // Loop header.
- TLoopType loopType = node->getType();
- if (loopType == ELoopFor) // for loop
- {
- if (!node->getUnrollFlag()) {
- 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";
- }
- }
- else if (loopType == ELoopWhile) // while loop
- {
- out << "while (";
- ASSERT(node->getCondition() != NULL);
- node->getCondition()->traverse(this);
- out << ")\n";
- }
- else // do-while loop
- {
- ASSERT(loopType == ELoopDoWhile);
- out << "do\n";
- }
-
- // Loop body.
- if (node->getUnrollFlag())
- {
- TLoopIndexInfo indexInfo;
- mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
- mLoopUnroll.Push(indexInfo);
- while (mLoopUnroll.SatisfiesLoopCondition())
- {
- visitCodeBlock(node->getBody());
- mLoopUnroll.Step();
- }
- mLoopUnroll.Pop();
- }
- else
- {
- visitCodeBlock(node->getBody());
- }
-
- // Loop footer.
- if (loopType == ELoopDoWhile) // do-while loop
- {
- out << "while (";
- ASSERT(node->getCondition() != NULL);
- node->getCondition()->traverse(this);
- out << ");\n";
- }
- decrementDepth();
-
- // 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", NULL, NULL); break;
- case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
- case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
- case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
- default: UNREACHABLE(); break;
- }
-
- return true;
-}
-
-void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
- TInfoSinkBase &out = objSink();
- if (node != NULL)
- {
- 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.
- }
-}
-
-TString TOutputGLSLBase::getTypeName(const TType& type)
-{
- TInfoSinkBase out;
- if (type.isMatrix())
- {
- out << "mat";
- out << type.getNominalSize();
- }
- else if (type.isVector())
- {
- switch (type.getBasicType())
- {
- case EbtFloat: out << "vec"; break;
- case EbtInt: out << "ivec"; break;
- case EbtBool: out << "bvec"; break;
- default: UNREACHABLE(); break;
- }
- out << type.getNominalSize();
- }
- else
- {
- if (type.getBasicType() == EbtStruct)
- out << hashName(type.getStruct()->name());
- else
- out << type.getBasicString();
- }
- return TString(out.c_str());
-}
-
-TString TOutputGLSLBase::hashName(const TString& name)
-{
- if (mHashFunction == NULL || name.empty())
- return name;
- NameMap::const_iterator it = mNameMap.find(name.c_str());
- if (it != mNameMap.end())
- return it->second.c_str();
- TString hashedName = TIntermTraverser::hash(name, mHashFunction);
- mNameMap[name.c_str()] = hashedName.c_str();
- return hashedName;
-}
-
-TString TOutputGLSLBase::hashVariableName(const TString& name)
-{
- if (mSymbolTable.findBuiltIn(name) != NULL)
- return name;
- return hashName(name);
-}
-
-TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
-{
- TString name = TFunction::unmangleName(mangled_name);
- if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
- return name;
- return hashName(name);
-}
-
-bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
-{
- return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
-}
-
-void TOutputGLSLBase::declareStruct(const TStructure* structure)
-{
- TInfoSinkBase& out = objSink();
-
- out << "struct " << hashName(structure->name()) << "{\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()) << " " << hashName(field->name());
- if (field->type()->isArray())
- out << arrayBrackets(*field->type());
- out << ";\n";
- }
- out << "}";
-
- mDeclaredStructs.insert(structure->name());
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h
deleted file mode 100644
index 69868c09c..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-// 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 CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
-#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
-
-#include <set>
-
-#include "compiler/ForLoopUnroll.h"
-#include "compiler/intermediate.h"
-#include "compiler/ParseContext.h"
-
-class TOutputGLSLBase : public TIntermTraverser
-{
-public:
- TOutputGLSLBase(TInfoSinkBase& objSink,
- ShArrayIndexClampingStrategy clampingStrategy,
- ShHashFunction64 hashFunction,
- NameMap& nameMap,
- TSymbolTable& symbolTable);
-
-protected:
- TInfoSinkBase& objSink() { return mObjSink; }
- void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
- void writeVariableType(const TType& type);
- virtual bool writeVariablePrecision(TPrecision precision) = 0;
- void writeFunctionParameters(const TIntermSequence& args);
- const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
- TString getTypeName(const TType& type);
-
- virtual void visitSymbol(TIntermSymbol* node);
- virtual void visitConstantUnion(TIntermConstantUnion* node);
- virtual bool visitBinary(Visit visit, TIntermBinary* node);
- virtual bool visitUnary(Visit visit, TIntermUnary* node);
- virtual bool visitSelection(Visit visit, TIntermSelection* node);
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
- virtual bool visitLoop(Visit visit, TIntermLoop* node);
- virtual bool visitBranch(Visit visit, TIntermBranch* node);
-
- void visitCodeBlock(TIntermNode* node);
-
-
- // Return the original name if hash function pointer is NULL;
- // otherwise return the hashed name.
- TString hashName(const TString& name);
- // Same as hashName(), but without hashing built-in variables.
- TString hashVariableName(const TString& name);
- // Same as hashName(), but without hashing built-in functions.
- TString hashFunctionName(const TString& mangled_name);
-
-private:
- bool structDeclared(const TStructure* structure) const;
- void declareStruct(const TStructure* structure);
-
- TInfoSinkBase& mObjSink;
- bool mDeclaringVariables;
-
- // Structs are declared as the tree is traversed. This set contains all
- // the structs already declared. It is maintained so that a struct is
- // declared only once.
- typedef std::set<TString> DeclaredStructs;
- DeclaredStructs mDeclaredStructs;
-
- ForLoopUnroll mLoopUnroll;
-
- ShArrayIndexClampingStrategy mClampingStrategy;
-
- // name hashing.
- ShHashFunction64 mHashFunction;
-
- NameMap& mNameMap;
-
- TSymbolTable& mSymbolTable;
-};
-
-#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp
deleted file mode 100644
index a715f229c..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp
+++ /dev/null
@@ -1,3133 +0,0 @@
-//
-// 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/OutputHLSL.h"
-
-#include "common/angleutils.h"
-#include "compiler/debug.h"
-#include "compiler/DetectDiscontinuity.h"
-#include "compiler/InfoSink.h"
-#include "compiler/SearchSymbol.h"
-#include "compiler/UnfoldShortCircuit.h"
-#include "compiler/NodeSearch.h"
-
-#include <algorithm>
-#include <cfloat>
-#include <stdio.h>
-
-namespace sh
-{
-// Integer to TString conversion
-TString str(int i)
-{
- char buffer[20];
- snprintf(buffer, sizeof(buffer), "%d", i);
- return buffer;
-}
-
-OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
- : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
-{
- mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
- mInsideFunction = false;
-
- mUsesTexture2D = false;
- mUsesTexture2D_bias = false;
- mUsesTexture2DProj = false;
- mUsesTexture2DProj_bias = false;
- mUsesTexture2DProjLod = false;
- mUsesTexture2DLod = false;
- mUsesTextureCube = false;
- mUsesTextureCube_bias = false;
- mUsesTextureCubeLod = false;
- mUsesTexture2DLod0 = false;
- mUsesTexture2DLod0_bias = false;
- mUsesTexture2DProjLod0 = false;
- mUsesTexture2DProjLod0_bias = false;
- mUsesTextureCubeLod0 = false;
- mUsesTextureCubeLod0_bias = false;
- mUsesFragColor = false;
- mUsesFragData = false;
- mUsesDepthRange = false;
- mUsesFragCoord = false;
- mUsesPointCoord = false;
- mUsesFrontFacing = false;
- mUsesPointSize = false;
- mUsesFragDepth = false;
- mUsesXor = false;
- mUsesMod1 = false;
- mUsesMod2v = false;
- mUsesMod2f = false;
- mUsesMod3v = false;
- mUsesMod3f = false;
- mUsesMod4v = false;
- mUsesMod4f = false;
- mUsesFaceforward1 = false;
- mUsesFaceforward2 = false;
- mUsesFaceforward3 = false;
- mUsesFaceforward4 = false;
- mUsesAtan2_1 = false;
- mUsesAtan2_2 = false;
- mUsesAtan2_3 = false;
- mUsesAtan2_4 = false;
- mUsesDiscardRewriting = false;
-
- mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
-
- mScopeDepth = 0;
-
- mUniqueIndex = 0;
-
- mContainsLoopDiscontinuity = false;
- mOutputLod0Function = false;
- mInsideDiscontinuousLoop = false;
-
- mExcessiveLoopIndex = NULL;
-
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- if (mContext.shaderType == SH_FRAGMENT_SHADER)
- {
- mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
- }
- else
- {
- mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust
- }
- }
- else
- {
- mUniformRegister = 0;
- }
-
- mSamplerRegister = 0;
-}
-
-OutputHLSL::~OutputHLSL()
-{
- delete mUnfoldShortCircuit;
-}
-
-void OutputHLSL::output()
-{
- mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
-
- mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
- header();
-
- mContext.infoSink().obj << mHeader.c_str();
- mContext.infoSink().obj << mBody.c_str();
-}
-
-TInfoSinkBase &OutputHLSL::getBodyStream()
-{
- return mBody;
-}
-
-const ActiveUniforms &OutputHLSL::getUniforms()
-{
- return mActiveUniforms;
-}
-
-int OutputHLSL::vectorSize(const TType &type) const
-{
- int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
- int arraySize = type.isArray() ? type.getArraySize() : 1;
-
- return elementSize * arraySize;
-}
-
-void OutputHLSL::header()
-{
- ShShaderType shaderType = mContext.shaderType;
- TInfoSinkBase &out = mHeader;
-
- for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
- {
- out << *structDeclaration;
- }
-
- for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
- {
- out << *constructor;
- }
-
- TString uniforms;
- TString varyings;
- TString attributes;
-
- for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++)
- {
- const TType &type = uniform->second->getType();
- const TString &name = uniform->second->getSymbol();
-
- if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
- {
- int index = samplerRegister(mReferencedUniforms[name]);
-
- uniforms += "uniform SamplerState sampler_" + decorateUniform(name, type) + arrayString(type) +
- " : register(s" + str(index) + ");\n";
-
- uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) +
- " : register(t" + str(index) + ");\n";
- }
- else
- {
- uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) +
- " : register(" + registerString(mReferencedUniforms[name]) + ");\n";
- }
- }
-
- for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
- {
- const TType &type = varying->second->getType();
- const TString &name = varying->second->getSymbol();
-
- // Program linking depends on this exact format
- varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
- }
-
- for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
- {
- const TType &type = attribute->second->getType();
- const TString &name = attribute->second->getSymbol();
-
- attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
- }
-
- if (mUsesDiscardRewriting)
- {
- out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
- }
-
- if (shaderType == SH_FRAGMENT_SHADER)
- {
- TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
- const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
-
- const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
-
- out << "// Varyings\n";
- out << varyings;
- out << "\n"
- "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 (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_HLSL11_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";
- }
-
- 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";
- }
-
- out << uniforms;
- out << "\n";
-
- if (mUsesTexture2D)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
- "{\n"
- " return tex2D(s, t);\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n"
- "{\n"
- " return t.Sample(s, uv);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2D_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
- "{\n"
- " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv, float bias)\n"
- "{\n"
- " return t.SampleBias(s, uv, bias);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProj)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
- "{\n"
- " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
- "{\n"
- " return tex2Dproj(s, t);\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.Sample(s, float2(uvw.x / uvw.z, uvw.y / uvw.z));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
- "{\n"
- " return t.Sample(s, float2(uvw.x / uvw.w, uvw.y / uvw.w));\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProj_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
- "{\n"
- " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
- "{\n"
- " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float bias)\n"
- "{\n"
- " return t.SampleBias(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), bias);\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw, float bias)\n"
- "{\n"
- " return t.SampleBias(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), bias);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCube)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
- "{\n"
- " return texCUBE(s, t);\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.Sample(s, uvw);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCube_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
- "{\n"
- " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw, float bias)\n"
- "{\n"
- " return t.SampleBias(s, uvw, bias);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- // These *Lod0 intrinsics are not available in GL fragment shaders.
- // They are used to sample using discontinuous texture coordinates.
- if (mUsesTexture2DLod0)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv)\n"
- "{\n"
- " return t.SampleLevel(s, uv, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DLod0_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv, float bias)\n"
- "{\n"
- " return t.SampleLevel(s, uv, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProjLod0)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float4 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProjLod0_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float3 uvw, float bias)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float4 uvw, float bias)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCubeLod0)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n"
- "{\n"
- " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, uvw, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCubeLod0_bias)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n"
- "{\n"
- " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw, float bias)\n"
- "{\n"
- " return t.SampleLevel(s, uvw, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- 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";
- }
- }
- else // Vertex shader
- {
- out << "// Attributes\n";
- out << attributes;
- out << "\n"
- "static float4 gl_Position = float4(0, 0, 0, 0);\n";
-
- if (mUsesPointSize)
- {
- out << "static float gl_PointSize = float(1);\n";
- }
-
- out << "\n"
- "// Varyings\n";
- out << varyings;
- out << "\n";
-
- if (mUsesDepthRange)
- {
- out << "struct gl_DepthRangeParameters\n"
- "{\n"
- " float near;\n"
- " float far;\n"
- " float diff;\n"
- "};\n"
- "\n";
- }
-
- if (mOutputType == SH_HLSL11_OUTPUT)
- {
- if (mUsesDepthRange)
- {
- out << "cbuffer DriverConstants : register(b1)\n"
- "{\n"
- " float3 dx_DepthRange : packoffset(c0);\n"
- "};\n"
- "\n";
- }
- }
- else
- {
- if (mUsesDepthRange)
- {
- out << "uniform float3 dx_DepthRange : register(c0);\n";
- }
-
- out << "uniform float4 dx_ViewAdjust : register(c1);\n"
- "\n";
- }
-
- if (mUsesDepthRange)
- {
- out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
- "\n";
- }
-
- out << uniforms;
- out << "\n";
-
- if (mUsesTexture2D)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n"
- "{\n"
- " return t.SampleLevel(s, uv, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DLod)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DLod(Texture2D t, SamplerState s, float2 uv, float lod)\n"
- "{\n"
- " return t.SampleLevel(s, uv, lod);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProj)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTexture2DProjLod)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
- "{\n"
- " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float lod)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), lod);\n"
- "}\n"
- "\n"
- "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), lod);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCube)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
- "{\n"
- " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n"
- "{\n"
- " return t.SampleLevel(s, uvw, 0);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
-
- if (mUsesTextureCubeLod)
- {
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
- "{\n"
- " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n"
- "}\n"
- "\n";
- }
- else if (mOutputType == SH_HLSL11_OUTPUT)
- {
- out << "float4 gl_textureCubeLod(TextureCube t, SamplerState s, float3 uvw, float lod)\n"
- "{\n"
- " return t.SampleLevel(s, uvw, lod);\n"
- "}\n"
- "\n";
- }
- else UNREACHABLE();
- }
- }
-
- 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 (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";
- }
-
- if (mUsesMod1)
- {
- out << "float mod(float x, float y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod2v)
- {
- out << "float2 mod(float2 x, float2 y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod2f)
- {
- out << "float2 mod(float2 x, float y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod3v)
- {
- out << "float3 mod(float3 x, float3 y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod3f)
- {
- out << "float3 mod(float3 x, float y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod4v)
- {
- out << "float4 mod(float4 x, float4 y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesMod4f)
- {
- out << "float4 mod(float4 x, float y)\n"
- "{\n"
- " return x - y * floor(x / y);\n"
- "}\n"
- "\n";
- }
-
- if (mUsesFaceforward1)
- {
- out << "float faceforward(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"
- "\n";
- }
-
- if (mUsesFaceforward2)
- {
- out << "float2 faceforward(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"
- "\n";
- }
-
- if (mUsesFaceforward3)
- {
- out << "float3 faceforward(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"
- "\n";
- }
-
- if (mUsesFaceforward4)
- {
- out << "float4 faceforward(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"
- "\n";
- }
-
- if (mUsesAtan2_1)
- {
- out << "float atanyx(float y, float x)\n"
- "{\n"
- " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
- " return atan2(y, x);\n"
- "}\n";
- }
-
- if (mUsesAtan2_2)
- {
- out << "float2 atanyx(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";
- }
-
- if (mUsesAtan2_3)
- {
- out << "float3 atanyx(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";
- }
-
- if (mUsesAtan2_4)
- {
- out << "float4 atanyx(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], x[2]), atan2(y[3], x[3]));\n"
- "}\n";
- }
-}
-
-void OutputHLSL::visitSymbol(TIntermSymbol *node)
-{
- TInfoSinkBase &out = mBody;
-
- TString name = node->getSymbol();
-
- if (name == "gl_FragColor")
- {
- out << "gl_Color[0]";
- mUsesFragColor = true;
- }
- else if (name == "gl_FragData")
- {
- out << "gl_Color";
- mUsesFragData = true;
- }
- else if (name == "gl_DepthRange")
- {
- mUsesDepthRange = true;
- out << name;
- }
- else if (name == "gl_FragCoord")
- {
- mUsesFragCoord = true;
- out << name;
- }
- else if (name == "gl_PointCoord")
- {
- mUsesPointCoord = true;
- out << name;
- }
- else if (name == "gl_FrontFacing")
- {
- mUsesFrontFacing = true;
- out << name;
- }
- else if (name == "gl_PointSize")
- {
- mUsesPointSize = true;
- out << name;
- }
- else if (name == "gl_FragDepthEXT")
- {
- mUsesFragDepth = true;
- out << "gl_Depth";
- }
- else
- {
- TQualifier qualifier = node->getQualifier();
-
- if (qualifier == EvqUniform)
- {
- mReferencedUniforms[name] = node;
- out << decorateUniform(name, node->getType());
- }
- else if (qualifier == EvqAttribute)
- {
- mReferencedAttributes[name] = node;
- out << decorate(name);
- }
- else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
- {
- mReferencedVaryings[name] = node;
- out << decorate(name);
- }
- else
- {
- out << decorate(name);
- }
- }
-}
-
-bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
-{
- TInfoSinkBase &out = mBody;
-
- switch (node->getOp())
- {
- case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
- case EOpInitialize:
- if (visit == PreVisit)
- {
- // 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;".
-
- TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
- TIntermTyped *expression = node->getRight();
-
- sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
- expression->traverse(&searchSymbol);
- bool sameSymbol = searchSymbol.foundMatch();
-
- if (sameSymbol)
- {
- // Type already printed
- out << "t" + str(mUniqueIndex) + " = ";
- expression->traverse(this);
- out << ", ";
- symbolNode->traverse(this);
- out << " = t" + str(mUniqueIndex);
-
- mUniqueIndex++;
- return false;
- }
- }
- else if (visit == InVisit)
- {
- out << " = ";
- }
- break;
- case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
- case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
- case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
- case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
- case EOpMatrixTimesScalarAssign: outputTriplet(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 << " = mul(";
- node->getLeft()->traverse(this);
- out << ", ";
- }
- else
- {
- out << "))";
- }
- break;
- case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
- case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
- case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
- case EOpIndexDirectStruct:
- if (visit == InVisit)
- {
- const TStructure* structure = node->getLeft()->getType().getStruct();
- const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
- const TField* field = structure->fields()[index->getIConst(0)];
- out << "." + decorateField(field->name(), node->getLeft()->getType());
-
- return false;
- }
- break;
- case EOpVectorSwizzle:
- if (visit == InVisit)
- {
- out << ".";
-
- TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
-
- if (swizzle)
- {
- TIntermSequence &sequence = swizzle->getSequence();
-
- for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
- {
- TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
-
- if (element)
- {
- int i = element->getIConst(0);
-
- switch (i)
- {
- case 0: out << "x"; break;
- case 1: out << "y"; break;
- case 2: out << "z"; break;
- case 3: out << "w"; break;
- default: UNREACHABLE();
- }
- }
- else UNREACHABLE();
- }
- }
- else UNREACHABLE();
-
- return false; // Fully processed
- }
- break;
- case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
- case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
- case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
- case EOpEqual:
- case EOpNotEqual:
- if (node->getLeft()->isScalar())
- {
- if (node->getOp() == EOpEqual)
- {
- outputTriplet(visit, "(", " == ", ")");
- }
- else
- {
- outputTriplet(visit, "(", " != ", ")");
- }
- }
- else if (node->getLeft()->getBasicType() == EbtStruct)
- {
- if (node->getOp() == EOpEqual)
- {
- out << "(";
- }
- else
- {
- out << "!(";
- }
-
- const TFieldList &fields = node->getLeft()->getType().getStruct()->fields();
-
- for (size_t i = 0; i < fields.size(); i++)
- {
- const TField *field = fields[i];
-
- node->getLeft()->traverse(this);
- out << "." + decorateField(field->name(), node->getLeft()->getType()) + " == ";
- node->getRight()->traverse(this);
- out << "." + decorateField(field->name(), node->getLeft()->getType());
-
- if (i < fields.size() - 1)
- {
- out << " && ";
- }
- }
-
- out << ")";
-
- return false;
- }
- else
- {
- ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
-
- if (node->getOp() == EOpEqual)
- {
- outputTriplet(visit, "all(", " == ", ")");
- }
- else
- {
- outputTriplet(visit, "!all(", " == ", ")");
- }
- }
- break;
- case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
- case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
- case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
- case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
- case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
- case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
- case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
- case EOpLogicalOr:
- if (node->getRight()->hasSideEffects())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- return false;
- }
- else
- {
- outputTriplet(visit, "(", " || ", ")");
- return true;
- }
- case EOpLogicalXor:
- mUsesXor = true;
- outputTriplet(visit, "xor(", ", ", ")");
- break;
- case EOpLogicalAnd:
- if (node->getRight()->hasSideEffects())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- return false;
- }
- else
- {
- outputTriplet(visit, "(", " && ", ")");
- return true;
- }
- default: UNREACHABLE();
- }
-
- return true;
-}
-
-bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
-{
- switch (node->getOp())
- {
- case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
- case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
- case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
- case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
- case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
- case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
- case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
- case EOpConvIntToBool:
- case EOpConvFloatToBool:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: outputTriplet(visit, "bool(", "", ")"); break;
- case 2: outputTriplet(visit, "bool2(", "", ")"); break;
- case 3: outputTriplet(visit, "bool3(", "", ")"); break;
- case 4: outputTriplet(visit, "bool4(", "", ")"); break;
- default: UNREACHABLE();
- }
- break;
- case EOpConvBoolToFloat:
- case EOpConvIntToFloat:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: outputTriplet(visit, "float(", "", ")"); break;
- case 2: outputTriplet(visit, "float2(", "", ")"); break;
- case 3: outputTriplet(visit, "float3(", "", ")"); break;
- case 4: outputTriplet(visit, "float4(", "", ")"); break;
- default: UNREACHABLE();
- }
- break;
- case EOpConvFloatToInt:
- case EOpConvBoolToInt:
- switch (node->getOperand()->getType().getNominalSize())
- {
- case 1: outputTriplet(visit, "int(", "", ")"); break;
- case 2: outputTriplet(visit, "int2(", "", ")"); break;
- case 3: outputTriplet(visit, "int3(", "", ")"); break;
- case 4: outputTriplet(visit, "int4(", "", ")"); break;
- default: UNREACHABLE();
- }
- break;
- case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
- case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
- case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
- case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
- case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
- case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
- case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
- case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
- case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
- case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
- case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
- case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
- case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
- case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
- case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
- case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
- case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
- case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
- case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
- case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
- case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
- case EOpDFdx:
- if(mInsideDiscontinuousLoop || mOutputLod0Function)
- {
- outputTriplet(visit, "(", "", ", 0.0)");
- }
- else
- {
- outputTriplet(visit, "ddx(", "", ")");
- }
- break;
- case EOpDFdy:
- if(mInsideDiscontinuousLoop || mOutputLod0Function)
- {
- outputTriplet(visit, "(", "", ", 0.0)");
- }
- else
- {
- outputTriplet(visit, "ddy(", "", ")");
- }
- break;
- case EOpFwidth:
- if(mInsideDiscontinuousLoop || mOutputLod0Function)
- {
- outputTriplet(visit, "(", "", ", 0.0)");
- }
- else
- {
- outputTriplet(visit, "fwidth(", "", ")");
- }
- break;
- case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
- case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
- default: UNREACHABLE();
- }
-
- return true;
-}
-
-bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
-{
- TInfoSinkBase &out = mBody;
-
- switch (node->getOp())
- {
- case EOpSequence:
- {
- if (mInsideFunction)
- {
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
-
- mScopeDepth++;
-
- if (mScopeBracket.size() < mScopeDepth)
- {
- mScopeBracket.push_back(0); // New scope level
- }
- else
- {
- mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
- }
- }
-
- for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
- {
- outputLineDirective((*sit)->getLine().first_line);
-
- traverseStatements(*sit);
-
- out << ";\n";
- }
-
- if (mInsideFunction)
- {
- outputLineDirective(node->getLine().last_line);
- out << "}\n";
-
- mScopeDepth--;
- }
-
- return false;
- }
- case EOpDeclaration:
- if (visit == PreVisit)
- {
- TIntermSequence &sequence = node->getSequence();
- TIntermTyped *variable = sequence[0]->getAsTyped();
-
- if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
- {
- if (variable->getType().getStruct())
- {
- addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL);
- }
-
- if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
- {
- if (!mInsideFunction)
- {
- out << "static ";
- }
-
- out << typeString(variable->getType()) + " ";
-
- for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
- {
- TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
-
- if (symbol)
- {
- symbol->traverse(this);
- out << arrayString(symbol->getType());
- out << " = " + initializer(variable->getType());
- }
- else
- {
- (*sit)->traverse(this);
- }
-
- if (*sit != sequence.back())
- {
- out << ", ";
- }
- }
- }
- else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
- {
- // Already added to constructor map
- }
- else UNREACHABLE();
- }
- else if (variable && (variable->getQualifier() == EvqVaryingOut || variable->getQualifier() == EvqInvariantVaryingOut))
- {
- for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
- {
- TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
-
- if (symbol)
- {
- // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
- mReferencedVaryings[symbol->getSymbol()] = symbol;
- }
- else
- {
- (*sit)->traverse(this);
- }
- }
- }
-
- return false;
- }
- else if (visit == InVisit)
- {
- out << ", ";
- }
- break;
- case EOpPrototype:
- if (visit == PreVisit)
- {
- out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
-
- TIntermSequence &arguments = node->getSequence();
-
- for (unsigned int i = 0; i < arguments.size(); i++)
- {
- TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
-
- if (symbol)
- {
- out << argumentString(symbol);
-
- if (i < arguments.size() - 1)
- {
- out << ", ";
- }
- }
- else UNREACHABLE();
- }
-
- out << ");\n";
-
- // Also prototype the Lod0 variant if needed
- if (mContainsLoopDiscontinuity && !mOutputLod0Function)
- {
- mOutputLod0Function = true;
- node->traverse(this);
- mOutputLod0Function = false;
- }
-
- return false;
- }
- break;
- case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
- case EOpFunction:
- {
- TString name = TFunction::unmangleName(node->getName());
-
- out << typeString(node->getType()) << " ";
-
- if (name == "main")
- {
- out << "gl_main(";
- }
- else
- {
- out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
- }
-
- TIntermSequence &sequence = node->getSequence();
- TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
-
- for (unsigned int i = 0; i < arguments.size(); i++)
- {
- TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
-
- if (symbol)
- {
- if (symbol->getType().getStruct())
- {
- addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL);
- }
-
- out << argumentString(symbol);
-
- if (i < arguments.size() - 1)
- {
- out << ", ";
- }
- }
- else UNREACHABLE();
- }
-
- out << ")\n"
- "{\n";
-
- if (sequence.size() > 1)
- {
- mInsideFunction = true;
- sequence[1]->traverse(this);
- mInsideFunction = false;
- }
-
- out << "}\n";
-
- if (mContainsLoopDiscontinuity && !mOutputLod0Function)
- {
- if (name != "main")
- {
- mOutputLod0Function = true;
- node->traverse(this);
- mOutputLod0Function = false;
- }
- }
-
- return false;
- }
- break;
- case EOpFunctionCall:
- {
- TString name = TFunction::unmangleName(node->getName());
- bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
-
- if (node->isUserDefined())
- {
- out << decorate(name) << (lod0 ? "Lod0(" : "(");
- }
- else
- {
- if (name == "texture2D")
- {
- if (!lod0)
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTexture2D = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTexture2D_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2D(";
- }
- else
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTexture2DLod0 = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTexture2DLod0_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2DLod0(";
- }
- }
- else if (name == "texture2DProj")
- {
- if (!lod0)
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTexture2DProj = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTexture2DProj_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2DProj(";
- }
- else
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTexture2DProjLod0 = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTexture2DProjLod0_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2DProjLod0(";
- }
- }
- else if (name == "textureCube")
- {
- if (!lod0)
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTextureCube = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTextureCube_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_textureCube(";
- }
- else
- {
- if (node->getSequence().size() == 2)
- {
- mUsesTextureCubeLod0 = true;
- }
- else if (node->getSequence().size() == 3)
- {
- mUsesTextureCubeLod0_bias = true;
- }
- else UNREACHABLE();
-
- out << "gl_textureCubeLod0(";
- }
- }
- else if (name == "texture2DLod")
- {
- if (node->getSequence().size() == 3)
- {
- mUsesTexture2DLod = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2DLod(";
- }
- else if (name == "texture2DProjLod")
- {
- if (node->getSequence().size() == 3)
- {
- mUsesTexture2DProjLod = true;
- }
- else UNREACHABLE();
-
- out << "gl_texture2DProjLod(";
- }
- else if (name == "textureCubeLod")
- {
- if (node->getSequence().size() == 3)
- {
- mUsesTextureCubeLod = true;
- }
- else UNREACHABLE();
-
- out << "gl_textureCubeLod(";
- }
- else UNREACHABLE();
- }
-
- TIntermSequence &arguments = node->getSequence();
-
- for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
- {
- if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
- {
- out << "texture_";
- (*arg)->traverse(this);
- out << ", sampler_";
- }
-
- (*arg)->traverse(this);
-
- if (arg < arguments.end() - 1)
- {
- out << ", ";
- }
- }
-
- out << ")";
-
- return false;
- }
- break;
- case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
- case EOpConstructFloat:
- addConstructor(node->getType(), "vec1", &node->getSequence());
- outputTriplet(visit, "vec1(", "", ")");
- break;
- case EOpConstructVec2:
- addConstructor(node->getType(), "vec2", &node->getSequence());
- outputTriplet(visit, "vec2(", ", ", ")");
- break;
- case EOpConstructVec3:
- addConstructor(node->getType(), "vec3", &node->getSequence());
- outputTriplet(visit, "vec3(", ", ", ")");
- break;
- case EOpConstructVec4:
- addConstructor(node->getType(), "vec4", &node->getSequence());
- outputTriplet(visit, "vec4(", ", ", ")");
- break;
- case EOpConstructBool:
- addConstructor(node->getType(), "bvec1", &node->getSequence());
- outputTriplet(visit, "bvec1(", "", ")");
- break;
- case EOpConstructBVec2:
- addConstructor(node->getType(), "bvec2", &node->getSequence());
- outputTriplet(visit, "bvec2(", ", ", ")");
- break;
- case EOpConstructBVec3:
- addConstructor(node->getType(), "bvec3", &node->getSequence());
- outputTriplet(visit, "bvec3(", ", ", ")");
- break;
- case EOpConstructBVec4:
- addConstructor(node->getType(), "bvec4", &node->getSequence());
- outputTriplet(visit, "bvec4(", ", ", ")");
- break;
- case EOpConstructInt:
- addConstructor(node->getType(), "ivec1", &node->getSequence());
- outputTriplet(visit, "ivec1(", "", ")");
- break;
- case EOpConstructIVec2:
- addConstructor(node->getType(), "ivec2", &node->getSequence());
- outputTriplet(visit, "ivec2(", ", ", ")");
- break;
- case EOpConstructIVec3:
- addConstructor(node->getType(), "ivec3", &node->getSequence());
- outputTriplet(visit, "ivec3(", ", ", ")");
- break;
- case EOpConstructIVec4:
- addConstructor(node->getType(), "ivec4", &node->getSequence());
- outputTriplet(visit, "ivec4(", ", ", ")");
- break;
- case EOpConstructMat2:
- addConstructor(node->getType(), "mat2", &node->getSequence());
- outputTriplet(visit, "mat2(", ", ", ")");
- break;
- case EOpConstructMat3:
- addConstructor(node->getType(), "mat3", &node->getSequence());
- outputTriplet(visit, "mat3(", ", ", ")");
- break;
- case EOpConstructMat4:
- addConstructor(node->getType(), "mat4", &node->getSequence());
- outputTriplet(visit, "mat4(", ", ", ")");
- break;
- case EOpConstructStruct:
- addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence());
- outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")");
- break;
- case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
- case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
- case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
- case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
- case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
- case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
- case EOpMod:
- {
- // We need to look at the number of components in both arguments
- switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
- + node->getSequence()[1]->getAsTyped()->getNominalSize())
- {
- case 11: mUsesMod1 = true; break;
- case 22: mUsesMod2v = true; break;
- case 21: mUsesMod2f = true; break;
- case 33: mUsesMod3v = true; break;
- case 31: mUsesMod3f = true; break;
- case 44: mUsesMod4v = true; break;
- case 41: mUsesMod4f = true; break;
- default: UNREACHABLE();
- }
-
- outputTriplet(visit, "mod(", ", ", ")");
- }
- break;
- case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
- case EOpAtan:
- ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
- switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
- {
- case 1: mUsesAtan2_1 = true; break;
- case 2: mUsesAtan2_2 = true; break;
- case 3: mUsesAtan2_3 = true; break;
- case 4: mUsesAtan2_4 = true; break;
- default: UNREACHABLE();
- }
- outputTriplet(visit, "atanyx(", ", ", ")");
- break;
- case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
- case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
- case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
- case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
- case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
- case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
- case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
- case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
- case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
- case EOpFaceForward:
- {
- switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
- {
- case 1: mUsesFaceforward1 = true; break;
- case 2: mUsesFaceforward2 = true; break;
- case 3: mUsesFaceforward3 = true; break;
- case 4: mUsesFaceforward4 = true; break;
- default: UNREACHABLE();
- }
-
- outputTriplet(visit, "faceforward(", ", ", ")");
- }
- break;
- case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
- case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
- case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
- default: UNREACHABLE();
- }
-
- return true;
-}
-
-bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
-{
- TInfoSinkBase &out = mBody;
-
- if (node->usesTernaryOperator())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- }
- else // if/else statement
- {
- mUnfoldShortCircuit->traverse(node->getCondition());
-
- out << "if (";
-
- node->getCondition()->traverse(this);
-
- out << ")\n";
-
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
-
- bool discard = false;
-
- if (node->getTrueBlock())
- {
- traverseStatements(node->getTrueBlock());
-
- // Detect true discard
- discard = (discard || FindDiscard::search(node->getTrueBlock()));
- }
-
- outputLineDirective(node->getLine().first_line);
- out << ";\n}\n";
-
- if (node->getFalseBlock())
- {
- out << "else\n";
-
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- out << "{\n";
-
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- traverseStatements(node->getFalseBlock());
-
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- out << ";\n}\n";
-
- // Detect false discard
- discard = (discard || FindDiscard::search(node->getFalseBlock()));
- }
-
- // ANGLE issue 486: Detect problematic conditional discard
- if (discard && FindSideEffectRewriting::search(node))
- {
- mUsesDiscardRewriting = true;
- }
- }
-
- return false;
-}
-
-void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
-{
- writeConstantUnion(node->getType(), node->getUnionArrayPointer());
-}
-
-bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
-{
- bool wasDiscontinuous = mInsideDiscontinuousLoop;
-
- if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
- {
- mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
- }
-
- if (mOutputType == SH_HLSL9_OUTPUT)
- {
- if (handleExcessiveLoop(node))
- {
- return false;
- }
- }
-
- TInfoSinkBase &out = mBody;
-
- if (node->getType() == ELoopDoWhile)
- {
- out << "{do\n";
-
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
- }
- else
- {
- 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";
-
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
- }
-
- if (node->getBody())
- {
- traverseStatements(node->getBody());
- }
-
- outputLineDirective(node->getLine().first_line);
- out << ";}\n";
-
- if (node->getType() == ELoopDoWhile)
- {
- outputLineDirective(node->getCondition()->getLine().first_line);
- out << "while(\n";
-
- node->getCondition()->traverse(this);
-
- out << ");";
- }
-
- out << "}\n";
-
- mInsideDiscontinuousLoop = wasDiscontinuous;
-
- return false;
-}
-
-bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
-{
- TInfoSinkBase &out = mBody;
-
- switch (node->getFlowOp())
- {
- case EOpKill:
- outputTriplet(visit, "discard;\n", "", "");
- break;
- case EOpBreak:
- if (visit == PreVisit)
- {
- if (mExcessiveLoopIndex)
- {
- out << "{Break";
- mExcessiveLoopIndex->traverse(this);
- out << " = true; break;}\n";
- }
- else
- {
- out << "break;\n";
- }
- }
- break;
- case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
- case EOpReturn:
- if (visit == PreVisit)
- {
- if (node->getExpression())
- {
- out << "return ";
- }
- else
- {
- out << "return;\n";
- }
- }
- else if (visit == PostVisit)
- {
- if (node->getExpression())
- {
- out << ";\n";
- }
- }
- break;
- default: UNREACHABLE();
- }
-
- return true;
-}
-
-void OutputHLSL::traverseStatements(TIntermNode *node)
-{
- if (isSingleStatement(node))
- {
- mUnfoldShortCircuit->traverse(node);
- }
-
- node->traverse(this);
-}
-
-bool OutputHLSL::isSingleStatement(TIntermNode *node)
-{
- TIntermAggregate *aggregate = node->getAsAggregate();
-
- if (aggregate)
- {
- if (aggregate->getOp() == EOpSequence)
- {
- return false;
- }
- else
- {
- for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
- {
- if (!isSingleStatement(*sit))
- {
- return false;
- }
- }
-
- return true;
- }
- }
-
- 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(TIntermLoop *node)
-{
- const int MAX_LOOP_ITERATIONS = 254;
- TInfoSinkBase &out = mBody;
-
- // Parse loops of the form:
- // for(int index = initial; index [comparator] limit; index += increment)
- TIntermSymbol *index = NULL;
- TOperator comparator = EOpNull;
- int initial = 0;
- int limit = 0;
- int increment = 0;
-
- // Parse index name and intial value
- if (node->getInit())
- {
- TIntermAggregate *init = node->getInit()->getAsAggregate();
-
- 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->getNominalSize() == 1)
- {
- index = symbol;
- initial = constant->getIConst(0);
- }
- }
- }
- }
- }
- }
-
- // Parse comparator and limit value
- if (index != NULL && node->getCondition())
- {
- TIntermBinary *test = node->getCondition()->getAsBinaryNode();
-
- if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
- {
- TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
-
- if (constant)
- {
- if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
- {
- comparator = test->getOp();
- limit = constant->getIConst(0);
- }
- }
- }
- }
-
- // Parse increment
- if (index != NULL && 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->getNominalSize() == 1)
- {
- 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 != NULL && 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 = NULL; // Stops setting the Break flag
- }
-
- // for(int index = initial; index < clampedLimit; index += increment)
-
- out << "for(";
- index->traverse(this);
- out << " = ";
- out << initial;
-
- out << "; ";
- index->traverse(this);
- out << " < ";
- out << clampedLimit;
-
- out << "; ";
- index->traverse(this);
- out << " += ";
- out << increment;
- out << ")\n";
-
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
-
- if (node->getBody())
- {
- node->getBody()->traverse(this);
- }
-
- outputLineDirective(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(Visit visit, const TString &preString, const TString &inString, const TString &postString)
-{
- TInfoSinkBase &out = mBody;
-
- if (visit == PreVisit)
- {
- out << preString;
- }
- else if (visit == InVisit)
- {
- out << inString;
- }
- else if (visit == PostVisit)
- {
- out << postString;
- }
-}
-
-void OutputHLSL::outputLineDirective(int line)
-{
- if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
- {
- mBody << "\n";
- mBody << "#line " << line;
-
- if (mContext.sourcePath)
- {
- mBody << " \"" << mContext.sourcePath << "\"";
- }
-
- mBody << "\n";
- }
-}
-
-TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
-{
- TQualifier qualifier = symbol->getQualifier();
- const TType &type = symbol->getType();
- TString name = symbol->getSymbol();
-
- if (name.empty()) // HLSL demands named arguments, also for prototypes
- {
- name = "x" + str(mUniqueIndex++);
- }
- else
- {
- name = decorate(name);
- }
-
- if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
- {
- return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " +
- qualifierString(qualifier) + " SamplerState sampler_" + name + arrayString(type);
- }
-
- return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
-}
-
-TString OutputHLSL::qualifierString(TQualifier qualifier)
-{
- switch(qualifier)
- {
- case EvqIn: return "in";
- case EvqOut: return "out";
- case EvqInOut: return "inout";
- case EvqConstReadOnly: return "const";
- default: UNREACHABLE();
- }
-
- return "";
-}
-
-TString OutputHLSL::typeString(const TType &type)
-{
- if (type.getBasicType() == EbtStruct)
- {
- const TString& typeName = type.getStruct()->name();
- if (typeName != "")
- {
- return structLookup(typeName);
- }
- else // Nameless structure, define in place
- {
- const TFieldList &fields = type.getStruct()->fields();
-
- TString string = "struct\n"
- "{\n";
-
- for (unsigned int i = 0; i < fields.size(); i++)
- {
- const TField *field = fields[i];
-
- string += " " + typeString(*field->type()) + " " + decorate(field->name()) + arrayString(*field->type()) + ";\n";
- }
-
- string += "} ";
-
- return string;
- }
- }
- else if (type.isMatrix())
- {
- switch (type.getNominalSize())
- {
- case 2: return "float2x2";
- case 3: return "float3x3";
- case 4: return "float4x4";
- }
- }
- 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 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:
- return "sampler2D";
- case EbtSamplerCube:
- return "samplerCUBE";
- case EbtSamplerExternalOES:
- return "sampler2D";
- default:
- break;
- }
- }
-
- UNREACHABLE();
- return "<unknown type>";
-}
-
-TString OutputHLSL::textureString(const TType &type)
-{
- switch (type.getBasicType())
- {
- case EbtSampler2D:
- return "Texture2D";
- case EbtSamplerCube:
- return "TextureCube";
- case EbtSamplerExternalOES:
- return "Texture2D";
- default:
- break;
- }
-
- UNREACHABLE();
- return "<unknown texture type>";
-}
-
-TString OutputHLSL::arrayString(const TType &type)
-{
- if (!type.isArray())
- {
- return "";
- }
-
- return "[" + str(type.getArraySize()) + "]";
-}
-
-TString OutputHLSL::initializer(const TType &type)
-{
- TString string;
-
- size_t size = type.getObjectSize();
- for (size_t component = 0; component < size; component++)
- {
- string += "0";
-
- if (component + 1 < size)
- {
- string += ", ";
- }
- }
-
- return "{" + string + "}";
-}
-
-void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
-{
- if (name == "")
- {
- return; // Nameless structures don't have constructors
- }
-
- if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
- {
- return; // Already added
- }
-
- TType ctorType = type;
- ctorType.clearArrayness();
- ctorType.setPrecision(EbpHigh);
- ctorType.setQualifier(EvqTemporary);
-
- TString ctorName = type.getStruct() ? decorate(name) : name;
-
- typedef std::vector<TType> ParameterArray;
- ParameterArray ctorParameters;
-
- if (type.getStruct())
- {
- mStructNames.insert(decorate(name));
-
- TString structure;
- structure += "struct " + decorate(name) + "\n"
- "{\n";
-
- const TFieldList &fields = type.getStruct()->fields();
-
- for (unsigned int i = 0; i < fields.size(); i++)
- {
- const TField *field = fields[i];
-
- structure += " " + typeString(*field->type()) + " " + decorateField(field->name(), type) + arrayString(*field->type()) + ";\n";
- }
-
- structure += "};\n";
-
- if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
- {
- mStructDeclarations.push_back(structure);
- }
-
- for (unsigned int i = 0; i < fields.size(); i++)
- {
- ctorParameters.push_back(*fields[i]->type());
- }
- }
- else if (parameters)
- {
- for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
- {
- ctorParameters.push_back((*parameter)->getAsTyped()->getType());
- }
- }
- else UNREACHABLE();
-
- TString constructor;
-
- if (ctorType.getStruct())
- {
- constructor += ctorName + " " + ctorName + "_ctor(";
- }
- else // Built-in type
- {
- constructor += typeString(ctorType) + " " + ctorName + "(";
- }
-
- for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
- {
- const TType &type = ctorParameters[parameter];
-
- constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
-
- if (parameter < ctorParameters.size() - 1)
- {
- constructor += ", ";
- }
- }
-
- constructor += ")\n"
- "{\n";
-
- if (ctorType.getStruct())
- {
- constructor += " " + ctorName + " structure = {";
- }
- else
- {
- constructor += " return " + typeString(ctorType) + "(";
- }
-
- if (ctorType.isMatrix() && ctorParameters.size() == 1)
- {
- int dim = ctorType.getNominalSize();
- const TType &parameter = ctorParameters[0];
-
- if (parameter.isScalar())
- {
- for (int row = 0; row < dim; row++)
- {
- for (int col = 0; col < dim; col++)
- {
- constructor += TString((row == col) ? "x0" : "0.0");
-
- if (row < dim - 1 || col < dim - 1)
- {
- constructor += ", ";
- }
- }
- }
- }
- else if (parameter.isMatrix())
- {
- for (int row = 0; row < dim; row++)
- {
- for (int col = 0; col < dim; col++)
- {
- if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
- {
- constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
- }
- else
- {
- constructor += TString((row == col) ? "1.0" : "0.0");
- }
-
- if (row < dim - 1 || col < dim - 1)
- {
- constructor += ", ";
- }
- }
- }
- }
- else UNREACHABLE();
- }
- 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(static_cast<int>(parameterIndex));
-
- if (parameter.isScalar())
- {
- ASSERT(parameterSize <= remainingComponents);
- remainingComponents -= parameterSize;
- }
- 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() || parameter.getStruct())
- {
- ASSERT(remainingComponents == parameterSize || moreParameters);
- ASSERT(parameterSize <= remainingComponents);
-
- remainingComponents -= parameterSize;
- }
- else UNREACHABLE();
-
- if (moreParameters)
- {
- parameterIndex++;
- }
-
- if (remainingComponents)
- {
- constructor += ", ";
- }
- }
- }
-
- if (ctorType.getStruct())
- {
- constructor += "};\n"
- " return structure;\n"
- "}\n";
- }
- else
- {
- constructor += ");\n"
- "}\n";
- }
-
- mConstructors.insert(constructor);
-}
-
-const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
-{
- TInfoSinkBase &out = mBody;
-
- if (type.getBasicType() == EbtStruct)
- {
- out << structLookup(type.getStruct()->name()) + "_ctor(";
-
- const TFieldList &fields = type.getStruct()->fields();
-
- for (size_t i = 0; i < fields.size(); i++)
- {
- const TType *fieldType = fields[i]->type();
-
- constUnion = writeConstantUnion(*fieldType, constUnion);
-
- if (i != fields.size() - 1)
- {
- out << ", ";
- }
- }
-
- out << ")";
- }
- else
- {
- size_t size = type.getObjectSize();
- bool writeType = size > 1;
-
- if (writeType)
- {
- out << typeString(type) << "(";
- }
-
- for (size_t i = 0; i < size; i++, constUnion++)
- {
- switch (constUnion->getType())
- {
- case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
- case EbtInt: out << constUnion->getIConst(); break;
- case EbtBool: out << constUnion->getBConst(); break;
- default: UNREACHABLE();
- }
-
- if (i != size - 1)
- {
- out << ", ";
- }
- }
-
- if (writeType)
- {
- out << ")";
- }
- }
-
- return constUnion;
-}
-
-TString OutputHLSL::scopeString(unsigned int depthLimit)
-{
- TString string;
-
- for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
- {
- string += "_" + str(i);
- }
-
- return string;
-}
-
-TString OutputHLSL::scopedStruct(const TString &typeName)
-{
- if (typeName == "")
- {
- return typeName;
- }
-
- return typeName + scopeString(mScopeDepth);
-}
-
-TString OutputHLSL::structLookup(const TString &typeName)
-{
- for (int depth = mScopeDepth; depth >= 0; depth--)
- {
- TString scopedName = decorate(typeName + scopeString(depth));
-
- for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
- {
- if (*structName == scopedName)
- {
- return scopedName;
- }
- }
- }
-
- UNREACHABLE(); // Should have found a matching constructor
-
- return typeName;
-}
-
-TString OutputHLSL::decorate(const TString &string)
-{
- if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
- {
- return "_" + string;
- }
-
- return string;
-}
-
-TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
-{
- if (type.getBasicType() == EbtSamplerExternalOES)
- {
- return "ex_" + string;
- }
-
- return decorate(string);
-}
-
-TString OutputHLSL::decorateField(const TString &string, const TType &structure)
-{
- if (structure.getStruct()->name().compare(0, 3, "gl_") != 0)
- {
- return decorate(string);
- }
-
- return string;
-}
-
-TString OutputHLSL::registerString(TIntermSymbol *operand)
-{
- ASSERT(operand->getQualifier() == EvqUniform);
-
- if (IsSampler(operand->getBasicType()))
- {
- return "s" + str(samplerRegister(operand));
- }
-
- return "c" + str(uniformRegister(operand));
-}
-
-int OutputHLSL::samplerRegister(TIntermSymbol *sampler)
-{
- const TType &type = sampler->getType();
- ASSERT(IsSampler(type.getBasicType()));
-
- int index = mSamplerRegister;
- mSamplerRegister += sampler->totalRegisterCount();
-
- declareUniform(type, sampler->getSymbol(), index);
-
- return index;
-}
-
-int OutputHLSL::uniformRegister(TIntermSymbol *uniform)
-{
- const TType &type = uniform->getType();
- ASSERT(!IsSampler(type.getBasicType()));
-
- int index = mUniformRegister;
- mUniformRegister += uniform->totalRegisterCount();
-
- declareUniform(type, uniform->getSymbol(), index);
-
- return index;
-}
-
-void OutputHLSL::declareUniform(const TType &type, const TString &name, int index)
-{
- TStructure *structure = type.getStruct();
-
- if (!structure)
- {
- mActiveUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));
- }
- else
- {
- const TFieldList &fields = structure->fields();
-
- if (type.isArray())
- {
- int elementIndex = index;
-
- for (int i = 0; i < type.getArraySize(); i++)
- {
- for (size_t j = 0; j < fields.size(); j++)
- {
- const TType &fieldType = *fields[j]->type();
- const TString uniformName = name + "[" + str(i) + "]." + fields[j]->name();
- declareUniform(fieldType, uniformName, elementIndex);
- elementIndex += fieldType.totalRegisterCount();
- }
- }
- }
- else
- {
- int fieldIndex = index;
-
- for (size_t i = 0; i < fields.size(); i++)
- {
- const TType &fieldType = *fields[i]->type();
- const TString uniformName = name + "." + fields[i]->name();
- declareUniform(fieldType, uniformName, fieldIndex);
- fieldIndex += fieldType.totalRegisterCount();
- }
- }
- }
-}
-
-GLenum OutputHLSL::glVariableType(const TType &type)
-{
- if (type.getBasicType() == EbtFloat)
- {
- if (type.isScalar())
- {
- return GL_FLOAT;
- }
- else 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();
- }
- }
- else if (type.isMatrix())
- {
- switch(type.getNominalSize())
- {
- case 2: return GL_FLOAT_MAT2;
- case 3: return GL_FLOAT_MAT3;
- case 4: return GL_FLOAT_MAT4;
- default: UNREACHABLE();
- }
- }
- else UNREACHABLE();
- }
- else if (type.getBasicType() == EbtInt)
- {
- if (type.isScalar())
- {
- return GL_INT;
- }
- else 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();
- }
- }
- else UNREACHABLE();
- }
- else if (type.getBasicType() == EbtBool)
- {
- if (type.isScalar())
- {
- return GL_BOOL;
- }
- else 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();
- }
- }
- else UNREACHABLE();
- }
- else if (type.getBasicType() == EbtSampler2D)
- {
- return GL_SAMPLER_2D;
- }
- else if (type.getBasicType() == EbtSamplerCube)
- {
- return GL_SAMPLER_CUBE;
- }
- else UNREACHABLE();
-
- return GL_NONE;
-}
-
-GLenum OutputHLSL::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:
- // Should be defined as the default precision by the parser
- default: UNREACHABLE();
- }
- }
- else if (type.getBasicType() == EbtInt)
- {
- switch (type.getPrecision())
- {
- case EbpHigh: return GL_HIGH_INT;
- case EbpMedium: return GL_MEDIUM_INT;
- case EbpLow: return GL_LOW_INT;
- case EbpUndefined:
- // Should be defined as the default precision by the parser
- default: UNREACHABLE();
- }
- }
-
- // Other types (boolean, sampler) don't have a precision
- return GL_NONE;
-}
-
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h
deleted file mode 100644
index 586a76fb9..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-// 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_OUTPUTHLSL_H_
-#define COMPILER_OUTPUTHLSL_H_
-
-#include <list>
-#include <set>
-#include <map>
-
-#define GL_APICALL
-#include <GLES2/gl2.h>
-
-#include "compiler/intermediate.h"
-#include "compiler/ParseContext.h"
-#include "compiler/Uniform.h"
-
-namespace sh
-{
-class UnfoldShortCircuit;
-
-class OutputHLSL : public TIntermTraverser
-{
- public:
- OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType);
- ~OutputHLSL();
-
- void output();
-
- TInfoSinkBase &getBodyStream();
- const ActiveUniforms &getUniforms();
-
- TString typeString(const TType &type);
- TString textureString(const TType &type);
- static TString qualifierString(TQualifier qualifier);
- static TString arrayString(const TType &type);
- static TString initializer(const TType &type);
- static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes
- static TString decorateUniform(const TString &string, const TType &type);
- static TString decorateField(const TString &string, const TType &structure);
-
- protected:
- void header();
-
- // Visit AST nodes and output their code to the body stream
- void visitSymbol(TIntermSymbol*);
- void visitConstantUnion(TIntermConstantUnion*);
- bool visitBinary(Visit visit, TIntermBinary*);
- bool visitUnary(Visit visit, TIntermUnary*);
- bool visitSelection(Visit visit, TIntermSelection*);
- bool visitAggregate(Visit visit, TIntermAggregate*);
- bool visitLoop(Visit visit, TIntermLoop*);
- bool visitBranch(Visit visit, TIntermBranch*);
-
- void traverseStatements(TIntermNode *node);
- bool isSingleStatement(TIntermNode *node);
- bool handleExcessiveLoop(TIntermLoop *node);
- void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString);
- void outputLineDirective(int line);
- TString argumentString(const TIntermSymbol *symbol);
- int vectorSize(const TType &type) const;
-
- void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
- const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
-
- TString scopeString(unsigned int depthLimit);
- TString scopedStruct(const TString &typeName);
- TString structLookup(const TString &typeName);
-
- TParseContext &mContext;
- const ShShaderOutput mOutputType;
- UnfoldShortCircuit *mUnfoldShortCircuit;
- bool mInsideFunction;
-
- // Output streams
- TInfoSinkBase mHeader;
- TInfoSinkBase mBody;
- TInfoSinkBase mFooter;
-
- typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
- ReferencedSymbols mReferencedUniforms;
- ReferencedSymbols mReferencedAttributes;
- ReferencedSymbols mReferencedVaryings;
-
- // Parameters determining what goes in the header output
- bool mUsesTexture2D;
- bool mUsesTexture2D_bias;
- bool mUsesTexture2DLod;
- bool mUsesTexture2DProj;
- bool mUsesTexture2DProj_bias;
- bool mUsesTexture2DProjLod;
- bool mUsesTextureCube;
- bool mUsesTextureCube_bias;
- bool mUsesTextureCubeLod;
- bool mUsesTexture2DLod0;
- bool mUsesTexture2DLod0_bias;
- bool mUsesTexture2DProjLod0;
- bool mUsesTexture2DProjLod0_bias;
- bool mUsesTextureCubeLod0;
- bool mUsesTextureCubeLod0_bias;
- bool mUsesFragColor;
- bool mUsesFragData;
- bool mUsesDepthRange;
- bool mUsesFragCoord;
- bool mUsesPointCoord;
- bool mUsesFrontFacing;
- bool mUsesPointSize;
- bool mUsesFragDepth;
- bool mUsesXor;
- bool mUsesMod1;
- bool mUsesMod2v;
- bool mUsesMod2f;
- bool mUsesMod3v;
- bool mUsesMod3f;
- bool mUsesMod4v;
- bool mUsesMod4f;
- bool mUsesFaceforward1;
- bool mUsesFaceforward2;
- bool mUsesFaceforward3;
- bool mUsesFaceforward4;
- bool mUsesAtan2_1;
- bool mUsesAtan2_2;
- bool mUsesAtan2_3;
- bool mUsesAtan2_4;
- bool mUsesDiscardRewriting;
-
- int mNumRenderTargets;
-
- typedef std::set<TString> Constructors;
- Constructors mConstructors;
-
- typedef std::set<TString> StructNames;
- StructNames mStructNames;
-
- typedef std::list<TString> StructDeclarations;
- StructDeclarations mStructDeclarations;
-
- typedef std::vector<int> ScopeBracket;
- ScopeBracket mScopeBracket;
- unsigned int mScopeDepth;
-
- int mUniqueIndex; // For creating unique names
-
- bool mContainsLoopDiscontinuity;
- bool mOutputLod0Function;
- bool mInsideDiscontinuousLoop;
-
- TIntermSymbol *mExcessiveLoopIndex;
-
- int mUniformRegister;
- int mSamplerRegister;
-
- TString registerString(TIntermSymbol *operand);
- int samplerRegister(TIntermSymbol *sampler);
- int uniformRegister(TIntermSymbol *uniform);
- void declareUniform(const TType &type, const TString &name, int index);
- static GLenum glVariableType(const TType &type);
- static GLenum glVariablePrecision(const TType &type);
-
- ActiveUniforms mActiveUniforms;
-};
-}
-
-#endif // COMPILER_OUTPUTHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ParseContext.cpp b/Source/ThirdParty/ANGLE/src/compiler/ParseContext.cpp
deleted file mode 100644
index 9a279523b..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ParseContext.cpp
+++ /dev/null
@@ -1,1602 +0,0 @@
-//
-// 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/ParseContext.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "compiler/glslang.h"
-#include "compiler/preprocessor/SourceLocation.h"
-
-///////////////////////////////////////////////////////////////////////
-//
-// Sub- vector and matrix fields
-//
-////////////////////////////////////////////////////////////////////////
-
-//
-// Look at a '.' field selector string and change it into offsets
-// for a vector.
-//
-bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
-{
- fields.num = (int) compString.size();
- if (fields.num > 4) {
- error(line, "illegal vector field selection", compString.c_str());
- return false;
- }
-
- enum {
- exyzw,
- ergba,
- estpq
- } fieldSet[4];
-
- for (int i = 0; i < fields.num; ++i) {
- switch (compString[i]) {
- case 'x':
- fields.offsets[i] = 0;
- fieldSet[i] = exyzw;
- break;
- case 'r':
- fields.offsets[i] = 0;
- fieldSet[i] = ergba;
- break;
- case 's':
- fields.offsets[i] = 0;
- fieldSet[i] = estpq;
- break;
- case 'y':
- fields.offsets[i] = 1;
- fieldSet[i] = exyzw;
- break;
- case 'g':
- fields.offsets[i] = 1;
- fieldSet[i] = ergba;
- break;
- case 't':
- fields.offsets[i] = 1;
- fieldSet[i] = estpq;
- break;
- case 'z':
- fields.offsets[i] = 2;
- fieldSet[i] = exyzw;
- break;
- case 'b':
- fields.offsets[i] = 2;
- fieldSet[i] = ergba;
- break;
- case 'p':
- fields.offsets[i] = 2;
- fieldSet[i] = estpq;
- break;
-
- case 'w':
- fields.offsets[i] = 3;
- fieldSet[i] = exyzw;
- break;
- case 'a':
- fields.offsets[i] = 3;
- fieldSet[i] = ergba;
- break;
- case 'q':
- fields.offsets[i] = 3;
- fieldSet[i] = estpq;
- break;
- default:
- error(line, "illegal vector field selection", compString.c_str());
- return false;
- }
- }
-
- for (int i = 0; i < fields.num; ++i) {
- if (fields.offsets[i] >= vecSize) {
- error(line, "vector field selection out of range", compString.c_str());
- return false;
- }
-
- if (i > 0) {
- if (fieldSet[i] != fieldSet[i-1]) {
- error(line, "illegal - vector component fields not from the same set", compString.c_str());
- return false;
- }
- }
- }
-
- return true;
-}
-
-
-//
-// Look at a '.' field selector string and change it into offsets
-// for a matrix.
-//
-bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, const TSourceLoc& line)
-{
- fields.wholeRow = false;
- fields.wholeCol = false;
- fields.row = -1;
- fields.col = -1;
-
- if (compString.size() != 2) {
- error(line, "illegal length of matrix field selection", compString.c_str());
- return false;
- }
-
- if (compString[0] == '_') {
- if (compString[1] < '0' || compString[1] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.wholeCol = true;
- fields.col = compString[1] - '0';
- } else if (compString[1] == '_') {
- if (compString[0] < '0' || compString[0] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.wholeRow = true;
- fields.row = compString[0] - '0';
- } else {
- if (compString[0] < '0' || compString[0] > '3' ||
- compString[1] < '0' || compString[1] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.row = compString[0] - '0';
- fields.col = compString[1] - '0';
- }
-
- if (fields.row >= matSize || fields.col >= matSize) {
- error(line, "matrix field selection out of range", compString.c_str());
- return false;
- }
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////
-//
-// Errors
-//
-////////////////////////////////////////////////////////////////////////
-
-//
-// Track whether errors have occurred.
-//
-void TParseContext::recover()
-{
-}
-
-//
-// Used by flex/bison to output all syntax and parsing errors.
-//
-void TParseContext::error(const TSourceLoc& loc,
- const char* reason, const char* token,
- const char* extraInfo)
-{
- pp::SourceLocation srcLoc;
- srcLoc.file = loc.first_file;
- srcLoc.line = loc.first_line;
- diagnostics.writeInfo(pp::Diagnostics::ERROR,
- srcLoc, reason, token, extraInfo);
-
-}
-
-void TParseContext::warning(const TSourceLoc& loc,
- const char* reason, const char* token,
- const char* extraInfo) {
- pp::SourceLocation srcLoc;
- srcLoc.file = loc.first_file;
- srcLoc.line = loc.first_line;
- diagnostics.writeInfo(pp::Diagnostics::WARNING,
- srcLoc, reason, token, extraInfo);
-}
-
-void TParseContext::trace(const char* str)
-{
- diagnostics.writeDebug(str);
-}
-
-//
-// Same error message for all places assignments don't work.
-//
-void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
-{
- std::stringstream extraInfoStream;
- extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, "", op, extraInfo.c_str());
-}
-
-//
-// Same error message for all places unary operations don't work.
-//
-void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
-{
- std::stringstream extraInfoStream;
- extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
- << " (or there is no acceptable conversion)";
- std::string extraInfo = extraInfoStream.str();
- error(line, " wrong operand type", op, extraInfo.c_str());
-}
-
-//
-// Same error message for all binary operations don't work.
-//
-void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
-{
- std::stringstream extraInfoStream;
- extraInfoStream << "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)";
- std::string extraInfo = extraInfoStream.str();
- error(line, " wrong operand types ", op, extraInfo.c_str());
-}
-
-bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
- if (!checksPrecisionErrors)
- return false;
- switch( type ){
- case EbtFloat:
- if( precision == EbpUndefined ){
- error( line, "No precision specified for (float)", "" );
- return true;
- }
- break;
- case EbtInt:
- if( precision == EbpUndefined ){
- error( line, "No precision specified (int)", "" );
- return true;
- }
- break;
- default:
- return false;
- }
- return false;
-}
-
-//
-// 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.
-//
-// Returns true if the was an error.
-//
-bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
-{
- TIntermSymbol* symNode = node->getAsSymbolNode();
- TIntermBinary* binaryNode = node->getAsBinaryNode();
-
- if (binaryNode) {
- bool errorReturn;
-
- switch(binaryNode->getOp()) {
- case EOpIndexDirect:
- case EOpIndexIndirect:
- case EOpIndexDirectStruct:
- return lValueErrorCheck(line, op, binaryNode->getLeft());
- case EOpVectorSwizzle:
- errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
- if (!errorReturn) {
- int offset[4] = {0,0,0,0};
-
- TIntermTyped* rightNode = binaryNode->getRight();
- TIntermAggregate *aggrNode = rightNode->getAsAggregate();
-
- for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
- p != aggrNode->getSequence().end(); p++) {
- int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
- offset[value]++;
- if (offset[value] > 1) {
- error(line, " l-value of swizzle cannot have duplicate components", op);
-
- return true;
- }
- }
- }
-
- return errorReturn;
- default:
- break;
- }
- error(line, " l-value required", op);
-
- return true;
- }
-
-
- const char* symbol = 0;
- if (symNode != 0)
- symbol = symNode->getSymbol().c_str();
-
- const char* message = 0;
- 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 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;
- default:
-
- //
- // Type that can't be written to?
- //
- switch (node->getBasicType()) {
- case EbtSampler2D:
- case EbtSamplerCube:
- message = "can't modify a sampler";
- break;
- case EbtVoid:
- message = "can't modify void";
- break;
- default:
- break;
- }
- }
-
- if (message == 0 && binaryNode == 0 && symNode == 0) {
- error(line, " l-value required", op);
-
- return true;
- }
-
-
- //
- // Everything else is okay, no error.
- //
- if (message == 0)
- return false;
-
- //
- // If we get here, we have an error and a message.
- //
- if (symNode) {
- std::stringstream extraInfoStream;
- extraInfoStream << "\"" << symbol << "\" (" << message << ")";
- std::string extraInfo = extraInfoStream.str();
- error(line, " l-value required", op, extraInfo.c_str());
- }
- else {
- std::stringstream extraInfoStream;
- extraInfoStream << "(" << message << ")";
- std::string extraInfo = extraInfoStream.str();
- error(line, " l-value required", op, extraInfo.c_str());
- }
-
- return true;
-}
-
-//
-// Both test, and if necessary spit out an error, to see if the node is really
-// a constant.
-//
-// Returns true if the was an error.
-//
-bool TParseContext::constErrorCheck(TIntermTyped* node)
-{
- if (node->getQualifier() == EvqConst)
- return false;
-
- error(node->getLine(), "constant expression required", "");
-
- return true;
-}
-
-//
-// Both test, and if necessary spit out an error, to see if the node is really
-// an integer.
-//
-// Returns true if the was an error.
-//
-bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
-{
- if (node->getBasicType() == EbtInt && node->getNominalSize() == 1)
- return false;
-
- error(node->getLine(), "integer expression required", token);
-
- return true;
-}
-
-//
-// Both test, and if necessary spit out an error, to see if we are currently
-// globally scoped.
-//
-// Returns true if the was an error.
-//
-bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
-{
- if (global)
- return false;
-
- error(line, "only allowed at global scope", token);
-
- return true;
-}
-
-//
-// For now, keep it simple: if it starts "gl_", it's reserved, independent
-// of scope. Except, if the symbol table is at the built-in push-level,
-// which is when we are parsing built-ins.
-// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
-// webgl shader.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
-{
- static const char* reservedErrMsg = "reserved built-in name";
- if (!symbolTable.atBuiltInLevel()) {
- if (identifier.compare(0, 3, "gl_") == 0) {
- error(line, reservedErrMsg, "gl_");
- return true;
- }
- if (isWebGLBasedSpec(shaderSpec)) {
- if (identifier.compare(0, 6, "webgl_") == 0) {
- error(line, reservedErrMsg, "webgl_");
- return true;
- }
- if (identifier.compare(0, 7, "_webgl_") == 0) {
- error(line, reservedErrMsg, "_webgl_");
- return true;
- }
- if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
- error(line, reservedErrMsg, "css_");
- return true;
- }
- }
- if (identifier.find("__") != TString::npos) {
- error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
- return true;
- }
- }
-
- return false;
-}
-
-//
-// Make sure there is enough data provided to the constructor to build
-// something of the type of the constructor. Also returns the type of
-// the constructor.
-//
-// Returns true if there was an error in construction.
-//
-bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
-{
- *type = function.getReturnType();
-
- bool constructingMatrix = false;
- switch(op) {
- case EOpConstructMat2:
- case EOpConstructMat3:
- case EOpConstructMat4:
- constructingMatrix = true;
- break;
- default:
- break;
- }
-
- //
- // 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 constType = true;
- bool full = false;
- bool overFull = false;
- bool matrixInMatrix = false;
- bool arrayArg = false;
- for (size_t i = 0; i < function.getParamCount(); ++i) {
- const TParameter& param = function.getParam(i);
- size += param.type->getObjectSize();
-
- if (constructingMatrix && param.type->isMatrix())
- matrixInMatrix = true;
- if (full)
- overFull = true;
- if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
- full = true;
- if (param.type->getQualifier() != EvqConst)
- constType = false;
- if (param.type->isArray())
- arrayArg = true;
- }
-
- if (constType)
- type->setQualifier(EvqConst);
-
- if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
- error(line, "array constructor needs one argument per array element", "constructor");
- return true;
- }
-
- if (arrayArg && op != EOpConstructStruct) {
- error(line, "constructing from a non-dereferenced array", "constructor");
- return true;
- }
-
- if (matrixInMatrix && !type->isArray()) {
- if (function.getParamCount() != 1) {
- error(line, "constructing matrix from matrix can only take one argument", "constructor");
- return true;
- }
- }
-
- if (overFull) {
- error(line, "too many arguments", "constructor");
- return true;
- }
-
- if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->fields().size()) != function.getParamCount()) {
- error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
- return true;
- }
-
- if (!type->isMatrix() || !matrixInMatrix) {
- if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
- (op == EOpConstructStruct && size < type->getObjectSize())) {
- error(line, "not enough data provided for construction", "constructor");
- return true;
- }
- }
-
- TIntermTyped *typed = node ? node->getAsTyped() : 0;
- if (typed == 0) {
- error(line, "constructor argument does not have a type", "constructor");
- return true;
- }
- if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
- error(line, "cannot convert a sampler", "constructor");
- return true;
- }
- if (typed->getBasicType() == EbtVoid) {
- error(line, "cannot convert a void", "constructor");
- return true;
- }
-
- return false;
-}
-
-// 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::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType)
-{
- if (pubType.type == EbtVoid) {
- error(line, "illegal use of type 'void'", identifier.c_str());
- return true;
- }
-
- return false;
-}
-
-// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
-//
-// returns true in case of an error
-//
-bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
-{
- if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
- error(line, "boolean expression expected", "");
- return true;
- }
-
- return false;
-}
-
-// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
-//
-// returns true in case of an error
-//
-bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
-{
- if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
- error(line, "boolean expression expected", "");
- return true;
- }
-
- return false;
-}
-
-bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
-{
- if (pType.type == EbtStruct) {
- if (containsSampler(*pType.userDef)) {
- error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
-
- return true;
- }
-
- return false;
- } else if (IsSampler(pType.type)) {
- error(line, reason, getBasicString(pType.type));
-
- return true;
- }
-
- return false;
-}
-
-bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
-{
- if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
- pType.type == EbtStruct) {
- error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
-
- return true;
- }
-
- if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
- return true;
-
- return false;
-}
-
-bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
-{
- if ((qualifier == EvqOut || qualifier == EvqInOut) &&
- type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
- error(line, "samplers cannot be output parameters", type.getBasicString());
- return true;
- }
-
- return false;
-}
-
-bool TParseContext::containsSampler(TType& type)
-{
- if (IsSampler(type.getBasicType()))
- return true;
-
- if (type.getBasicType() == EbtStruct) {
- const TFieldList& fields = type.getStruct()->fields();
- for (unsigned int i = 0; i < fields.size(); ++i) {
- if (containsSampler(*fields[i]->type()))
- return true;
- }
- }
-
- return false;
-}
-
-//
-// Do size checking for an array type's size.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
-{
- TIntermConstantUnion* constant = expr->getAsConstantUnion();
- if (constant == 0 || constant->getBasicType() != EbtInt) {
- error(line, "array size must be a constant integer expression", "");
- return true;
- }
-
- size = constant->getIConst(0);
-
- if (size <= 0) {
- error(line, "array size must be a positive integer", "");
- size = 1;
- return true;
- }
-
- return false;
-}
-
-//
-// See if this qualifier can be an array.
-//
-// Returns true if there is an error.
-//
-bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type)
-{
- if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) {
- error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
- return true;
- }
-
- return false;
-}
-
-//
-// See if this type can be an array.
-//
-// Returns true if there is an error.
-//
-bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
-{
- //
- // Can the type be an array?
- //
- if (type.array) {
- error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
- return true;
- }
-
- return false;
-}
-
-//
-// Do all the semantic checking for declaring an array, with and
-// without a size, and make the right changes to the symbol table.
-//
-// size == 0 means no specified size.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable)
-{
- //
- // Don't check for reserved word use until after we know it's not in the symbol table,
- // because reserved arrays can be redeclared.
- //
-
- bool builtIn = false;
- bool sameScope = false;
- TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
- if (symbol == 0 || !sameScope) {
- if (reservedErrorCheck(line, identifier))
- return true;
-
- variable = new TVariable(&identifier, TType(type));
-
- if (type.arraySize)
- variable->getType().setArraySize(type.arraySize);
-
- if (! symbolTable.insert(*variable)) {
- delete variable;
- error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
- return true;
- }
- } else {
- if (! symbol->isVariable()) {
- error(line, "variable expected", identifier.c_str());
- return true;
- }
-
- variable = static_cast<TVariable*>(symbol);
- if (! variable->getType().isArray()) {
- error(line, "redeclaring non-array as array", identifier.c_str());
- return true;
- }
- if (variable->getType().getArraySize() > 0) {
- error(line, "redeclaration of array with size", identifier.c_str());
- return true;
- }
-
- if (! variable->getType().sameElementType(TType(type))) {
- error(line, "redeclaration of array with a different type", identifier.c_str());
- return true;
- }
-
- if (type.arraySize)
- variable->getType().setArraySize(type.arraySize);
- }
-
- if (voidErrorCheck(line, identifier, type))
- return true;
-
- return false;
-}
-
-//
-// Enforce non-initializer type/qualifier rules.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array)
-{
- if (type.qualifier == EvqConst)
- {
- // Make the qualifier make sense.
- type.qualifier = EvqTemporary;
-
- if (array)
- {
- error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
- }
- else if (type.isStructureContainingArrays())
- {
- error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
- }
- else
- {
- error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
- }
-
- return true;
- }
-
- return false;
-}
-
-//
-// Do semantic checking for a variable declaration that has no initializer,
-// and update the symbol table.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable)
-{
- if (reservedErrorCheck(line, identifier))
- recover();
-
- variable = new TVariable(&identifier, TType(type));
-
- if (! symbolTable.insert(*variable)) {
- error(line, "redefinition", variable->getName().c_str());
- delete variable;
- variable = 0;
- return true;
- }
-
- if (voidErrorCheck(line, identifier, type))
- return true;
-
- return false;
-}
-
-bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
-{
- if (qualifier != EvqConst && qualifier != EvqTemporary) {
- error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
- return true;
- }
- if (qualifier == EvqConst && paramQualifier != EvqIn) {
- error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
- return true;
- }
-
- if (qualifier == EvqConst)
- type->setQualifier(EvqConstReadOnly);
- else
- type->setQualifier(paramQualifier);
-
- return false;
-}
-
-bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
-{
- const TExtensionBehavior& extBehavior = extensionBehavior();
- TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
- if (iter == extBehavior.end()) {
- error(line, "extension", extension.c_str(), "is not supported");
- return true;
- }
- // In GLSL ES, an extension's default behavior is "disable".
- if (iter->second == EBhDisable || iter->second == EBhUndefined) {
- error(line, "extension", extension.c_str(), "is disabled");
- return true;
- }
- if (iter->second == EBhWarn) {
- warning(line, "extension", extension.c_str(), "is being used");
- return false;
- }
-
- return false;
-}
-
-bool TParseContext::supportsExtension(const char* extension)
-{
- const TExtensionBehavior& extbehavior = extensionBehavior();
- TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
- return (iter != extbehavior.end());
-}
-
-bool TParseContext::isExtensionEnabled(const char* extension) const
-{
- const TExtensionBehavior& extbehavior = extensionBehavior();
- TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
-
- if (iter == extbehavior.end())
- {
- return false;
- }
-
- return (iter->second == EBhEnable || iter->second == EBhRequire);
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-//
-// Non-Errors.
-//
-/////////////////////////////////////////////////////////////////////////////////
-
-//
-// Look up a function name in the symbol table, and make sure it is a function.
-//
-// Return the function symbol if found, otherwise 0.
-//
-const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, bool *builtIn)
-{
- // First find by unmangled name to check whether the function name has been
- // hidden by a variable name or struct typename.
- // If a function is found, check for one with a matching argument list.
- const TSymbol* symbol = symbolTable.find(call->getName(), builtIn);
- if (symbol == 0 || symbol->isFunction()) {
- symbol = symbolTable.find(call->getMangledName(), builtIn);
- }
-
- if (symbol == 0) {
- error(line, "no matching overloaded function found", call->getName().c_str());
- return 0;
- }
-
- if (!symbol->isFunction()) {
- error(line, "function name expected", call->getName().c_str());
- return 0;
- }
-
- return static_cast<const TFunction*>(symbol);
-}
-
-//
-// Initializers show up in several places in the grammar. Have one set of
-// code to handle them here.
-//
-bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType,
- TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
-{
- TType type = TType(pType);
-
- if (variable == 0) {
- if (reservedErrorCheck(line, identifier))
- return true;
-
- if (voidErrorCheck(line, identifier, pType))
- return true;
-
- //
- // add variable to symbol table
- //
- variable = new TVariable(&identifier, type);
- if (! symbolTable.insert(*variable)) {
- error(line, "redefinition", variable->getName().c_str());
- return true;
- // don't delete variable, it's used by error recovery, and the pool
- // pop will take care of the memory
- }
- }
-
- //
- // identifier must be of type constant, a global, or a temporary
- //
- TQualifier qualifier = variable->getType().getQualifier();
- if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
- error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
- return true;
- }
- //
- // test for and propagate constant
- //
-
- if (qualifier == EvqConst) {
- if (qualifier != initializer->getType().getQualifier()) {
- std::stringstream extraInfoStream;
- extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, " assigning non-constant to", "=", extraInfo.c_str());
- variable->getType().setQualifier(EvqTemporary);
- return true;
- }
- if (type != initializer->getType()) {
- error(line, " non-matching types for const initializer ",
- variable->getType().getQualifierString());
- variable->getType().setQualifier(EvqTemporary);
- return true;
- }
- if (initializer->getAsConstantUnion()) {
- variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
- } else if (initializer->getAsSymbolNode()) {
- const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
- const TVariable* tVar = static_cast<const TVariable*>(symbol);
-
- ConstantUnion* constArray = tVar->getConstPointer();
- variable->shareConstPointer(constArray);
- } else {
- std::stringstream extraInfoStream;
- extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, " cannot assign to", "=", extraInfo.c_str());
- variable->getType().setQualifier(EvqTemporary);
- return true;
- }
- }
-
- if (qualifier != EvqConst) {
- TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
- intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
- if (intermNode == 0) {
- assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
- return true;
- }
- } else
- intermNode = 0;
-
- return false;
-}
-
-bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
-{
- ASSERT(aggrNode != NULL);
- if (!aggrNode->isConstructor())
- return false;
-
- bool allConstant = true;
-
- // check if all the child nodes are constants so that they can be inserted into
- // the parent node
- TIntermSequence &sequence = aggrNode->getSequence() ;
- for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
- if (!(*p)->getAsTyped()->getAsConstantUnion())
- return false;
- }
-
- return allConstant;
-}
-
-// 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 0 for an error or the constructed node (aggregate or typed) for no error.
-//
-TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line)
-{
- if (node == 0)
- return 0;
-
- TIntermAggregate* aggrNode = node->getAsAggregate();
-
- TFieldList::const_iterator memberFields;
- if (op == EOpConstructStruct)
- memberFields = type->getStruct()->fields().begin();
-
- TType elementType = *type;
- if (type->isArray())
- elementType.clearArrayness();
-
- bool singleArg;
- if (aggrNode) {
- if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
- singleArg = true;
- else
- singleArg = false;
- } else
- singleArg = true;
-
- TIntermTyped *newNode;
- if (singleArg) {
- // If structure constructor or array constructor is being called
- // for only one parameter inside the structure, we need to call constructStruct function once.
- if (type->isArray())
- newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
- else if (op == EOpConstructStruct)
- newNode = constructStruct(node, (*memberFields)->type(), 1, node->getLine(), false);
- else
- newNode = constructBuiltIn(type, op, node, node->getLine(), false);
-
- if (newNode && newNode->getAsAggregate()) {
- TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
- if (constConstructor)
- return constConstructor;
- }
-
- return newNode;
- }
-
- //
- // Handle list of arguments.
- //
- TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
- // if the structure constructor contains more than one parameter, then construct
- // each parameter
-
- int paramCount = 0; // keeps a track of the constructor parameter number being checked
-
- // for each parameter to the constructor call, check to see if the right type is passed or convert them
- // to the right type if possible (and allowed).
- // for structure constructors, just check if the right type is passed, no conversion is allowed.
-
- for (TIntermSequence::iterator p = sequenceVector.begin();
- p != sequenceVector.end(); p++, paramCount++) {
- if (type->isArray())
- newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
- else if (op == EOpConstructStruct)
- newNode = constructStruct(*p, memberFields[paramCount]->type(), paramCount+1, node->getLine(), true);
- else
- newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
-
- if (newNode) {
- *p = newNode;
- }
- }
-
- TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
- TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
- if (constConstructor)
- return constConstructor;
-
- return constructor;
-}
-
-TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
-{
- bool canBeFolded = areAllChildConst(aggrNode);
- aggrNode->setType(type);
- if (canBeFolded) {
- bool returnVal = false;
- ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
- if (aggrNode->getSequence().size() == 1) {
- returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
- }
- else {
- returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
- }
- if (returnVal)
- return 0;
-
- return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
- }
-
- return 0;
-}
-
-// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
-// for the parameter to the constructor (passed to this function). Essentially, it converts
-// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
-// float, then float is converted to int.
-//
-// Returns 0 for an error or the constructed node.
-//
-TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset)
-{
- TIntermTyped* newNode;
- TOperator basicOp;
-
- //
- // First, convert types as needed.
- //
- switch (op) {
- case EOpConstructVec2:
- case EOpConstructVec3:
- case EOpConstructVec4:
- case EOpConstructMat2:
- case EOpConstructMat3:
- case EOpConstructMat4:
- case EOpConstructFloat:
- basicOp = EOpConstructFloat;
- break;
-
- case EOpConstructIVec2:
- case EOpConstructIVec3:
- case EOpConstructIVec4:
- case EOpConstructInt:
- basicOp = EOpConstructInt;
- break;
-
- case EOpConstructBVec2:
- case EOpConstructBVec3:
- case EOpConstructBVec4:
- case EOpConstructBool:
- basicOp = EOpConstructBool;
- break;
-
- default:
- error(line, "unsupported construction", "");
- recover();
-
- return 0;
- }
- newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
- if (newNode == 0) {
- error(line, "can't convert", "constructor");
- return 0;
- }
-
- //
- // Now, if there still isn't an operation to do the construction, and we need one, add one.
- //
-
- // Otherwise, skip out early.
- if (subset || (newNode != node && newNode->getType() == *type))
- return newNode;
-
- // setAggregateOperator will insert a new node for the constructor, as needed.
- return intermediate.setAggregateOperator(newNode, op, line);
-}
-
-// This function tests for the type of the parameters to the structures constructors. Raises
-// an error message if the expected type does not match the parameter passed to the constructor.
-//
-// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
-//
-TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset)
-{
- if (*type == node->getAsTyped()->getType()) {
- if (subset)
- return node->getAsTyped();
- else
- return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
- } else {
- std::stringstream extraInfoStream;
- extraInfoStream << "cannot convert parameter " << paramCount
- << " from '" << node->getAsTyped()->getType().getBasicString()
- << "' to '" << type->getBasicString() << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, "", "constructor", extraInfo.c_str());
- recover();
- }
-
- return 0;
-}
-
-//
-// This function returns the tree representation for the vector field(s) being accessed from contant vector.
-// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
-// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
-// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
-// a constant matrix.
-//
-TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
-{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
-
- ConstantUnion *unionArray;
- if (tempConstantNode) {
- unionArray = tempConstantNode->getUnionArrayPointer();
-
- if (!unionArray) {
- return node;
- }
- } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
- error(line, "Cannot offset into the vector", "Error");
- recover();
-
- return 0;
- }
-
- ConstantUnion* constArray = new ConstantUnion[fields.num];
-
- for (int i = 0; i < fields.num; i++) {
- if (fields.offsets[i] >= node->getType().getNominalSize()) {
- std::stringstream extraInfoStream;
- extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- fields.offsets[i] = 0;
- }
-
- constArray[i] = unionArray[fields.offsets[i]];
-
- }
- typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
- return typedNode;
-}
-
-//
-// This function returns the column being accessed from a constant matrix. The values are retrieved from
-// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
-// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
-// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
-//
-TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
-{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
-
- if (index >= node->getType().getNominalSize()) {
- std::stringstream extraInfoStream;
- extraInfoStream << "matrix field selection out of range '" << index << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- index = 0;
- }
-
- if (tempConstantNode) {
- ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
- int size = tempConstantNode->getType().getNominalSize();
- typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
- } else {
- error(line, "Cannot offset into the matrix", "Error");
- recover();
-
- return 0;
- }
-
- return typedNode;
-}
-
-
-//
-// This function returns an element of an array accessed from a constant array. The values are retrieved from
-// the symbol table and parse-tree is built for the type of the element. The input
-// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
-// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
-//
-TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
-{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
- TType arrayElementType = node->getType();
- arrayElementType.clearArrayness();
-
- if (index >= node->getType().getArraySize()) {
- std::stringstream extraInfoStream;
- extraInfoStream << "array field selection out of range '" << index << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- index = 0;
- }
-
- if (tempConstantNode) {
- size_t arrayElementSize = arrayElementType.getObjectSize();
- ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
- typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
- } else {
- error(line, "Cannot offset into the array", "Error");
- recover();
-
- return 0;
- }
-
- return typedNode;
-}
-
-
-//
-// This function returns the value of a particular field inside a constant structure from the symbol table.
-// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
-// function and returns the parse-tree with the values of the embedded/nested struct.
-//
-TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, const TSourceLoc& line)
-{
- const TFieldList& fields = node->getType().getStruct()->fields();
-
- size_t instanceSize = 0;
- for (size_t index = 0; index < fields.size(); ++index) {
- if (fields[index]->name() == identifier) {
- break;
- } else {
- instanceSize += fields[index]->type()->getObjectSize();
- }
- }
-
- TIntermTyped* typedNode = 0;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
- if (tempConstantNode) {
- ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
-
- typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
- } else {
- error(line, "Cannot offset into the structure", "Error");
- recover();
-
- return 0;
- }
-
- return typedNode;
-}
-
-bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
-{
- ++structNestingLevel;
-
- // Embedded structure definitions are not supported per GLSL ES spec.
- // They aren't allowed in GLSL either, but we need to detect this here
- // so we don't rely on the GLSL compiler to catch it.
- if (structNestingLevel > 1) {
- error(line, "", "Embedded struct definitions are not allowed");
- return true;
- }
-
- return false;
-}
-
-void TParseContext::exitStructDeclaration()
-{
- --structNestingLevel;
-}
-
-namespace {
-
-const int kWebGLMaxStructNesting = 4;
-
-} // namespace
-
-bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
-{
- if (!isWebGLBasedSpec(shaderSpec)) {
- return false;
- }
-
- if (field.type()->getBasicType() != EbtStruct) {
- return false;
- }
-
- // 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;
- reasonStream << "Reference of struct type "
- << field.type()->getStruct()->name().c_str()
- << " exceeds maximum allowed nesting level of "
- << kWebGLMaxStructNesting;
- std::string reason = reasonStream.str();
- error(line, reason.c_str(), field.name().c_str(), "");
- return true;
- }
-
- return false;
-}
-
-//
-// Parse an array index expression
-//
-TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
-{
- TIntermTyped *indexedExpression = NULL;
-
- if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
- {
- if (baseExpression->getAsSymbolNode())
- {
- error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
- }
- else
- {
- error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
- }
- recover();
- }
-
- if (indexExpression->getQualifier() == EvqConst)
- {
- int index = indexExpression->getAsConstantUnion()->getIConst(0);
- if (index < 0)
- {
- std::stringstream infoStream;
- infoStream << index;
- std::string info = infoStream.str();
- error(location, "negative index", info.c_str());
- recover();
- index = 0;
- }
- if (baseExpression->getType().getQualifier() == EvqConst)
- {
- if (baseExpression->isArray())
- {
- // constant folding for arrays
- indexedExpression = addConstArrayNode(index, baseExpression, location);
- }
- else if (baseExpression->isVector())
- {
- // constant folding for vectors
- TVectorFields fields;
- fields.num = 1;
- fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
- indexedExpression = addConstVectorNode(fields, baseExpression, location);
- }
- else if (baseExpression->isMatrix())
- {
- // constant folding for matrices
- indexedExpression = addConstMatrixNode(index, baseExpression, location);
- }
- }
- else
- {
- if (baseExpression->isArray())
- {
- if (index >= baseExpression->getType().getArraySize())
- {
- std::stringstream extraInfoStream;
- extraInfoStream << "array index out of range '" << index << "'";
- std::string extraInfo = extraInfoStream.str();
- error(location, "", "[", extraInfo.c_str());
- recover();
- index = baseExpression->getType().getArraySize() - 1;
- }
- else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
- {
- error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
- recover();
- index = 0;
- }
- }
- else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
- {
- std::stringstream extraInfoStream;
- extraInfoStream << "field selection out of range '" << index << "'";
- std::string extraInfo = extraInfoStream.str();
- error(location, "", "[", extraInfo.c_str());
- recover();
- index = baseExpression->getType().getNominalSize() - 1;
- }
-
- indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index);
- indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
- }
- }
- else
- {
- indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
- }
-
- if (indexedExpression == 0)
- {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setFConst(0.0f);
- indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
- }
- else if (baseExpression->isArray())
- {
- const TType &baseType = baseExpression->getType();
- if (baseType.getStruct())
- {
- TType copyOfType(baseType.getStruct());
- indexedExpression->setType(copyOfType);
- }
- else
- {
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->isMatrix()));
- }
-
- if (baseExpression->getType().getQualifier() == EvqConst)
- {
- indexedExpression->getTypePointer()->setQualifier(EvqConst);
- }
- }
- else if (baseExpression->isMatrix())
- {
- TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getNominalSize()));
- }
- else if (baseExpression->isVector())
- {
- TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
- }
- else
- {
- indexedExpression->setType(baseExpression->getType());
- }
-
- return indexedExpression;
-}
-
-//
-// 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 == NULL))
- 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;
-}
-
-
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ParseContext.h b/Source/ThirdParty/ANGLE/src/compiler/ParseContext.h
deleted file mode 100644
index c2b3c3f7e..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ParseContext.h
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// 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 _PARSER_HELPER_INCLUDED_
-#define _PARSER_HELPER_INCLUDED_
-
-#include "compiler/Diagnostics.h"
-#include "compiler/DirectiveHandler.h"
-#include "compiler/localintermediate.h"
-#include "compiler/preprocessor/Preprocessor.h"
-#include "compiler/ShHandle.h"
-#include "compiler/SymbolTable.h"
-
-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.
-//
-struct TParseContext {
- TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
- intermediate(interm),
- symbolTable(symt),
- shaderType(type),
- shaderSpec(spec),
- compileOptions(options),
- sourcePath(sourcePath),
- treeRoot(0),
- loopNestingLevel(0),
- structNestingLevel(0),
- currentFunctionType(NULL),
- functionReturnsValue(false),
- checksPrecisionErrors(checksPrecErrors),
- diagnostics(is),
- directiveHandler(ext, diagnostics),
- preprocessor(&diagnostics, &directiveHandler),
- scanner(NULL) { }
- TIntermediate& intermediate; // to hold and build a parse tree
- TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
- ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
- ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
- int compileOptions;
- const char* sourcePath; // Path of source file or NULL.
- TIntermNode* treeRoot; // root of parse tree being created
- int loopNestingLevel; // 0 if outside all loops
- int structNestingLevel; // incremented while parsing a struct declaration
- const TType* currentFunctionType; // the return type of the function that's currently being parsed
- bool functionReturnsValue; // true if a non-void function has a return
- bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
- bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
- TString HashErrMsg;
- TDiagnostics diagnostics;
- TDirectiveHandler directiveHandler;
- pp::Preprocessor preprocessor;
- void* scanner;
-
- int numErrors() const { return diagnostics.numErrors(); }
- TInfoSink& infoSink() { return diagnostics.infoSink(); }
- void error(const TSourceLoc& loc, const char *reason, const char* token,
- const char* extraInfo="");
- void warning(const TSourceLoc& loc, const char* reason, const char* token,
- const char* extraInfo="");
- void trace(const char* str);
- void recover();
-
- bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line);
- bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, const TSourceLoc& line);
-
- bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier);
- void assignError(const TSourceLoc& line, const char* op, TString left, TString right);
- void unaryOpError(const TSourceLoc& line, const char* op, TString operand);
- void binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right);
- bool precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type);
- bool lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped*);
- bool constErrorCheck(TIntermTyped* node);
- bool integerErrorCheck(TIntermTyped* node, const char* token);
- bool globalErrorCheck(const TSourceLoc& line, bool global, const char* token);
- bool constructorErrorCheck(const TSourceLoc& line, TIntermNode*, TFunction&, TOperator, TType*);
- bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size);
- bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type);
- bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type);
- bool arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable);
- bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&);
- bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
- bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
- bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason);
- bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType);
- bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type);
- bool nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array);
- bool nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable);
- bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
- bool extensionErrorCheck(const TSourceLoc& line, const TString&);
-
- const TPragma& pragma() const { return directiveHandler.pragma(); }
- const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
- bool supportsExtension(const char* extension);
- bool isExtensionEnabled(const char* extension) const;
-
- bool containsSampler(TType& type);
- bool areAllChildConst(TIntermAggregate* aggrNode);
- const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, bool *builtIn = 0);
- bool executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType,
- TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
-
- TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
- TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
- TIntermTyped* constructStruct(TIntermNode*, TType*, int, const TSourceLoc&, bool subset);
- TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, const TSourceLoc&, bool subset);
- TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line);
- TIntermTyped* addConstStruct(TString& , TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression);
-
- // Performs an error check for embedded struct declarations.
- // Returns true if an error was raised due to the declaration of
- // this struct.
- bool enterStructDeclaration(const TSourceLoc& line, const TString& identifier);
- void exitStructDeclaration();
-
- bool structNestingErrorCheck(const TSourceLoc& line, const TField& field);
-};
-
-int PaParseStrings(size_t count, const char* const string[], const int length[],
- TParseContext* context);
-
-#endif // _PARSER_HELPER_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Pragma.h b/Source/ThirdParty/ANGLE/src/compiler/Pragma.h
deleted file mode 100644
index 2f744123b..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Pragma.h
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// 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_PRAGMA_H_
-#define COMPILER_PRAGMA_H_
-
-struct TPragma {
- // By default optimization is turned on and debug is turned off.
- TPragma() : optimize(true), debug(false) { }
- TPragma(bool o, bool d) : optimize(o), debug(d) { }
-
- bool optimize;
- bool debug;
-};
-
-#endif // COMPILER_PRAGMA_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp
deleted file mode 100644
index 92a6874eb..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// 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/intermediate.h"
-
-class TAliveTraverser : public TIntermTraverser {
-public:
- TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q)
- {
- }
-
- bool wasFound() { return found; }
-
-protected:
- bool found;
- TQualifier qualifier;
-
- void visitSymbol(TIntermSymbol*);
- bool visitSelection(Visit, TIntermSelection*);
-};
-
-//
-// Report whether or not a variable of the given qualifier type
-// is guaranteed written. Not always possible to determine if
-// it is written conditionally.
-//
-// ?? It does not do this well yet, this is just a place holder
-// that simply determines if it was reference at all, anywhere.
-//
-bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
-{
- TAliveTraverser it(qualifier);
-
- if (node)
- node->traverse(&it);
-
- return it.wasFound();
-}
-
-void TAliveTraverser::visitSymbol(TIntermSymbol* node)
-{
- //
- // If it's what we're looking for, record it.
- //
- if (node->getQualifier() == qualifier)
- found = true;
-}
-
-bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node)
-{
- if (wasFound())
- return false;
-
- return true;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h
deleted file mode 100644
index 872a06f72..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h
+++ /dev/null
@@ -1,7 +0,0 @@
-//
-// 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.
-//
-
-bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp
deleted file mode 100644
index a4b8c1e63..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// 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/intermediate.h"
-#include "compiler/RemoveTree.h"
-
-//
-// Code to recursively delete the intermediate tree.
-//
-
-class RemoveTree : public TIntermTraverser
-{
-public:
- RemoveTree() : TIntermTraverser(false, false, true)
- {
- }
-
-protected:
- void visitSymbol(TIntermSymbol*);
- void visitConstantUnion(TIntermConstantUnion*);
- bool visitBinary(Visit visit, TIntermBinary*);
- bool visitUnary(Visit visit, TIntermUnary*);
- bool visitSelection(Visit visit, TIntermSelection*);
- bool visitAggregate(Visit visit, TIntermAggregate*);
-};
-
-void RemoveTree::visitSymbol(TIntermSymbol* node)
-{
- delete node;
-}
-
-bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node)
-{
- delete node;
-
- return true;
-}
-
-bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node)
-{
- delete node;
-
- return true;
-}
-
-bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- delete node;
-
- return true;
-}
-
-bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node)
-{
- delete node;
-
- return true;
-}
-
-void RemoveTree::visitConstantUnion(TIntermConstantUnion* node)
-{
- delete node;
-}
-
-//
-// Entry point.
-//
-void RemoveAllTreeNodes(TIntermNode* root)
-{
- RemoveTree it;
-
- root->traverse(&it);
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h
deleted file mode 100644
index 97a821679..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h
+++ /dev/null
@@ -1,7 +0,0 @@
-//
-// 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.
-//
-
-void RemoveAllTreeNodes(TIntermNode*);
diff --git a/Source/ThirdParty/ANGLE/src/compiler/RenameFunction.h b/Source/ThirdParty/ANGLE/src/compiler/RenameFunction.h
deleted file mode 100644
index 3908bfddb..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/RenameFunction.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// 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_RENAME_FUNCTION
-#define COMPILER_RENAME_FUNCTION
-
-#include "compiler/intermediate.h"
-
-//
-// Renames a function, including its declaration and any calls to it.
-//
-class RenameFunction : public TIntermTraverser
-{
-public:
- RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
- : TIntermTraverser(true, false, false)
- , mOldFunctionName(oldFunctionName)
- , mNewFunctionName(newFunctionName) {}
-
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
- {
- TOperator op = node->getOp();
- if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
- node->setName(mNewFunctionName);
- return true;
- }
-
-private:
- const TString mOldFunctionName;
- const TString mNewFunctionName;
-};
-
-#endif // COMPILER_RENAME_FUNCTION
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h b/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h
deleted file mode 100644
index 221d331ea..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h
+++ /dev/null
@@ -1,170 +0,0 @@
-//
-// 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 _SHHANDLE_INCLUDED_
-#define _SHHANDLE_INCLUDED_
-
-//
-// Machine independent part of the compiler private objects
-// sent as ShHandle to the driver.
-//
-// This should not be included by driver code.
-//
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/BuiltInFunctionEmulator.h"
-#include "compiler/ExtensionBehavior.h"
-#include "compiler/HashNames.h"
-#include "compiler/InfoSink.h"
-#include "compiler/SymbolTable.h"
-#include "compiler/VariableInfo.h"
-#include "third_party/compiler/ArrayBoundsClamper.h"
-
-class LongNameMap;
-class TCompiler;
-class TDependencyGraph;
-class TranslatorHLSL;
-
-//
-// Helper function to identify specs that are based on the WebGL spec,
-// like the CSS Shaders spec.
-//
-bool isWebGLBasedSpec(ShShaderSpec spec);
-
-//
-// The base class used to back handles returned to the driver.
-//
-class TShHandleBase {
-public:
- TShHandleBase();
- virtual ~TShHandleBase();
- virtual TCompiler* getAsCompiler() { return 0; }
- virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; }
-
-protected:
- // Memory allocator. Allocates and tracks memory required by the compiler.
- // Deallocates all memory when compiler is destructed.
- TPoolAllocator 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(ShShaderType type, ShShaderSpec spec);
- virtual ~TCompiler();
- virtual TCompiler* getAsCompiler() { return this; }
-
- bool Init(const ShBuiltInResources& resources);
- bool compile(const char* const shaderStrings[],
- size_t numStrings,
- int compileOptions);
-
- // Get results of the last compilation.
- TInfoSink& getInfoSink() { return infoSink; }
- const TVariableInfoList& getAttribs() const { return attribs; }
- const TVariableInfoList& getUniforms() const { return uniforms; }
- const TVariableInfoList& getVaryings() const { return varyings; }
- int getMappedNameMaxLength() const;
-
- ShHashFunction64 getHashFunction() const { return hashFunction; }
- NameMap& getNameMap() { return nameMap; }
- TSymbolTable& getSymbolTable() { return symbolTable; }
-
-protected:
- ShShaderType getShaderType() const { return shaderType; }
- ShShaderSpec getShaderSpec() const { return shaderSpec; }
- // Initialize symbol-table with built-in symbols.
- bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
- // Clears the results from the previous compilation.
- void clearResults();
- // Return true if function recursion is detected or call depth exceeded.
- bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth);
- // Rewrites a shader's intermediate tree according to the CSS Shaders spec.
- void rewriteCSSShader(TIntermNode* root);
- // Returns true if the given shader does not exceed the minimum
- // functionality mandated in GLSL 1.0 spec Appendix A.
- bool validateLimitations(TIntermNode* root);
- // Collect info for all attribs, uniforms, varyings.
- void collectVariables(TIntermNode* root);
- // Map long variable names into shorter ones.
- void mapLongVariableNames(TIntermNode* root);
- // Translate to object code.
- virtual void translate(TIntermNode* root) = 0;
- // Returns true if, after applying the packing rules in the GLSL 1.017 spec
- // Appendix A, section 7, the shader does not use too many uniforms or varyings.
- bool enforcePackingRestrictions();
- // Returns true if the shader passes the restrictions that aim to prevent timing attacks.
- bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
- // Returns true if the shader does not use samplers.
- bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
- // Returns true if the shader does not use sampler dependent values to affect control
- // flow or in operations whose time can depend on the input values.
- bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
- // Return true if the maximum expression complexity below the limit.
- bool limitExpressionComplexity(TIntermNode* root);
- // Get built-in extensions with default behavior.
- const TExtensionBehavior& getExtensionBehavior() const;
- // Get the resources set by InitBuiltInSymbolTable
- const ShBuiltInResources& getResources() const;
-
- const ArrayBoundsClamper& getArrayBoundsClamper() const;
- ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
- const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
-
-private:
- ShShaderType shaderType;
- ShShaderSpec shaderSpec;
-
- int maxUniformVectors;
- int maxVaryingVectors;
- int maxExpressionComplexity;
- int maxCallStackDepth;
-
- ShBuiltInResources compileResources;
-
- // Built-in symbol table for the given language, spec, and resources.
- // It is preserved from compile-to-compile.
- TSymbolTable symbolTable;
- // Built-in extensions with default behavior.
- TExtensionBehavior extensionBehavior;
- bool fragmentPrecisionHigh;
-
- ArrayBoundsClamper arrayBoundsClamper;
- ShArrayIndexClampingStrategy clampingStrategy;
- BuiltInFunctionEmulator builtInFunctionEmulator;
-
- // Results of compilation.
- TInfoSink infoSink; // Output sink.
- TVariableInfoList attribs; // Active attributes in the compiled shader.
- TVariableInfoList uniforms; // Active uniforms in the compiled shader.
- TVariableInfoList varyings; // Varyings in the compiled shader.
-
- // Cached copy of the ref-counted singleton.
- LongNameMap* longNameMap;
-
- // name hashing.
- ShHashFunction64 hashFunction;
- NameMap nameMap;
-};
-
-//
-// 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(
- ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
-void DeleteCompiler(TCompiler*);
-
-#endif // _SHHANDLE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp b/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp
deleted file mode 100644
index 42cd5cc5c..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-//
-// 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.
-//
-
-//
-// Implement the top-level of interface to the compiler,
-// as defined in ShaderLang.h
-//
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/InitializeDll.h"
-#include "compiler/preprocessor/length_limits.h"
-#include "compiler/ShHandle.h"
-#include "compiler/TranslatorHLSL.h"
-#include "compiler/VariablePacker.h"
-
-//
-// This is the platform independent interface between an OGL driver
-// and the shading language compiler.
-//
-
-static bool checkVariableMaxLengths(const ShHandle handle,
- size_t expectedValue)
-{
- size_t activeUniformLimit = 0;
- ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
- size_t activeAttribLimit = 0;
- ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
- size_t varyingLimit = 0;
- ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
- return (expectedValue == activeUniformLimit &&
- expectedValue == activeAttribLimit &&
- expectedValue == varyingLimit);
-}
-
-static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
-{
- size_t mappedNameMaxLength = 0;
- ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
- return (expectedValue == mappedNameMaxLength);
-}
-
-//
-// Driver must call this first, once, before doing any other compiler operations.
-// Subsequent calls to this function are no-op.
-//
-int ShInitialize()
-{
- static const bool kInitialized = InitProcess();
- return kInitialized ? 1 : 0;
-}
-
-//
-// Cleanup symbol tables
-//
-int ShFinalize()
-{
- DetachProcess();
- return 1;
-}
-
-//
-// Initialize built-in resources with minimum expected values.
-//
-void ShInitBuiltInResources(ShBuiltInResources* 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->ARB_texture_rectangle = 0;
- resources->EXT_draw_buffers = 0;
- resources->EXT_frag_depth = 0;
-
- // Disable highp precision in fragment shader by default.
- resources->FragmentPrecisionHigh = 0;
-
- // Disable name hashing by default.
- resources->HashFunction = NULL;
-
- resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
-}
-
-//
-// Driver calls these to create and destroy compiler objects.
-//
-ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
- ShShaderOutput output,
- const ShBuiltInResources* resources)
-{
- TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
- TCompiler* compiler = base->getAsCompiler();
- if (compiler == 0)
- return 0;
-
- // Generate built-in symbol table.
- if (!compiler->Init(*resources)) {
- ShDestruct(base);
- return 0;
- }
-
- return reinterpret_cast<void*>(base);
-}
-
-void ShDestruct(ShHandle handle)
-{
- if (handle == 0)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
-
- if (base->getAsCompiler())
- DeleteCompiler(base->getAsCompiler());
-}
-
-//
-// 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.
-//
-int ShCompile(
- const ShHandle handle,
- const char* const shaderStrings[],
- size_t numStrings,
- int compileOptions)
-{
- if (handle == 0)
- return 0;
-
- TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (compiler == 0)
- return 0;
-
- bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
- return success ? 1 : 0;
-}
-
-void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
-{
- if (!handle || !params)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (!compiler) return;
-
- switch(pname)
- {
- case SH_INFO_LOG_LENGTH:
- *params = compiler->getInfoSink().info.size() + 1;
- break;
- case SH_OBJECT_CODE_LENGTH:
- *params = compiler->getInfoSink().obj.size() + 1;
- break;
- case SH_ACTIVE_UNIFORMS:
- *params = compiler->getUniforms().size();
- break;
- case SH_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = 1 + MAX_SYMBOL_NAME_LEN;
- break;
- case SH_ACTIVE_ATTRIBUTES:
- *params = compiler->getAttribs().size();
- break;
- case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
- *params = 1 + MAX_SYMBOL_NAME_LEN;
- break;
- case SH_VARYINGS:
- *params = compiler->getVaryings().size();
- break;
- case SH_VARYING_MAX_LENGTH:
- *params = 1 + MAX_SYMBOL_NAME_LEN;
- break;
- case SH_MAPPED_NAME_MAX_LENGTH:
- // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
- // handle array and struct dereferences.
- *params = 1 + MAX_SYMBOL_NAME_LEN;
- break;
- case SH_NAME_MAX_LENGTH:
- *params = 1 + MAX_SYMBOL_NAME_LEN;
- break;
- case SH_HASHED_NAME_MAX_LENGTH:
- if (compiler->getHashFunction() == NULL) {
- *params = 0;
- } else {
- // 64 bits hashing output requires 16 bytes for hex
- // representation.
- const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
- *params = 16 + sizeof(HashedNamePrefix);
- }
- break;
- case SH_HASHED_NAMES_COUNT:
- *params = compiler->getNameMap().size();
- break;
- default: UNREACHABLE();
- }
-}
-
-//
-// Return any compiler log of messages for the application.
-//
-void ShGetInfoLog(const ShHandle handle, char* infoLog)
-{
- if (!handle || !infoLog)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (!compiler) return;
-
- TInfoSink& infoSink = compiler->getInfoSink();
- strcpy(infoLog, infoSink.info.c_str());
-}
-
-//
-// Return any object code.
-//
-void ShGetObjectCode(const ShHandle handle, char* objCode)
-{
- if (!handle || !objCode)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (!compiler) return;
-
- TInfoSink& infoSink = compiler->getInfoSink();
- strcpy(objCode, infoSink.obj.c_str());
-}
-
-void ShGetVariableInfo(const ShHandle handle,
- ShShaderInfo varType,
- int index,
- size_t* length,
- int* size,
- ShDataType* type,
- ShPrecisionType* precision,
- int* staticUse,
- char* name,
- char* mappedName)
-{
- if (!handle || !size || !type || !precision || !staticUse || !name)
- return;
- ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
- (varType == SH_ACTIVE_UNIFORMS) ||
- (varType == SH_VARYINGS));
-
- TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (compiler == 0)
- return;
-
- const TVariableInfoList& varList =
- varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() :
- (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() :
- compiler->getVaryings());
- if (index < 0 || index >= static_cast<int>(varList.size()))
- return;
-
- const TVariableInfo& varInfo = varList[index];
- if (length) *length = varInfo.name.size();
- *size = varInfo.size;
- *type = varInfo.type;
- switch (varInfo.precision) {
- case EbpLow:
- *precision = SH_PRECISION_LOWP;
- break;
- case EbpMedium:
- *precision = SH_PRECISION_MEDIUMP;
- break;
- case EbpHigh:
- *precision = SH_PRECISION_HIGHP;
- break;
- default:
- // Some types does not support precision, for example, boolean.
- *precision = SH_PRECISION_UNDEFINED;
- break;
- }
- *staticUse = varInfo.staticUse ? 1 : 0;
-
- // This size must match that queried by
- // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
- // in ShGetInfo, below.
- size_t variableLength = 1 + MAX_SYMBOL_NAME_LEN;
- ASSERT(checkVariableMaxLengths(handle, variableLength));
- strncpy(name, varInfo.name.c_str(), variableLength);
- name[variableLength - 1] = 0;
- if (mappedName) {
- // This size must match that queried by
- // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
- size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
- ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
- strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
- mappedName[maxMappedNameLength - 1] = 0;
- }
-}
-
-void ShGetNameHashingEntry(const ShHandle handle,
- int index,
- char* name,
- char* hashedName)
-{
- if (!handle || !name || !hashedName || index < 0)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
- TCompiler* compiler = base->getAsCompiler();
- if (!compiler) return;
-
- const NameMap& nameMap = compiler->getNameMap();
- if (index >= static_cast<int>(nameMap.size()))
- return;
-
- NameMap::const_iterator it = nameMap.begin();
- for (int i = 0; i < index; ++i)
- ++it;
-
- size_t len = it->first.length() + 1;
- size_t max_len = 0;
- ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
- if (len > max_len) {
- ASSERT(false);
- len = max_len;
- }
- strncpy(name, it->first.c_str(), len);
- // To be on the safe side in case the source is longer than expected.
- name[len - 1] = '\0';
-
- len = it->second.length() + 1;
- max_len = 0;
- ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
- if (len > max_len) {
- ASSERT(false);
- len = max_len;
- }
- strncpy(hashedName, it->second.c_str(), len);
- // To be on the safe side in case the source is longer than expected.
- hashedName[len - 1] = '\0';
-}
-
-void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
-{
- if (!handle || !params)
- return;
-
- TShHandleBase* base = static_cast<TShHandleBase*>(handle);
- TranslatorHLSL* translator = base->getAsTranslatorHLSL();
- if (!translator) return;
-
- switch(pname)
- {
- case SH_ACTIVE_UNIFORMS_ARRAY:
- *params = (void*)&translator->getUniforms();
- break;
- default: UNREACHABLE();
- }
-}
-
-int ShCheckVariablesWithinPackingLimits(
- int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
-{
- if (varInfoArraySize == 0)
- return 1;
- ASSERT(varInfoArray);
- TVariableInfoList variables;
- for (size_t ii = 0; ii < varInfoArraySize; ++ii)
- {
- TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size);
- variables.push_back(var);
- }
- VariablePacker packer;
- return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp
deleted file mode 100644
index 715e13616..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-//
-// 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.
-//
-
-//
-// Symbol table for parsing. Most functionaliy and main ideas
-// are documented in the header file.
-//
-
-#if defined(_MSC_VER)
-#pragma warning(disable: 4718)
-#endif
-
-#include "compiler/SymbolTable.h"
-
-#include <stdio.h>
-#include <algorithm>
-#include <climits>
-
-TType::TType(const TPublicType &p) :
- type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), structure(0)
-{
- if (p.userDef)
- structure = p.userDef->getStruct();
-}
-
-//
-// Recursively generate mangled names.
-//
-TString TType::buildMangledName() const
-{
- TString mangledName;
- if (isMatrix())
- mangledName += 'm';
- else if (isVector())
- mangledName += 'v';
-
- switch (type) {
- case EbtFloat: mangledName += 'f'; break;
- case EbtInt: mangledName += 'i'; break;
- case EbtBool: mangledName += 'b'; break;
- case EbtSampler2D: mangledName += "s2"; break;
- case EbtSamplerCube: mangledName += "sC"; break;
- case EbtStruct: mangledName += structure->mangledName(); break;
- default: break;
- }
-
- mangledName += static_cast<char>('0' + getNominalSize());
- if (isArray()) {
- char buf[20];
- snprintf(buf, sizeof(buf), "%d", arraySize);
- mangledName += '[';
- mangledName += buf;
- mangledName += ']';
- }
- return mangledName;
-}
-
-size_t TType::getObjectSize() const
-{
- size_t totalSize = 0;
-
- if (getBasicType() == EbtStruct)
- totalSize = structure->objectSize();
- else if (matrix)
- totalSize = size * size;
- else
- totalSize = size;
-
- if (isArray()) {
- size_t arraySize = getArraySize();
- if (arraySize > INT_MAX / totalSize)
- totalSize = INT_MAX;
- else
- totalSize *= arraySize;
- }
-
- return totalSize;
-}
-
-bool TStructure::containsArrays() const
-{
- for (size_t i = 0; i < mFields->size(); ++i) {
- const TType* fieldType = (*mFields)[i]->type();
- if (fieldType->isArray() || fieldType->isStructureContainingArrays())
- return true;
- }
- return false;
-}
-
-TString TStructure::buildMangledName() const
-{
- TString mangledName("struct-");
- mangledName += *mName;
- for (size_t i = 0; i < mFields->size(); ++i) {
- mangledName += '-';
- mangledName += (*mFields)[i]->type()->getMangledName();
- }
- return mangledName;
-}
-
-size_t TStructure::calculateObjectSize() const
-{
- size_t size = 0;
- for (size_t i = 0; i < mFields->size(); ++i) {
- size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
- if (fieldSize > INT_MAX - size)
- size = INT_MAX;
- else
- size += fieldSize;
- }
- return size;
-}
-
-int TStructure::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;
-}
-
-//
-// Dump functions.
-//
-
-void TVariable::dump(TInfoSink& infoSink) const
-{
- infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
- if (type.isArray()) {
- infoSink.debug << "[0]";
- }
- infoSink.debug << "\n";
-}
-
-void TFunction::dump(TInfoSink &infoSink) const
-{
- infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
-}
-
-void TSymbolTableLevel::dump(TInfoSink &infoSink) const
-{
- tLevel::const_iterator it;
- for (it = level.begin(); it != level.end(); ++it)
- (*it).second->dump(infoSink);
-}
-
-void TSymbolTable::dump(TInfoSink &infoSink) const
-{
- for (int level = currentLevel(); level >= 0; --level) {
- infoSink.debug << "LEVEL " << level << "\n";
- table[level]->dump(infoSink);
- }
-}
-
-//
-// Functions have buried pointers to delete.
-//
-TFunction::~TFunction()
-{
- for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
- delete (*i).type;
-}
-
-//
-// Symbol table levels are a map of pointers to symbols that have to be deleted.
-//
-TSymbolTableLevel::~TSymbolTableLevel()
-{
- for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
- if ((*it).first == (*it).second->getMangledName())
- delete (*it).second;
-}
-
-//
-// Change all function entries in the table with the non-mangled name
-// to be related to the provided built-in operation. This is a low
-// performance operation, and only intended for symbol tables that
-// live across a large number of compiles.
-//
-void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
-{
- tLevel::iterator it;
- for (it = level.begin(); it != level.end(); ++it) {
- if ((*it).second->isFunction()) {
- TFunction* function = static_cast<TFunction*>((*it).second);
- if (function->getName() == name)
- function->relateToOperator(op);
- }
- }
-}
-
-//
-// Change all function entries in the table with the non-mangled name
-// to be related to the provided built-in extension. This is a low
-// performance operation, and only intended for symbol tables that
-// live across a large number of compiles.
-//
-void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
-{
- for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
- TSymbol* symbol = it->second;
- if (symbol->getName() == name)
- symbol->relateToExtension(ext);
- }
-}
-
-TSymbolTable::~TSymbolTable()
-{
- for (size_t i = 0; i < table.size(); ++i)
- delete table[i];
- for (size_t i = 0; i < precisionStack.size(); ++i)
- delete precisionStack[i];
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h
deleted file mode 100644
index bebad4b92..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h
+++ /dev/null
@@ -1,382 +0,0 @@
-//
-// 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 _SYMBOL_TABLE_INCLUDED_
-#define _SYMBOL_TABLE_INCLUDED_
-
-//
-// 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 <assert.h>
-
-#include "common/angleutils.h"
-#include "compiler/InfoSink.h"
-#include "compiler/intermediate.h"
-
-//
-// Symbol base class. (Can build functions or variables out of these...)
-//
-class TSymbol {
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TSymbol(const TString* n) : uniqueId(0), name(n) { }
- virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
-
- const TString& getName() const { return *name; }
- virtual const TString& getMangledName() const { return getName(); }
- virtual bool isFunction() const { return false; }
- virtual bool isVariable() const { return false; }
- void setUniqueId(int id) { uniqueId = id; }
- int getUniqueId() const { return uniqueId; }
- virtual void dump(TInfoSink &infoSink) const = 0;
- void relateToExtension(const TString& ext) { extension = ext; }
- const TString& getExtension() const { return extension; }
-
-private:
- DISALLOW_COPY_AND_ASSIGN(TSymbol);
-
- int uniqueId; // For real comparing during code generation
- const TString *name;
- TString extension;
-};
-
-//
-// Variable class, meaning a symbol that's not a function.
-//
-// There could be a separate class heirarchy for Constant variables;
-// Only one of int, bool, or float, (or none) is correct for
-// any particular use, but it's easy to do this way, and doesn't
-// seem worth having separate classes, and "getConst" can't simply return
-// different values for different types polymorphically, so this is
-// just simple and pragmatic.
-//
-class TVariable : public TSymbol {
-public:
- TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { }
- virtual ~TVariable() { }
- virtual bool isVariable() const { return true; }
- TType& getType() { return type; }
- const TType& getType() const { return type; }
- bool isUserType() const { return userType; }
- void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); }
-
- virtual void dump(TInfoSink &infoSink) const;
-
- ConstantUnion* getConstPointer()
- {
- if (!unionArray)
- unionArray = new ConstantUnion[type.getObjectSize()];
-
- return unionArray;
- }
-
- ConstantUnion* getConstPointer() const { return unionArray; }
-
- void shareConstPointer( ConstantUnion *constArray)
- {
- if (unionArray == constArray)
- return;
-
- delete[] unionArray;
- unionArray = constArray;
- }
-
-private:
- DISALLOW_COPY_AND_ASSIGN(TVariable);
-
- TType type;
- bool userType;
- // we are assuming that Pool Allocator will free the memory allocated to unionArray
- // when this object is destroyed
- ConstantUnion *unionArray;
-};
-
-//
-// The function sub-class of symbols and the parser will need to
-// share this definition of a function parameter.
-//
-struct TParameter {
- TString *name;
- TType* type;
-};
-
-//
-// The function sub-class of a symbol.
-//
-class TFunction : public TSymbol {
-public:
- TFunction(TOperator o) :
- TSymbol(0),
- returnType(TType(EbtVoid, EbpUndefined)),
- op(o),
- defined(false) { }
- TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
- TSymbol(name),
- returnType(retType),
- mangledName(TFunction::mangleName(*name)),
- op(tOp),
- defined(false) { }
- virtual ~TFunction();
- virtual bool isFunction() const { return true; }
-
- static TString mangleName(const TString& name) { return name + '('; }
- static TString unmangleName(const TString& mangledName)
- {
- return TString(mangledName.c_str(), mangledName.find_first_of('('));
- }
-
- void addParameter(TParameter& p)
- {
- parameters.push_back(p);
- mangledName = mangledName + p.type->getMangledName();
- }
-
- const TString& getMangledName() const { return mangledName; }
- const TType& getReturnType() const { return returnType; }
-
- void relateToOperator(TOperator o) { op = o; }
- TOperator getBuiltInOp() const { return op; }
-
- void setDefined() { defined = true; }
- bool isDefined() { return defined; }
-
- size_t getParamCount() const { return parameters.size(); }
- const TParameter& getParam(size_t i) const { return parameters[i]; }
-
- virtual void dump(TInfoSink &infoSink) const;
-
-private:
- DISALLOW_COPY_AND_ASSIGN(TFunction);
-
- typedef TVector<TParameter> TParamList;
- TParamList parameters;
- TType returnType;
- TString mangledName;
- TOperator op;
- bool defined;
-};
-
-
-class TSymbolTableLevel {
-public:
- typedef TMap<TString, TSymbol*> tLevel;
- typedef tLevel::const_iterator const_iterator;
- typedef const tLevel::value_type tLevelPair;
- typedef std::pair<tLevel::iterator, bool> tInsertResult;
-
- TSymbolTableLevel() { }
- ~TSymbolTableLevel();
-
- bool insert(const TString &name, TSymbol &symbol)
- {
- //
- // returning true means symbol was added to the table
- //
- tInsertResult result = level.insert(tLevelPair(name, &symbol));
-
- return result.second;
- }
-
- bool insert(TSymbol &symbol)
- {
- return insert(symbol.getMangledName(), symbol);
- }
-
- TSymbol* find(const TString& name) const
- {
- tLevel::const_iterator it = level.find(name);
- if (it == level.end())
- return 0;
- else
- return (*it).second;
- }
-
- const_iterator begin() const
- {
- return level.begin();
- }
-
- const_iterator end() const
- {
- return level.end();
- }
-
- void relateToOperator(const char* name, TOperator op);
- void relateToExtension(const char* name, const TString& ext);
- void dump(TInfoSink &infoSink) const;
-
-protected:
- tLevel level;
-};
-
-class TSymbolTable {
-public:
- TSymbolTable() : uniqueId(0)
- {
- //
- // The symbol table cannot be used until push() is called, but
- // the lack of an initial call to push() can be used to detect
- // that the symbol table has not been preloaded with built-ins.
- //
- }
- ~TSymbolTable();
-
- //
- // When the symbol table is initialized with the built-ins, there should
- // 'push' calls, so that built-ins are at level 0 and the shader
- // globals are at level 1.
- //
- bool isEmpty() { return table.size() == 0; }
- bool atBuiltInLevel() { return table.size() == 1; }
- bool atGlobalLevel() { return table.size() <= 2; }
- void push()
- {
- table.push_back(new TSymbolTableLevel);
- precisionStack.push_back(new PrecisionStackLevel);
- }
-
- void pop()
- {
- delete table.back();
- table.pop_back();
-
- delete precisionStack.back();
- precisionStack.pop_back();
- }
-
- bool insert(TSymbol& symbol)
- {
- symbol.setUniqueId(++uniqueId);
- return table[currentLevel()]->insert(symbol);
- }
-
- bool insertConstInt(const char *name, int value)
- {
- TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
- constant->getConstPointer()->setIConst(value);
- return insert(*constant);
- }
-
- bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0)
- {
- TFunction *function = new TFunction(NewPoolTString(name), *rvalue);
-
- TParameter param1 = {NULL, ptype1};
- function->addParameter(param1);
-
- if(ptype2)
- {
- TParameter param2 = {NULL, ptype2};
- function->addParameter(param2);
- }
-
- if(ptype3)
- {
- TParameter param3 = {NULL, ptype3};
- function->addParameter(param3);
- }
-
- return insert(*function);
- }
-
- TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
- {
- int level = currentLevel();
- TSymbol* symbol;
- do {
- symbol = table[level]->find(name);
- --level;
- } while (symbol == 0 && level >= 0);
- level++;
- if (builtIn)
- *builtIn = level == 0;
- if (sameScope)
- *sameScope = level == currentLevel();
- return symbol;
- }
-
- TSymbol* findBuiltIn(const TString &name)
- {
- return table[0]->find(name);
- }
-
- TSymbolTableLevel* getOuterLevel() {
- assert(table.size() >= 2);
- return table[currentLevel() - 1];
- }
-
- void relateToOperator(const char* name, TOperator op) {
- table[0]->relateToOperator(name, op);
- }
- void relateToExtension(const char* name, const TString& ext) {
- table[0]->relateToExtension(name, ext);
- }
- void dump(TInfoSink &infoSink) const;
-
- bool setDefaultPrecision(const TPublicType& type, TPrecision prec) {
- if (!supportsPrecision(type.type))
- return false;
- if (type.size != 1 || type.matrix || type.array)
- return false; // Not allowed to set for aggregate types
- int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
- (*precisionStack[indexOfLastElement])[type.type] = prec; // Uses map operator [], overwrites the current value
- return true;
- }
-
- // Searches down the precisionStack for a precision qualifier for the specified TBasicType
- TPrecision getDefaultPrecision(TBasicType type) {
- if (!supportsPrecision(type))
- return EbpUndefined;
- int level = static_cast<int>(precisionStack.size()) - 1;
- assert(level >= 0); // Just to be safe. Should not happen.
- PrecisionStackLevel::iterator it;
- TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
- while (level >= 0) {
- it = precisionStack[level]->find(type);
- if (it != precisionStack[level]->end()) {
- prec = (*it).second;
- break;
- }
- level--;
- }
- return prec;
- }
-
-private:
- int currentLevel() const { return static_cast<int>(table.size()) - 1; }
-
- bool supportsPrecision(TBasicType type) {
- // Only supports precision for int, float, and sampler types.
- return type == EbtFloat || type == EbtInt || IsSampler(type);
- }
-
- int uniqueId; // for unique identification in code generation
- std::vector<TSymbolTableLevel*> table;
- typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
- std::vector<PrecisionStackLevel*> precisionStack;
-};
-
-#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp
deleted file mode 100644
index 2900f8a8e..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// 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/TranslatorESSL.h"
-
-#include "compiler/OutputESSL.h"
-
-TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
- : TCompiler(type, spec) {
-}
-
-void TranslatorESSL::translate(TIntermNode* root) {
- TInfoSinkBase& sink = getInfoSink().obj;
-
- // Write built-in extension behaviors.
- writeExtensionBehavior();
-
- // Write emulated built-in functions if needed.
- getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
- sink, getShaderType() == SH_FRAGMENT_SHADER);
-
- // Write array bounds clamping emulation if needed.
- getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
-
- // Write translated shader.
- TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable());
- root->traverse(&outputESSL);
-}
-
-void TranslatorESSL::writeExtensionBehavior() {
- TInfoSinkBase& sink = getInfoSink().obj;
- const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
- for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
- iter != extensionBehavior.end(); ++iter) {
- if (iter->second != EBhUndefined) {
- sink << "#extension " << iter->first << " : "
- << getBehaviorString(iter->second) << "\n";
- }
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h
deleted file mode 100644
index a1196bd00..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// 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_TRANSLATORESSL_H_
-#define COMPILER_TRANSLATORESSL_H_
-
-#include "compiler/ShHandle.h"
-
-class TranslatorESSL : public TCompiler {
-public:
- TranslatorESSL(ShShaderType type, ShShaderSpec spec);
-
-protected:
- virtual void translate(TIntermNode* root);
-
-private:
- void writeExtensionBehavior();
-};
-
-#endif // COMPILER_TRANSLATORESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp
deleted file mode 100644
index 7ca4341dc..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// 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/TranslatorGLSL.h"
-
-#include "compiler/OutputGLSL.h"
-#include "compiler/VersionGLSL.h"
-
-static void writeVersion(ShShaderType type, TIntermNode* root,
- TInfoSinkBase& sink) {
- TVersionGLSL versionGLSL(type);
- 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) {
- sink << "#version " << version << "\n";
- }
-}
-
-TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec)
- : TCompiler(type, spec) {
-}
-
-void TranslatorGLSL::translate(TIntermNode* root) {
- TInfoSinkBase& sink = getInfoSink().obj;
-
- // Write GLSL version.
- writeVersion(getShaderType(), root, sink);
-
- // Write emulated built-in functions if needed.
- getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
- sink, false);
-
- // Write array bounds clamping emulation if needed.
- getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
-
- // Write translated shader.
- TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable());
- root->traverse(&outputGLSL);
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h
deleted file mode 100644
index c2ce06d19..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// 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_TRANSLATORGLSL_H_
-#define COMPILER_TRANSLATORGLSL_H_
-
-#include "compiler/ShHandle.h"
-
-class TranslatorGLSL : public TCompiler {
-public:
- TranslatorGLSL(ShShaderType type, ShShaderSpec spec);
-
-protected:
- virtual void translate(TIntermNode* root);
-};
-
-#endif // COMPILER_TRANSLATORGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp
deleted file mode 100644
index 37408a07c..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// 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/TranslatorHLSL.h"
-
-#include "compiler/InitializeParseContext.h"
-#include "compiler/OutputHLSL.h"
-
-TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
- : TCompiler(type, spec), mOutputType(output)
-{
-}
-
-void TranslatorHLSL::translate(TIntermNode *root)
-{
- TParseContext& parseContext = *GetGlobalParseContext();
- sh::OutputHLSL outputHLSL(parseContext, getResources(), mOutputType);
-
- outputHLSL.output();
- mActiveUniforms = outputHLSL.getUniforms();
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h
deleted file mode 100644
index 9550e15e8..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// 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_TRANSLATORHLSL_H_
-#define COMPILER_TRANSLATORHLSL_H_
-
-#include "compiler/ShHandle.h"
-#include "compiler/Uniform.h"
-
-class TranslatorHLSL : public TCompiler {
-public:
- TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
-
- virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; }
- const sh::ActiveUniforms &getUniforms() { return mActiveUniforms; }
-
-protected:
- virtual void translate(TIntermNode* root);
-
- sh::ActiveUniforms mActiveUniforms;
- ShShaderOutput mOutputType;
-};
-
-#endif // COMPILER_TRANSLATORHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Types.h b/Source/ThirdParty/ANGLE/src/compiler/Types.h
deleted file mode 100644
index 75560ddc6..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Types.h
+++ /dev/null
@@ -1,307 +0,0 @@
-//
-// 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 _TYPES_INCLUDED
-#define _TYPES_INCLUDED
-
-#include "common/angleutils.h"
-
-#include "compiler/BaseTypes.h"
-#include "compiler/Common.h"
-#include "compiler/debug.h"
-
-struct TPublicType;
-class TType;
-
-class TField
-{
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TField(TType* type, TString* name) : mType(type), mName(name) {}
-
- // TODO(alokp): We should only return const type.
- // Fix it by tweaking grammar.
- TType* type() { return mType; }
- const TType* type() const { return mType; }
-
- const TString& name() const { return *mName; }
-
-private:
- DISALLOW_COPY_AND_ASSIGN(TField);
- TType* mType;
- TString* mName;
-};
-
-typedef TVector<TField*> TFieldList;
-inline TFieldList* NewPoolTFieldList()
-{
- void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList));
- return new(memory) TFieldList;
-}
-
-class TStructure
-{
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TStructure(TString* name, TFieldList* fields)
- : mName(name),
- mFields(fields),
- mObjectSize(0),
- mDeepestNesting(0) {
- }
-
- const TString& name() const { return *mName; }
- const TFieldList& fields() const { return *mFields; }
-
- const TString& mangledName() const {
- if (mMangledName.empty())
- mMangledName = buildMangledName();
- return mMangledName;
- }
- size_t objectSize() const {
- if (mObjectSize == 0)
- mObjectSize = calculateObjectSize();
- return mObjectSize;
- };
- int deepestNesting() const {
- if (mDeepestNesting == 0)
- mDeepestNesting = calculateDeepestNesting();
- return mDeepestNesting;
- }
- bool containsArrays() const;
-
-private:
- DISALLOW_COPY_AND_ASSIGN(TStructure);
- TString buildMangledName() const;
- size_t calculateObjectSize() const;
- int calculateDeepestNesting() const;
-
- TString* mName;
- TFieldList* mFields;
-
- mutable TString mMangledName;
- mutable size_t mObjectSize;
- mutable int mDeepestNesting;
-};
-
-//
-// Base class for things that have a type.
-//
-class TType
-{
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TType() {}
- TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, unsigned char s = 1, bool m = false, bool a = false) :
- type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), structure(0)
- {
- }
- explicit TType(const TPublicType &p);
- TType(TStructure* userDef, TPrecision p = EbpUndefined) :
- type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), structure(userDef)
- {
- }
-
- TBasicType getBasicType() const { return type; }
- void setBasicType(TBasicType t) { type = t; }
-
- TPrecision getPrecision() const { return precision; }
- void setPrecision(TPrecision p) { precision = p; }
-
- TQualifier getQualifier() const { return qualifier; }
- void setQualifier(TQualifier q) { qualifier = q; }
-
- // One-dimensional size of single instance type
- int getNominalSize() const { return size; }
- void setNominalSize(unsigned char s) { size = s; }
- // Full size of single instance of type
- size_t getObjectSize() const;
-
- int elementRegisterCount() const
- {
- if (structure)
- {
- const TFieldList &fields = getStruct()->fields();
- int registerCount = 0;
-
- for (size_t i = 0; i < fields.size(); i++)
- {
- registerCount += fields[i]->type()->totalRegisterCount();
- }
-
- return registerCount;
- }
- else if (isMatrix())
- {
- return getNominalSize();
- }
- else
- {
- return 1;
- }
- }
-
- int totalRegisterCount() const
- {
- if (array)
- {
- return arraySize * elementRegisterCount();
- }
- else
- {
- return elementRegisterCount();
- }
- }
-
- bool isMatrix() const { return matrix ? true : false; }
- void setMatrix(bool m) { matrix = m; }
-
- bool isArray() const { return array ? true : false; }
- int getArraySize() const { return arraySize; }
- void setArraySize(int s) { array = true; arraySize = s; }
- void clearArrayness() { array = false; arraySize = 0; }
-
- bool isVector() const { return size > 1 && !matrix; }
- bool isScalar() const { return size == 1 && !matrix && !structure; }
-
- TStructure* getStruct() const { return structure; }
- void setStruct(TStructure* s) { structure = s; }
-
- const TString& getMangledName() const {
- if (mangled.empty()) {
- mangled = buildMangledName();
- mangled += ';';
- }
- return mangled;
- }
-
- bool sameElementType(const TType& right) const {
- return type == right.type &&
- size == right.size &&
- matrix == right.matrix &&
- structure == right.structure;
- }
- bool operator==(const TType& right) const {
- return type == right.type &&
- size == right.size &&
- matrix == right.matrix &&
- array == right.array && (!array || arraySize == right.arraySize) &&
- structure == right.structure;
- // 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 (size != right.size) return size < right.size;
- if (matrix != right.matrix) return matrix < right.matrix;
- if (array != right.array) return array < right.array;
- if (arraySize != right.arraySize) return arraySize < right.arraySize;
- if (structure != right.structure) return structure < right.structure;
-
- return false;
- }
-
- const char* getBasicString() const { return ::getBasicString(type); }
- const char* getPrecisionString() const { return ::getPrecisionString(precision); }
- const char* getQualifierString() const { return ::getQualifierString(qualifier); }
- TString getCompleteString() 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 {
- return structure ? structure->deepestNesting() : 0;
- }
-
- bool isStructureContainingArrays() const {
- return structure ? structure->containsArrays() : false;
- }
-
-private:
- TString buildMangledName() const;
-
- TBasicType type;
- TPrecision precision;
- TQualifier qualifier;
- unsigned char size;
- bool matrix;
- bool array;
- int arraySize;
-
- TStructure* structure; // 0 unless this is a struct
-
- mutable TString mangled;
-};
-
-//
-// 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
-{
- TBasicType type;
- TQualifier qualifier;
- TPrecision precision;
- unsigned char size; // size of vector or matrix, not size of array
- bool matrix;
- bool array;
- int arraySize;
- TType* userDef;
- TSourceLoc line;
-
- void setBasic(TBasicType bt, TQualifier q, const TSourceLoc& ln)
- {
- type = bt;
- qualifier = q;
- precision = EbpUndefined;
- size = 1;
- matrix = false;
- array = false;
- arraySize = 0;
- userDef = 0;
- line = ln;
- }
-
- void setAggregate(unsigned char s, bool m = false)
- {
- size = s;
- matrix = m;
- }
-
- void setArray(bool a, int s = 0)
- {
- array = a;
- arraySize = s;
- }
-
- bool isStructureContainingArrays() const
- {
- if (!userDef)
- {
- return false;
- }
-
- return userDef->isStructureContainingArrays();
- }
-};
-
-#endif // _TYPES_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.cpp b/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.cpp
deleted file mode 100644
index 5cfdd3230..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-// 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.
-//
-// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements.
-// The results are assigned to s# temporaries, which are used by the main translator instead of
-// the original expression.
-//
-
-#include "compiler/UnfoldShortCircuit.h"
-
-#include "compiler/InfoSink.h"
-#include "compiler/OutputHLSL.h"
-
-namespace sh
-{
-UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
-{
- mTemporaryIndex = 0;
-}
-
-void UnfoldShortCircuit::traverse(TIntermNode *node)
-{
- int rewindIndex = mTemporaryIndex;
- node->traverse(this);
- mTemporaryIndex = rewindIndex;
-}
-
-bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
-{
- TInfoSinkBase &out = mOutputHLSL->getBodyStream();
-
- // 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)
- if (!node->getRight()->hasSideEffects())
- {
- return 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;".
- {
- int i = mTemporaryIndex;
-
- out << "bool s" << i << ";\n";
-
- out << "{\n";
-
- mTemporaryIndex = i + 1;
- node->getLeft()->traverse(this);
- out << "s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getLeft()->traverse(mOutputHLSL);
- out << ";\n";
- out << "if (!s" << i << ")\n"
- "{\n";
- mTemporaryIndex = i + 1;
- node->getRight()->traverse(this);
- out << " s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getRight()->traverse(mOutputHLSL);
- out << ";\n"
- "}\n";
-
- out << "}\n";
-
- mTemporaryIndex = i + 1;
- }
- 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;".
- {
- int i = mTemporaryIndex;
-
- out << "bool s" << i << ";\n";
-
- out << "{\n";
-
- mTemporaryIndex = i + 1;
- node->getLeft()->traverse(this);
- out << "s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getLeft()->traverse(mOutputHLSL);
- out << ";\n";
- out << "if (s" << i << ")\n"
- "{\n";
- mTemporaryIndex = i + 1;
- node->getRight()->traverse(this);
- out << " s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getRight()->traverse(mOutputHLSL);
- out << ";\n"
- "}\n";
-
- out << "}\n";
-
- mTemporaryIndex = i + 1;
- }
- return false;
- default:
- return true;
- }
-}
-
-bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
-{
- TInfoSinkBase &out = mOutputHLSL->getBodyStream();
-
- // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
- if (node->usesTernaryOperator())
- {
- int i = mTemporaryIndex;
-
- out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n";
-
- out << "{\n";
-
- mTemporaryIndex = i + 1;
- node->getCondition()->traverse(this);
- out << "if (";
- mTemporaryIndex = i + 1;
- node->getCondition()->traverse(mOutputHLSL);
- out << ")\n"
- "{\n";
- mTemporaryIndex = i + 1;
- node->getTrueBlock()->traverse(this);
- out << " s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getTrueBlock()->traverse(mOutputHLSL);
- out << ";\n"
- "}\n"
- "else\n"
- "{\n";
- mTemporaryIndex = i + 1;
- node->getFalseBlock()->traverse(this);
- out << " s" << i << " = ";
- mTemporaryIndex = i + 1;
- node->getFalseBlock()->traverse(mOutputHLSL);
- out << ";\n"
- "}\n";
-
- out << "}\n";
-
- mTemporaryIndex = i + 1;
- }
-
- return false;
-}
-
-bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
-{
- int rewindIndex = mTemporaryIndex;
-
- if (node->getInit())
- {
- node->getInit()->traverse(this);
- }
-
- if (node->getCondition())
- {
- node->getCondition()->traverse(this);
- }
-
- if (node->getExpression())
- {
- node->getExpression()->traverse(this);
- }
-
- mTemporaryIndex = rewindIndex;
-
- return false;
-}
-
-int UnfoldShortCircuit::getNextTemporaryIndex()
-{
- return mTemporaryIndex++;
-}
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.h b/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.h
deleted file mode 100644
index ae2989fa4..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuit.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// 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.
-//
-// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements
-//
-
-#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_
-#define COMPILER_UNFOLDSHORTCIRCUIT_H_
-
-#include "compiler/intermediate.h"
-#include "compiler/ParseContext.h"
-
-namespace sh
-{
-class OutputHLSL;
-
-class UnfoldShortCircuit : public TIntermTraverser
-{
- public:
- UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL);
-
- void traverse(TIntermNode *node);
- bool visitBinary(Visit visit, TIntermBinary*);
- bool visitSelection(Visit visit, TIntermSelection *node);
- bool visitLoop(Visit visit, TIntermLoop *node);
-
- int getNextTemporaryIndex();
-
- protected:
- TParseContext &mContext;
- OutputHLSL *const mOutputHLSL;
-
- int mTemporaryIndex;
-};
-}
-
-#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.cpp b/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.cpp
deleted file mode 100644
index b6d0f2f30..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// 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/UnfoldShortCircuitAST.h"
-
-namespace
-{
-
-// "x || y" is equivalent to "x ? true : y".
-TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
-{
- const TType boolType(EbtBool, EbpUndefined);
- ConstantUnion *u = new ConstantUnion;
- u->setBConst(true);
- TIntermConstantUnion *trueNode = new TIntermConstantUnion(
- u, TType(EbtBool, EbpUndefined, EvqConst, 1));
- return new TIntermSelection(x, trueNode, y, boolType);
-}
-
-// "x && y" is equivalent to "x ? y : false".
-TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
-{
- const TType boolType(EbtBool, EbpUndefined);
- ConstantUnion *u = new ConstantUnion;
- u->setBConst(false);
- TIntermConstantUnion *falseNode = new TIntermConstantUnion(
- u, TType(EbtBool, EbpUndefined, EvqConst, 1));
- return new TIntermSelection(x, y, falseNode, boolType);
-}
-
-} // namespace anonymous
-
-bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
-{
- TIntermSelection *replacement = NULL;
-
- 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)
- {
- replacements.push_back(
- NodeUpdateEntry(getParentNode(), node, replacement));
- }
- return true;
-}
-
-void UnfoldShortCircuitAST::updateTree()
-{
- for (size_t ii = 0; ii < replacements.size(); ++ii)
- {
- const NodeUpdateEntry& entry = replacements[ii];
- ASSERT(entry.parent);
- bool replaced = entry.parent->replaceChildNode(
- entry.original, entry.replacement);
- ASSERT(replaced);
-
- // In AST traversing, a parent is visited before its children.
- // After we replace a node, if an 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 < replacements.size(); ++jj)
- {
- NodeUpdateEntry& entry2 = replacements[jj];
- if (entry2.parent == entry.original)
- entry2.parent = entry.replacement;
- }
- }
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.h b/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.h
deleted file mode 100644
index cfc500664..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/UnfoldShortCircuitAST.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// 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_UNFOLD_SHORT_CIRCUIT_AST_H_
-#define COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_
-
-#include "common/angleutils.h"
-#include "compiler/intermediate.h"
-
-// 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 UnfoldShortCircuitAST : public TIntermTraverser
-{
- public:
- UnfoldShortCircuitAST() { }
-
- virtual bool visitBinary(Visit visit, TIntermBinary *);
-
- void updateTree();
-
- private:
- struct NodeUpdateEntry
- {
- NodeUpdateEntry(TIntermNode *_parent,
- TIntermNode *_original,
- TIntermNode *_replacement)
- : parent(_parent),
- original(_original),
- replacement(_replacement) {}
-
- TIntermNode *parent;
- TIntermNode *original;
- TIntermNode *replacement;
- };
-
- // During traversing, save all the replacements that need to happen;
- // then replace them by calling updateNodes().
- std::vector<NodeUpdateEntry> replacements;
-
- DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST);
-};
-
-#endif // COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Uniform.cpp b/Source/ThirdParty/ANGLE/src/compiler/Uniform.cpp
deleted file mode 100644
index f367db2be..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Uniform.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/Uniform.h"
-
-namespace sh
-{
-
-Uniform::Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex)
-{
- this->type = type;
- this->precision = precision;
- this->name = name;
- this->arraySize = arraySize;
- this->registerIndex = registerIndex;
-}
-
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Uniform.h b/Source/ThirdParty/ANGLE/src/compiler/Uniform.h
deleted file mode 100644
index 4c53ffa7d..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/Uniform.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// 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.
-//
-
-#ifndef COMPILER_UNIFORM_H_
-#define COMPILER_UNIFORM_H_
-
-#include <string>
-#include <vector>
-
-#define GL_APICALL
-#include <GLES2/gl2.h>
-
-namespace sh
-{
-
-struct Uniform
-{
- Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex);
-
- GLenum type;
- GLenum precision;
- std::string name;
- unsigned int arraySize;
-
- int registerIndex;
-};
-
-typedef std::vector<Uniform> ActiveUniforms;
-
-}
-
-#endif // COMPILER_UNIFORM_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp
deleted file mode 100644
index 64969c489..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp
+++ /dev/null
@@ -1,512 +0,0 @@
-//
-// 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/ValidateLimitations.h"
-#include "compiler/InfoSink.h"
-#include "compiler/InitializeParseContext.h"
-#include "compiler/ParseContext.h"
-
-namespace {
-bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) {
- for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) {
- if (i->index.id == symbol->getId())
- return true;
- }
- return false;
-}
-
-void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
- for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
- if (i->index.id == symbol->getId()) {
- ASSERT(i->loop != NULL);
- i->loop->setUnrollFlag(true);
- return;
- }
- }
- UNREACHABLE();
-}
-
-// 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 TLoopStack& stack)
- : mValid(true), mLoopStack(stack) {}
-
- // Returns true if the parsed node represents a constant index expression.
- bool isValid() const { return mValid; }
-
- virtual void visitSymbol(TIntermSymbol* symbol) {
- // Only constants and loop indices are allowed in a
- // constant index expression.
- if (mValid) {
- mValid = (symbol->getQualifier() == EvqConst) ||
- IsLoopIndex(symbol, mLoopStack);
- }
- }
-
-private:
- bool mValid;
- const TLoopStack& mLoopStack;
-};
-
-// Traverses a node to check if it uses a loop index.
-// If an int loop index is used in its body as a sampler array index,
-// mark the loop for unroll.
-class ValidateLoopIndexExpr : public TIntermTraverser {
-public:
- ValidateLoopIndexExpr(TLoopStack& stack)
- : mUsesFloatLoopIndex(false),
- mUsesIntLoopIndex(false),
- mLoopStack(stack) {}
-
- bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
- bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
-
- virtual void visitSymbol(TIntermSymbol* symbol) {
- if (IsLoopIndex(symbol, mLoopStack)) {
- switch (symbol->getBasicType()) {
- case EbtFloat:
- mUsesFloatLoopIndex = true;
- break;
- case EbtInt:
- mUsesIntLoopIndex = true;
- MarkLoopForUnroll(symbol, mLoopStack);
- break;
- default:
- UNREACHABLE();
- }
- }
- }
-
-private:
- bool mUsesFloatLoopIndex;
- bool mUsesIntLoopIndex;
- TLoopStack& mLoopStack;
-};
-} // namespace
-
-ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
- TInfoSinkBase& sink)
- : mShaderType(shaderType),
- mSink(sink),
- mNumErrors(0)
-{
-}
-
-bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node)
-{
- // Check if loop index is modified in the loop body.
- validateOperation(node, node->getLeft());
-
- // Check indexing.
- switch (node->getOp()) {
- case EOpIndexDirect:
- validateIndexing(node);
- break;
- case EOpIndexIndirect:
-#if defined(__APPLE__)
- // Loop unrolling is a work-around for a Mac Cg compiler bug where it
- // crashes when a sampler array's index is also the loop index.
- // Once Apple fixes this bug, we should remove the code in this CL.
- // See http://codereview.appspot.com/4331048/.
- if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
- (node->getLeft()->getAsSymbolNode())) {
- TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
- if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
- ValidateLoopIndexExpr validate(mLoopStack);
- node->getRight()->traverse(&validate);
- if (validate.usesFloatLoopIndex()) {
- error(node->getLine(),
- "sampler array index is float loop index",
- "for");
- }
- }
- }
-#endif
- validateIndexing(node);
- break;
- default: break;
- }
- return true;
-}
-
-bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node)
-{
- // Check if loop index is modified in the loop body.
- validateOperation(node, node->getOperand());
-
- return true;
-}
-
-bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node)
-{
- switch (node->getOp()) {
- case EOpFunctionCall:
- validateFunctionCall(node);
- break;
- default:
- break;
- }
- return true;
-}
-
-bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node)
-{
- if (!validateLoopType(node))
- return false;
-
- TLoopInfo info;
- memset(&info, 0, sizeof(TLoopInfo));
- info.loop = node;
- if (!validateForLoopHeader(node, &info))
- return false;
-
- TIntermNode* body = node->getBody();
- if (body != NULL) {
- mLoopStack.push_back(info);
- body->traverse(this);
- mLoopStack.pop_back();
- }
-
- // The loop is fully processed - no need to visit children.
- return false;
-}
-
-void ValidateLimitations::error(TSourceLoc loc,
- const char *reason, const char* token)
-{
- mSink.prefix(EPrefixError);
- mSink.location(loc);
- mSink << "'" << token << "' : " << reason << "\n";
- ++mNumErrors;
-}
-
-bool ValidateLimitations::withinLoopBody() const
-{
- return !mLoopStack.empty();
-}
-
-bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const
-{
- return IsLoopIndex(symbol, mLoopStack);
-}
-
-bool ValidateLimitations::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 ValidateLimitations::validateForLoopHeader(TIntermLoop* node,
- TLoopInfo* info)
-{
- ASSERT(node->getType() == ELoopFor);
-
- //
- // The for statement has the form:
- // for ( init-declaration ; condition ; expression ) statement
- //
- if (!validateForLoopInit(node, info))
- return false;
- if (!validateForLoopCond(node, info))
- return false;
- if (!validateForLoopExpr(node, info))
- return false;
-
- return true;
-}
-
-bool ValidateLimitations::validateForLoopInit(TIntermLoop* node,
- TLoopInfo* info)
-{
- TIntermNode* init = node->getInit();
- if (init == NULL) {
- error(node->getLine(), "Missing init declaration", "for");
- return false;
- }
-
- //
- // init-declaration has the form:
- // type-specifier identifier = constant-expression
- //
- TIntermAggregate* decl = init->getAsAggregate();
- if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) {
- error(init->getLine(), "Invalid init declaration", "for");
- return false;
- }
- // 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 false;
- }
- TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
- if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) {
- error(decl->getLine(), "Invalid init declaration", "for");
- return false;
- }
- TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
- if (symbol == NULL) {
- error(declInit->getLine(), "Invalid init declaration", "for");
- return false;
- }
- // The loop index has type int or float.
- TBasicType type = symbol->getBasicType();
- if ((type != EbtInt) && (type != EbtFloat)) {
- error(symbol->getLine(),
- "Invalid type for loop index", getBasicString(type));
- return false;
- }
- // 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->getSymbol().c_str());
- return false;
- }
-
- info->index.id = symbol->getId();
- return true;
-}
-
-bool ValidateLimitations::validateForLoopCond(TIntermLoop* node,
- TLoopInfo* info)
-{
- TIntermNode* cond = node->getCondition();
- if (cond == NULL) {
- error(node->getLine(), "Missing condition", "for");
- return false;
- }
- //
- // condition has the form:
- // loop_index relational_operator constant_expression
- //
- TIntermBinary* binOp = cond->getAsBinaryNode();
- if (binOp == NULL) {
- 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 == NULL) {
- error(binOp->getLine(), "Invalid condition", "for");
- return false;
- }
- if (symbol->getId() != info->index.id) {
- error(symbol->getLine(),
- "Expected loop index", symbol->getSymbol().c_str());
- 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->getSymbol().c_str());
- return false;
- }
-
- return true;
-}
-
-bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node,
- TLoopInfo* info)
-{
- TIntermNode* expr = node->getExpression();
- if (expr == NULL) {
- 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 ? NULL : expr->getAsBinaryNode();
-
- TOperator op = EOpNull;
- TIntermSymbol* symbol = NULL;
- if (unOp != NULL) {
- op = unOp->getOp();
- symbol = unOp->getOperand()->getAsSymbolNode();
- } else if (binOp != NULL) {
- op = binOp->getOp();
- symbol = binOp->getLeft()->getAsSymbolNode();
- }
-
- // The operand must be loop index.
- if (symbol == NULL) {
- error(expr->getLine(), "Invalid expression", "for");
- return false;
- }
- if (symbol->getId() != info->index.id) {
- error(symbol->getLine(),
- "Expected loop index", symbol->getSymbol().c_str());
- return false;
- }
-
- // The operator is one of: ++ -- += -=.
- switch (op) {
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- ASSERT((unOp != NULL) && (binOp == NULL));
- break;
- case EOpAddAssign:
- case EOpSubAssign:
- ASSERT((unOp == NULL) && (binOp != NULL));
- break;
- default:
- error(expr->getLine(), "Invalid operator", getOperatorString(op));
- return false;
- }
-
- // Loop index must be incremented/decremented with a constant.
- if (binOp != NULL) {
- if (!isConstExpr(binOp->getRight())) {
- error(binOp->getLine(),
- "Loop index cannot be modified by non-constant expression",
- symbol->getSymbol().c_str());
- return false;
- }
- }
-
- return true;
-}
-
-bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
-{
- ASSERT(node->getOp() == EOpFunctionCall);
-
- // If not within loop body, there is nothing to check.
- if (!withinLoopBody())
- return true;
-
- // List of param indices for which loop indices are used as argument.
- typedef std::vector<size_t> ParamIndex;
- ParamIndex pIndex;
- TIntermSequence& params = node->getSequence();
- for (TIntermSequence::size_type i = 0; i < params.size(); ++i) {
- TIntermSymbol* symbol = params[i]->getAsSymbolNode();
- if (symbol && isLoopIndex(symbol))
- pIndex.push_back(i);
- }
- // If none of the loop indices are used as arguments,
- // there is nothing to check.
- if (pIndex.empty())
- return true;
-
- bool valid = true;
- TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
- TSymbol* symbol = symbolTable.find(node->getName());
- ASSERT(symbol && symbol->isFunction());
- TFunction* function = static_cast<TFunction*>(symbol);
- for (ParamIndex::const_iterator i = pIndex.begin();
- i != pIndex.end(); ++i) {
- const TParameter& param = function->getParam(*i);
- TQualifier qual = param.type->getQualifier();
- if ((qual == EvqOut) || (qual == EvqInOut)) {
- error(params[*i]->getLine(),
- "Loop index cannot be used as argument to a function out or inout parameter",
- params[*i]->getAsSymbolNode()->getSymbol().c_str());
- valid = false;
- }
- }
-
- return valid;
-}
-
-bool ValidateLimitations::validateOperation(TIntermOperator* node,
- TIntermNode* operand) {
- // Check if loop index is modified in the loop body.
- if (!withinLoopBody() || !node->isAssignment())
- return true;
-
- const TIntermSymbol* symbol = operand->getAsSymbolNode();
- if (symbol && isLoopIndex(symbol)) {
- error(node->getLine(),
- "Loop index cannot be statically assigned to within the body of the loop",
- symbol->getSymbol().c_str());
- }
- return true;
-}
-
-bool ValidateLimitations::isConstExpr(TIntermNode* node)
-{
- ASSERT(node != NULL);
- return node->getAsConstantUnion() != NULL;
-}
-
-bool ValidateLimitations::isConstIndexExpr(TIntermNode* node)
-{
- ASSERT(node != NULL);
-
- ValidateConstIndexExpr validate(mLoopStack);
- node->traverse(&validate);
- return validate.isValid();
-}
-
-bool ValidateLimitations::validateIndexing(TIntermBinary* node)
-{
- ASSERT((node->getOp() == EOpIndexDirect) ||
- (node->getOp() == EOpIndexIndirect));
-
- bool valid = true;
- TIntermTyped* index = node->getRight();
- // The index expression must have integral type.
- if (!index->isScalar() || (index->getBasicType() != EbtInt)) {
- error(index->getLine(),
- "Index expression must have integral type",
- index->getCompleteString().c_str());
- valid = false;
- }
- // 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 == SH_VERTEX_SHADER) &&
- (operand->getQualifier() == EvqUniform);
- if (!skip && !isConstIndexExpr(index)) {
- error(index->getLine(), "Index expression must be constant", "[]");
- valid = false;
- }
- return valid;
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h
deleted file mode 100644
index a835cb3c2..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// 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 "GLSLANG/ShaderLang.h"
-#include "compiler/intermediate.h"
-
-class TInfoSinkBase;
-
-struct TLoopInfo {
- struct TIndex {
- int id; // symbol id.
- } index;
- TIntermLoop* loop;
-};
-typedef TVector<TLoopInfo> TLoopStack;
-
-// Traverses intermediate tree to ensure that the shader does not exceed the
-// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
-class ValidateLimitations : public TIntermTraverser {
-public:
- ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink);
-
- int numErrors() const { return mNumErrors; }
-
- virtual bool visitBinary(Visit, TIntermBinary*);
- virtual bool visitUnary(Visit, TIntermUnary*);
- virtual bool visitAggregate(Visit, TIntermAggregate*);
- virtual bool visitLoop(Visit, TIntermLoop*);
-
-private:
- void error(TSourceLoc loc, const char *reason, const char* token);
-
- bool withinLoopBody() const;
- bool isLoopIndex(const TIntermSymbol* symbol) const;
- bool validateLoopType(TIntermLoop* node);
- bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info);
- bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info);
- bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info);
- bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info);
- // Returns true if none of the loop indices is used as the argument to
- // the given function out or inout parameter.
- bool validateFunctionCall(TIntermAggregate* node);
- bool validateOperation(TIntermOperator* node, TIntermNode* operand);
-
- // 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);
-
- ShShaderType mShaderType;
- TInfoSinkBase& mSink;
- int mNumErrors;
- TLoopStack mLoopStack;
-};
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp
deleted file mode 100644
index 34ea4b659..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-//
-// 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/VariableInfo.h"
-
-namespace {
-
-TString arrayBrackets(int index)
-{
- TStringStream stream;
- stream << "[" << index << "]";
- return stream.str();
-}
-
-// Returns the data type for an attribute, uniform, or varying.
-ShDataType getVariableDataType(const TType& type)
-{
- switch (type.getBasicType()) {
- case EbtFloat:
- if (type.isMatrix()) {
- switch (type.getNominalSize()) {
- case 2: return SH_FLOAT_MAT2;
- case 3: return SH_FLOAT_MAT3;
- case 4: return SH_FLOAT_MAT4;
- default: UNREACHABLE();
- }
- } else if (type.isVector()) {
- switch (type.getNominalSize()) {
- case 2: return SH_FLOAT_VEC2;
- case 3: return SH_FLOAT_VEC3;
- case 4: return SH_FLOAT_VEC4;
- default: UNREACHABLE();
- }
- } else {
- return SH_FLOAT;
- }
- case EbtInt:
- if (type.isMatrix()) {
- UNREACHABLE();
- } else if (type.isVector()) {
- switch (type.getNominalSize()) {
- case 2: return SH_INT_VEC2;
- case 3: return SH_INT_VEC3;
- case 4: return SH_INT_VEC4;
- default: UNREACHABLE();
- }
- } else {
- return SH_INT;
- }
- case EbtBool:
- if (type.isMatrix()) {
- UNREACHABLE();
- } else if (type.isVector()) {
- switch (type.getNominalSize()) {
- case 2: return SH_BOOL_VEC2;
- case 3: return SH_BOOL_VEC3;
- case 4: return SH_BOOL_VEC4;
- default: UNREACHABLE();
- }
- } else {
- return SH_BOOL;
- }
- case EbtSampler2D: return SH_SAMPLER_2D;
- case EbtSamplerCube: return SH_SAMPLER_CUBE;
- case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES;
- case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB;
- default: UNREACHABLE();
- }
- return SH_NONE;
-}
-
-void getBuiltInVariableInfo(const TType& type,
- const TString& name,
- const TString& mappedName,
- TVariableInfoList& infoList);
-void getUserDefinedVariableInfo(const TType& type,
- const TString& name,
- const TString& mappedName,
- TVariableInfoList& infoList,
- ShHashFunction64 hashFunction);
-
-// Returns info for an attribute, uniform, or varying.
-void getVariableInfo(const TType& type,
- const TString& name,
- const TString& mappedName,
- TVariableInfoList& infoList,
- ShHashFunction64 hashFunction)
-{
- if (type.getBasicType() == EbtStruct) {
- if (type.isArray()) {
- for (int i = 0; i < type.getArraySize(); ++i) {
- TString lname = name + arrayBrackets(i);
- TString lmappedName = mappedName + arrayBrackets(i);
- getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction);
- }
- } else {
- getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction);
- }
- } else {
- getBuiltInVariableInfo(type, name, mappedName, infoList);
- }
-}
-
-void getBuiltInVariableInfo(const TType& type,
- const TString& name,
- const TString& mappedName,
- TVariableInfoList& infoList)
-{
- ASSERT(type.getBasicType() != EbtStruct);
-
- TVariableInfo varInfo;
- if (type.isArray()) {
- varInfo.name = (name + "[0]").c_str();
- varInfo.mappedName = (mappedName + "[0]").c_str();
- varInfo.size = type.getArraySize();
- } else {
- varInfo.name = name.c_str();
- varInfo.mappedName = mappedName.c_str();
- varInfo.size = 1;
- }
- varInfo.precision = type.getPrecision();
- varInfo.type = getVariableDataType(type);
- infoList.push_back(varInfo);
-}
-
-void getUserDefinedVariableInfo(const TType& type,
- const TString& name,
- const TString& mappedName,
- TVariableInfoList& infoList,
- ShHashFunction64 hashFunction)
-{
- ASSERT(type.getBasicType() == EbtStruct);
-
- const TFieldList& fields = type.getStruct()->fields();
- for (size_t i = 0; i < fields.size(); ++i) {
- const TType& fieldType = *(fields[i]->type());
- const TString& fieldName = fields[i]->name();
- getVariableInfo(fieldType,
- name + "." + fieldName,
- mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction),
- infoList,
- hashFunction);
- }
-}
-
-TVariableInfo* findVariable(const TType& type,
- const TString& name,
- TVariableInfoList& infoList)
-{
- // TODO(zmo): optimize this function.
- TString myName = name;
- if (type.isArray())
- myName += "[0]";
- for (size_t ii = 0; ii < infoList.size(); ++ii)
- {
- if (infoList[ii].name.c_str() == myName)
- return &(infoList[ii]);
- }
- return NULL;
-}
-
-} // namespace anonymous
-
-TVariableInfo::TVariableInfo()
- : type(SH_NONE),
- size(0),
- precision(EbpUndefined),
- staticUse(false)
-{
-}
-
-TVariableInfo::TVariableInfo(ShDataType type, int size)
- : type(type),
- size(size),
- precision(EbpUndefined),
- staticUse(false)
-{
-}
-
-CollectVariables::CollectVariables(TVariableInfoList& attribs,
- TVariableInfoList& uniforms,
- TVariableInfoList& varyings,
- ShHashFunction64 hashFunction)
- : mAttribs(attribs),
- mUniforms(uniforms),
- mVaryings(varyings),
- mPointCoordAdded(false),
- mFrontFacingAdded(false),
- mFragCoordAdded(false),
- mHashFunction(hashFunction)
-{
-}
-
-// We want to check whether a uniform/varying is statically used
-// because we only count the used ones in packing computing.
-// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
-// toward varying counting if they are statically used in a fragment
-// shader.
-void CollectVariables::visitSymbol(TIntermSymbol* symbol)
-{
- ASSERT(symbol != NULL);
- TVariableInfo* var = NULL;
- switch (symbol->getQualifier())
- {
- case EvqVaryingOut:
- case EvqInvariantVaryingOut:
- case EvqVaryingIn:
- case EvqInvariantVaryingIn:
- var = findVariable(symbol->getType(), symbol->getSymbol(), mVaryings);
- break;
- case EvqUniform:
- var = findVariable(symbol->getType(), symbol->getSymbol(), mUniforms);
- break;
- case EvqFragCoord:
- if (!mFragCoordAdded) {
- TVariableInfo info;
- info.name = "gl_FragCoord";
- info.mappedName = "gl_FragCoord";
- info.type = SH_FLOAT_VEC4;
- info.size = 1;
- info.precision = EbpMedium; // Use mediump as it doesn't really matter.
- info.staticUse = true;
- mVaryings.push_back(info);
- mFragCoordAdded = true;
- }
- return;
- case EvqFrontFacing:
- if (!mFrontFacingAdded) {
- TVariableInfo info;
- info.name = "gl_FrontFacing";
- info.mappedName = "gl_FrontFacing";
- info.type = SH_BOOL;
- info.size = 1;
- info.precision = EbpUndefined;
- info.staticUse = true;
- mVaryings.push_back(info);
- mFrontFacingAdded = true;
- }
- return;
- case EvqPointCoord:
- if (!mPointCoordAdded) {
- TVariableInfo info;
- info.name = "gl_PointCoord";
- info.mappedName = "gl_PointCoord";
- info.type = SH_FLOAT_VEC2;
- info.size = 1;
- info.precision = EbpMedium; // Use mediump as it doesn't really matter.
- info.staticUse = true;
- mVaryings.push_back(info);
- mPointCoordAdded = true;
- }
- return;
- default:
- break;
- }
- if (var)
- var->staticUse = true;
-}
-
-bool CollectVariables::visitAggregate(Visit, TIntermAggregate* node)
-{
- bool visitChildren = true;
-
- switch (node->getOp())
- {
- case EOpDeclaration: {
- const TIntermSequence& sequence = node->getSequence();
- TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
- if (qualifier == EvqAttribute || qualifier == EvqUniform ||
- qualifier == EvqVaryingIn || qualifier == EvqVaryingOut ||
- qualifier == EvqInvariantVaryingIn || qualifier == EvqInvariantVaryingOut)
- {
- TVariableInfoList& infoList = qualifier == EvqAttribute ? mAttribs :
- (qualifier == EvqUniform ? mUniforms : mVaryings);
- for (TIntermSequence::const_iterator i = sequence.begin();
- i != sequence.end(); ++i)
- {
- const TIntermSymbol* variable = (*i)->getAsSymbolNode();
- // 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,
- // and varyings cannot be initialized in a shader, we must have
- // only TIntermSymbol nodes in the sequence.
- ASSERT(variable != NULL);
- TString processedSymbol;
- if (mHashFunction == NULL)
- processedSymbol = variable->getSymbol();
- else
- processedSymbol = TIntermTraverser::hash(variable->getOriginalSymbol(), mHashFunction);
- getVariableInfo(variable->getType(),
- variable->getOriginalSymbol(),
- processedSymbol,
- infoList,
- mHashFunction);
- visitChildren = false;
- }
- }
- break;
- }
- default: break;
- }
-
- return visitChildren;
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h
deleted file mode 100644
index 3c7f2a5f8..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// 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_VARIABLE_INFO_H_
-#define COMPILER_VARIABLE_INFO_H_
-
-#include "GLSLANG/ShaderLang.h"
-#include "compiler/intermediate.h"
-
-// Provides information about a variable.
-// It is currently being used to store info about active attribs and uniforms.
-struct TVariableInfo {
- TVariableInfo(ShDataType type, int size);
- TVariableInfo();
-
- TPersistString name;
- TPersistString mappedName;
- ShDataType type;
- int size;
- TPrecision precision;
- bool staticUse;
-};
-typedef std::vector<TVariableInfo> TVariableInfoList;
-
-// Traverses intermediate tree to collect all attributes, uniforms, varyings.
-class CollectVariables : public TIntermTraverser {
-public:
- CollectVariables(TVariableInfoList& attribs,
- TVariableInfoList& uniforms,
- TVariableInfoList& varyings,
- ShHashFunction64 hashFunction);
-
- virtual void visitSymbol(TIntermSymbol*);
- virtual bool visitAggregate(Visit, TIntermAggregate*);
-
-private:
- TVariableInfoList& mAttribs;
- TVariableInfoList& mUniforms;
- TVariableInfoList& mVaryings;
-
- bool mPointCoordAdded;
- bool mFrontFacingAdded;
- bool mFragCoordAdded;
-
- ShHashFunction64 mHashFunction;
-};
-
-#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariablePacker.h b/Source/ThirdParty/ANGLE/src/compiler/VariablePacker.h
deleted file mode 100644
index 8987066cc..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/VariablePacker.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// 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 _VARIABLEPACKER_INCLUDED_
-#define _VARIABLEPACKER_INCLUDED_
-
-#include <vector>
-#include "compiler/ShHandle.h"
-
-class VariablePacker {
- public:
- // Returns true if the passed in variables pack in maxVectors following
- // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
- bool CheckVariablesWithinPackingLimits(
- int maxVectors,
- const TVariableInfoList& in_variables);
-
- // Gets how many components in a row a data type takes.
- static int GetNumComponentsPerRow(ShDataType type);
-
- // Gets how many rows a data type takes.
- static int GetNumRows(ShDataType type);
-
- 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_;
-};
-
-#endif // _VARIABLEPACKER_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp
deleted file mode 100644
index 7a82bb4dc..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// 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/VersionGLSL.h"
-
-static const int GLSL_VERSION_110 = 110;
-static const int GLSL_VERSION_120 = 120;
-
-// 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."
-//
-// TODO(alokp): The following two cases of invariant decalaration get lost
-// during parsing - they do not get carried over to the intermediate tree.
-// Handle these cases:
-// 1. When a pragma is used to force all output variables to be invariant:
-// - #pragma STDGL invariant(all)
-// 2. When a previously decalared or built-in variable is marked invariant:
-// - invariant gl_Position;
-// - varying vec3 color; invariant color;
-//
-TVersionGLSL::TVersionGLSL(ShShaderType type)
- : mShaderType(type),
- mVersion(GLSL_VERSION_110)
-{
-}
-
-void TVersionGLSL::visitSymbol(TIntermSymbol* node)
-{
- if (node->getSymbol() == "gl_PointCoord")
- updateVersion(GLSL_VERSION_120);
-}
-
-void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*)
-{
-}
-
-bool TVersionGLSL::visitBinary(Visit, TIntermBinary*)
-{
- return true;
-}
-
-bool TVersionGLSL::visitUnary(Visit, TIntermUnary*)
-{
- return true;
-}
-
-bool TVersionGLSL::visitSelection(Visit, TIntermSelection*)
-{
- return true;
-}
-
-bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node)
-{
- bool visitChildren = true;
-
- switch (node->getOp()) {
- case EOpSequence:
- // We need to visit sequence children to get to global or inner scope.
- visitChildren = true;
- break;
- case EOpDeclaration: {
- const TIntermSequence& sequence = node->getSequence();
- TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
- if ((qualifier == EvqInvariantVaryingIn) ||
- (qualifier == EvqInvariantVaryingOut)) {
- updateVersion(GLSL_VERSION_120);
- }
- break;
- }
- case EOpParameters: {
- const TIntermSequence& params = node->getSequence();
- for (TIntermSequence::const_iterator iter = params.begin();
- iter != params.end(); ++iter)
- {
- const TIntermTyped* param = (*iter)->getAsTyped();
- if (param->isArray())
- {
- TQualifier qualifier = param->getQualifier();
- if ((qualifier == EvqOut) || (qualifier == EvqInOut))
- {
- updateVersion(GLSL_VERSION_120);
- break;
- }
- }
- }
- // Fully processed. No need to visit children.
- visitChildren = false;
- break;
- }
- case EOpConstructMat2:
- case EOpConstructMat3:
- case EOpConstructMat4: {
- const TIntermSequence& sequence = node->getSequence();
- if (sequence.size() == 1) {
- TIntermTyped* typed = sequence.front()->getAsTyped();
- if (typed && typed->isMatrix()) {
- updateVersion(GLSL_VERSION_120);
- }
- }
- break;
- }
-
- default: break;
- }
-
- return visitChildren;
-}
-
-bool TVersionGLSL::visitLoop(Visit, TIntermLoop*)
-{
- return true;
-}
-
-bool TVersionGLSL::visitBranch(Visit, TIntermBranch*)
-{
- return true;
-}
-
-void TVersionGLSL::updateVersion(int version)
-{
- mVersion = std::max(version, mVersion);
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h
deleted file mode 100644
index 1c1cb1ab9..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// 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_VERSIONGLSL_H_
-#define COMPILER_VERSIONGLSL_H_
-
-#include "GLSLANG/ShaderLang.h"
-#include "compiler/intermediate.h"
-
-// 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
-//
-class TVersionGLSL : public TIntermTraverser {
-public:
- TVersionGLSL(ShShaderType type);
-
- // Returns 120 if the following is used the shader:
- // - "invariant",
- // - "gl_PointCoord",
- // - matrix/matrix constructors
- // - array "out" parameters
- // Else 110 is returned.
- int getVersion() { return mVersion; }
-
- virtual void visitSymbol(TIntermSymbol*);
- virtual void visitConstantUnion(TIntermConstantUnion*);
- virtual bool visitBinary(Visit, TIntermBinary*);
- virtual bool visitUnary(Visit, TIntermUnary*);
- virtual bool visitSelection(Visit, TIntermSelection*);
- virtual bool visitAggregate(Visit, TIntermAggregate*);
- virtual bool visitLoop(Visit, TIntermLoop*);
- virtual bool visitBranch(Visit, TIntermBranch*);
-
-protected:
- void updateVersion(int version);
-
-private:
- ShShaderType mShaderType;
- int mVersion;
-};
-
-#endif // COMPILER_VERSIONGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/debug.cpp b/Source/ThirdParty/ANGLE/src/compiler/debug.cpp
deleted file mode 100644
index 38d55acaf..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/debug.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// 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.
-//
-
-// debug.cpp: Debugging utilities.
-
-#include "compiler/debug.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "compiler/InitializeParseContext.h"
-#include "compiler/ParseContext.h"
-
-#ifdef TRACE_ENABLED
-static const int kTraceBufferLen = 1024;
-
-extern "C" {
-void Trace(const char *format, ...) {
- if (!format) return;
-
- TParseContext* parseContext = GetGlobalParseContext();
- if (parseContext) {
- char buf[kTraceBufferLen];
- va_list args;
- va_start(args, format);
- vsnprintf(buf, kTraceBufferLen, format, args);
- va_end(args);
-
- parseContext->trace(buf);
- }
-}
-} // extern "C"
-#endif // TRACE_ENABLED
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/debug.h b/Source/ThirdParty/ANGLE/src/compiler/debug.h
deleted file mode 100644
index 7a371516a..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/debug.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// 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.
-//
-
-// debug.h: Debugging utilities.
-
-#ifndef COMPILER_DEBUG_H_
-#define COMPILER_DEBUG_H_
-
-#include <assert.h>
-
-#ifdef _DEBUG
-#define TRACE_ENABLED // define to enable debug message tracing
-#endif // _DEBUG
-
-// Outputs text to the debug log
-#ifdef TRACE_ENABLED
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-void Trace(const char* format, ...);
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#else // TRACE_ENABLED
-
-#define Trace(...) ((void)0)
-
-#endif // TRACE_ENABLED
-
-// A macro asserting a condition and outputting failures to the debug log
-#define ASSERT(expression) do { \
- if(!(expression)) \
- Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
- assert(expression); \
-} while(0)
-
-#define UNIMPLEMENTED() do { \
- Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \
- assert(false); \
-} while(0)
-
-#define UNREACHABLE() do { \
- Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
- assert(false); \
-} while(0)
-
-#endif // COMPILER_DEBUG_H_
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.cpp b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.cpp
deleted file mode 100644
index ca661d676..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// 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.
-//
-
-#pragma warning(disable: 4718)
-
-#include "compiler/depgraph/DependencyGraph.h"
-#include "compiler/depgraph/DependencyGraphBuilder.h"
-
-TDependencyGraph::TDependencyGraph(TIntermNode* intermNode)
-{
- TDependencyGraphBuilder::build(intermNode, this);
-}
-
-TDependencyGraph::~TDependencyGraph()
-{
- for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter)
- {
- TGraphNode* node = *iter;
- delete node;
- }
-}
-
-TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall,
- int argumentNumber)
-{
- TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber);
- mAllNodes.push_back(argument);
- return argument;
-}
-
-TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall)
-{
- TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall);
- mAllNodes.push_back(functionCall);
- if (functionCall->getIntermFunctionCall()->isUserDefined())
- mUserDefinedFunctionCalls.push_back(functionCall);
- return functionCall;
-}
-
-TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol)
-{
- TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId());
-
- TGraphSymbol* symbol = NULL;
-
- if (iter != mSymbolIdMap.end()) {
- TSymbolIdPair pair = *iter;
- symbol = pair.second;
- } else {
- symbol = new TGraphSymbol(intermSymbol);
- mAllNodes.push_back(symbol);
-
- TSymbolIdPair pair(intermSymbol->getId(), symbol);
- mSymbolIdMap.insert(pair);
-
- // We save all sampler symbols in a collection, so we can start graph traversals from them quickly.
- if (IsSampler(intermSymbol->getBasicType()))
- mSamplerSymbols.push_back(symbol);
- }
-
- return symbol;
-}
-
-TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection)
-{
- TGraphSelection* selection = new TGraphSelection(intermSelection);
- mAllNodes.push_back(selection);
- return selection;
-}
-
-TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop)
-{
- TGraphLoop* loop = new TGraphLoop(intermLoop);
- mAllNodes.push_back(loop);
- return loop;
-}
-
-TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp)
-{
- TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp);
- mAllNodes.push_back(logicalOp);
- return logicalOp;
-}
-
-const char* TGraphLogicalOp::getOpString() const
-{
- const char* opString = NULL;
- switch (getIntermLogicalOp()->getOp()) {
- case EOpLogicalAnd: opString = "and"; break;
- case EOpLogicalOr: opString = "or"; break;
- default: opString = "unknown"; break;
- }
- return opString;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.h b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.h
deleted file mode 100644
index 5a9c35d00..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraph.h
+++ /dev/null
@@ -1,212 +0,0 @@
-//
-// 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_DEPGRAPH_DEPENDENCY_GRAPH_H
-#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
-
-#include "compiler/intermediate.h"
-
-#include <set>
-#include <stack>
-
-class TGraphNode;
-class TGraphParentNode;
-class TGraphArgument;
-class TGraphFunctionCall;
-class TGraphSymbol;
-class TGraphSelection;
-class TGraphLoop;
-class TGraphLogicalOp;
-class TDependencyGraphTraverser;
-class TDependencyGraphOutput;
-
-typedef std::set<TGraphNode*> TGraphNodeSet;
-typedef std::vector<TGraphNode*> TGraphNodeVector;
-typedef std::vector<TGraphSymbol*> TGraphSymbolVector;
-typedef std::vector<TGraphFunctionCall*> TFunctionCallVector;
-
-//
-// Base class for all dependency graph nodes.
-//
-class TGraphNode {
-public:
- TGraphNode(TIntermNode* node) : intermNode(node) {}
- virtual ~TGraphNode() {}
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-protected:
- TIntermNode* intermNode;
-};
-
-//
-// Base class for dependency graph nodes that may have children.
-//
-class TGraphParentNode : public TGraphNode {
-public:
- TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
- virtual ~TGraphParentNode() {}
- void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-private:
- TGraphNodeSet mDependentNodes;
-};
-
-//
-// Handle function call arguments.
-//
-class TGraphArgument : public TGraphParentNode {
-public:
- TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
- : TGraphParentNode(intermFunctionCall)
- , mArgumentNumber(argumentNumber) {}
- virtual ~TGraphArgument() {}
- const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
- int getArgumentNumber() const { return mArgumentNumber; }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-private:
- int mArgumentNumber;
-};
-
-//
-// Handle function calls.
-//
-class TGraphFunctionCall : public TGraphParentNode {
-public:
- TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
- : TGraphParentNode(intermFunctionCall) {}
- virtual ~TGraphFunctionCall() {}
- const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-};
-
-//
-// Handle symbols.
-//
-class TGraphSymbol : public TGraphParentNode {
-public:
- TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
- virtual ~TGraphSymbol() {}
- const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-};
-
-//
-// Handle if statements and ternary operators.
-//
-class TGraphSelection : public TGraphNode {
-public:
- TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
- virtual ~TGraphSelection() {}
- const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-};
-
-//
-// Handle for, do-while, and while loops.
-//
-class TGraphLoop : public TGraphNode {
-public:
- TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
- virtual ~TGraphLoop() {}
- const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-};
-
-//
-// Handle logical and, or.
-//
-class TGraphLogicalOp : public TGraphNode {
-public:
- TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
- virtual ~TGraphLogicalOp() {}
- const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
- const char* getOpString() const;
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
-};
-
-//
-// A dependency graph of symbols, function calls, conditions etc.
-//
-// This class provides an interface to the entry points of the dependency graph.
-//
-// Dependency graph nodes should be created by using one of the provided "create..." methods.
-// This class (and nobody else) manages the memory of the created nodes.
-// Nodes may not be removed after being added, so all created nodes will exist while the
-// TDependencyGraph instance exists.
-//
-class TDependencyGraph {
-public:
- TDependencyGraph(TIntermNode* intermNode);
- ~TDependencyGraph();
- TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); }
- TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); }
-
- TGraphSymbolVector::const_iterator beginSamplerSymbols() const
- {
- return mSamplerSymbols.begin();
- }
-
- TGraphSymbolVector::const_iterator endSamplerSymbols() const
- {
- return mSamplerSymbols.end();
- }
-
- TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const
- {
- return mUserDefinedFunctionCalls.begin();
- }
-
- TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const
- {
- return mUserDefinedFunctionCalls.end();
- }
-
- TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
- TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall);
- TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol);
- TGraphSelection* createSelection(TIntermSelection* intermSelection);
- TGraphLoop* createLoop(TIntermLoop* intermLoop);
- TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp);
-private:
- typedef TMap<int, TGraphSymbol*> TSymbolIdMap;
- typedef std::pair<int, TGraphSymbol*> TSymbolIdPair;
-
- TGraphNodeVector mAllNodes;
- TGraphSymbolVector mSamplerSymbols;
- TFunctionCallVector mUserDefinedFunctionCalls;
- TSymbolIdMap mSymbolIdMap;
-};
-
-//
-// For traversing the dependency graph. Users should derive from this,
-// put their traversal specific data in it, and then pass it to a
-// traverse method.
-//
-// When using this, just fill in the methods for nodes you want visited.
-//
-class TDependencyGraphTraverser {
-public:
- TDependencyGraphTraverser() : mDepth(0) {}
-
- virtual void visitSymbol(TGraphSymbol* symbol) {};
- virtual void visitArgument(TGraphArgument* selection) {};
- virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {};
- virtual void visitSelection(TGraphSelection* selection) {};
- virtual void visitLoop(TGraphLoop* loop) {};
- virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {};
-
- int getDepth() const { return mDepth; }
- void incrementDepth() { ++mDepth; }
- void decrementDepth() { --mDepth; }
-
- void clearVisited() { mVisited.clear(); }
- void markVisited(TGraphNode* node) { mVisited.insert(node); }
- bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); }
-private:
- int mDepth;
- TGraphNodeSet mVisited;
-};
-
-#endif
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.cpp b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.cpp
deleted file mode 100644
index 026e6d57a..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/depgraph/DependencyGraphBuilder.h"
-
-void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph)
-{
- TDependencyGraphBuilder builder(graph);
- builder.build(node);
-}
-
-bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate)
-{
- switch (intermAggregate->getOp()) {
- case EOpFunction: visitFunctionDefinition(intermAggregate); break;
- case EOpFunctionCall: visitFunctionCall(intermAggregate); break;
- default: visitAggregateChildren(intermAggregate); break;
- }
-
- return false;
-}
-
-void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate)
-{
- // Currently, we do not support user defined functions.
- if (intermAggregate->getName() != "main(")
- return;
-
- visitAggregateChildren(intermAggregate);
-}
-
-// Takes an expression like "f(x)" and creates a dependency graph like
-// "x -> argument 0 -> function call".
-void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall)
-{
- TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall);
-
- // Run through the function call arguments.
- int argumentNumber = 0;
- TIntermSequence& intermArguments = intermFunctionCall->getSequence();
- for (TIntermSequence::const_iterator iter = intermArguments.begin();
- iter != intermArguments.end();
- ++iter, ++argumentNumber)
- {
- TNodeSetMaintainer nodeSetMaintainer(this);
-
- TIntermNode* intermArgument = *iter;
- intermArgument->traverse(this);
-
- if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) {
- TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber);
- connectMultipleNodesToSingleNode(argumentNodes, argument);
- argument->addDependentNode(functionCall);
- }
- }
-
- // Push the leftmost symbol of this function call into the current set of dependent symbols to
- // represent the result of this function call.
- // Thus, an expression like "y = f(x)" will yield a dependency graph like
- // "x -> argument 0 -> function call -> y".
- // This line essentially passes the function call node back up to an earlier visitAssignment
- // call, which will create the connection "function call -> y".
- mNodeSets.insertIntoTopSet(functionCall);
-}
-
-void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate)
-{
- TIntermSequence& sequence = intermAggregate->getSequence();
- for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
- {
- TIntermNode* intermChild = *iter;
- intermChild->traverse(this);
- }
-}
-
-void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
-{
- // Push this symbol into the set of dependent symbols for the current assignment or condition
- // that we are traversing.
- TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol);
- mNodeSets.insertIntoTopSet(symbol);
-
- // If this symbol is the current leftmost symbol under an assignment, replace the previous
- // leftmost symbol with this symbol.
- if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) {
- mLeftmostSymbols.pop();
- mLeftmostSymbols.push(symbol);
- }
-}
-
-bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
-{
- TOperator op = intermBinary->getOp();
- if (op == EOpInitialize || intermBinary->isAssignment())
- visitAssignment(intermBinary);
- else if (op == EOpLogicalAnd || op == EOpLogicalOr)
- visitLogicalOp(intermBinary);
- else
- visitBinaryChildren(intermBinary);
-
- return false;
-}
-
-void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment)
-{
- TIntermTyped* intermLeft = intermAssignment->getLeft();
- if (!intermLeft)
- return;
-
- TGraphSymbol* leftmostSymbol = NULL;
-
- {
- TNodeSetMaintainer nodeSetMaintainer(this);
-
- {
- TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree);
- intermLeft->traverse(this);
- leftmostSymbol = mLeftmostSymbols.top();
-
- // After traversing the left subtree of this assignment, we should have found a real
- // leftmost symbol, and the leftmost symbol should not be a placeholder.
- ASSERT(leftmostSymbol != &mLeftSubtree);
- ASSERT(leftmostSymbol != &mRightSubtree);
- }
-
- if (TIntermTyped* intermRight = intermAssignment->getRight()) {
- TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
- intermRight->traverse(this);
- }
-
- if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet())
- connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
- }
-
- // Push the leftmost symbol of this assignment into the current set of dependent symbols to
- // represent the result of this assignment.
- // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a".
- // This line essentially passes the leftmost symbol of the nested assignment ("b" in this
- // example) back up to the earlier visitAssignment call for the outer assignment, which will
- // create the connection "b -> a".
- mNodeSets.insertIntoTopSet(leftmostSymbol);
-}
-
-void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp)
-{
- if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) {
- TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
-
- intermLeft->traverse(this);
- if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) {
- TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp);
- connectMultipleNodesToSingleNode(leftNodes, logicalOp);
- }
- }
-
- if (TIntermTyped* intermRight = intermLogicalOp->getRight()) {
- TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
- intermRight->traverse(this);
- }
-}
-
-void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary)
-{
- if (TIntermTyped* intermLeft = intermBinary->getLeft())
- intermLeft->traverse(this);
-
- if (TIntermTyped* intermRight = intermBinary->getRight()) {
- TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
- intermRight->traverse(this);
- }
-}
-
-bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection)
-{
- if (TIntermNode* intermCondition = intermSelection->getCondition()) {
- TNodeSetMaintainer nodeSetMaintainer(this);
-
- intermCondition->traverse(this);
- if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
- TGraphSelection* selection = mGraph->createSelection(intermSelection);
- connectMultipleNodesToSingleNode(conditionNodes, selection);
- }
- }
-
- if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock())
- intermTrueBlock->traverse(this);
-
- if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock())
- intermFalseBlock->traverse(this);
-
- return false;
-}
-
-bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop)
-{
- if (TIntermTyped* intermCondition = intermLoop->getCondition()) {
- TNodeSetMaintainer nodeSetMaintainer(this);
-
- intermCondition->traverse(this);
- if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
- TGraphLoop* loop = mGraph->createLoop(intermLoop);
- connectMultipleNodesToSingleNode(conditionNodes, loop);
- }
- }
-
- if (TIntermNode* intermBody = intermLoop->getBody())
- intermBody->traverse(this);
-
- if (TIntermTyped* intermExpression = intermLoop->getExpression())
- intermExpression->traverse(this);
-
- return false;
-}
-
-
-void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes,
- TGraphNode* node) const
-{
- for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter)
- {
- TGraphParentNode* currentNode = *iter;
- currentNode->addDependentNode(node);
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.h b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.h
deleted file mode 100644
index c5f232cb2..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphBuilder.h
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// 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_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
-#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
-
-#include "compiler/depgraph/DependencyGraph.h"
-
-//
-// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a
-// intermediate tree.
-//
-class TDependencyGraphBuilder : public TIntermTraverser {
-public:
- static void build(TIntermNode* node, TDependencyGraph* graph);
-
- virtual void visitSymbol(TIntermSymbol*);
- virtual bool visitBinary(Visit visit, TIntermBinary*);
- virtual bool visitSelection(Visit visit, TIntermSelection*);
- virtual bool visitAggregate(Visit visit, TIntermAggregate*);
- virtual bool visitLoop(Visit visit, TIntermLoop*);
-
-private:
- typedef std::stack<TGraphSymbol*> TSymbolStack;
- typedef std::set<TGraphParentNode*> TParentNodeSet;
-
- //
- // For collecting the dependent nodes of assignments, conditions, etc.
- // while traversing the intermediate tree.
- //
- // This data structure is stack of sets. Each set contains dependency graph parent nodes.
- //
- class TNodeSetStack {
- public:
- TNodeSetStack() {};
- ~TNodeSetStack() { clear(); }
-
- // This should only be called after a pushSet.
- // Returns NULL if the top set is empty.
- TParentNodeSet* getTopSet() const
- {
- ASSERT(!nodeSets.empty());
- TParentNodeSet* topSet = nodeSets.top();
- return !topSet->empty() ? topSet : NULL;
- }
-
- void pushSet() { nodeSets.push(new TParentNodeSet()); }
- void popSet()
- {
- ASSERT(!nodeSets.empty());
- delete nodeSets.top();
- nodeSets.pop();
- }
-
- // Pops the top set and adds its contents to the new top set.
- // This should only be called after a pushSet.
- // If there is no set below the top set, the top set is just deleted.
- void popSetIntoNext()
- {
- ASSERT(!nodeSets.empty());
- TParentNodeSet* oldTopSet = nodeSets.top();
- nodeSets.pop();
-
- if (!nodeSets.empty()) {
- TParentNodeSet* newTopSet = nodeSets.top();
- newTopSet->insert(oldTopSet->begin(), oldTopSet->end());
- }
-
- delete oldTopSet;
- }
-
- // Does nothing if there is no top set.
- // This can be called when there is no top set if we are visiting
- // symbols that are not under an assignment or condition.
- // We don't need to track those symbols.
- void insertIntoTopSet(TGraphParentNode* node)
- {
- if (nodeSets.empty())
- return;
-
- nodeSets.top()->insert(node);
- }
-
- void clear()
- {
- while (!nodeSets.empty())
- popSet();
- }
-
- private:
- typedef std::stack<TParentNodeSet*> TParentNodeSetStack;
-
- TParentNodeSetStack nodeSets;
- };
-
- //
- // An instance of this class pushes a new node set when instantiated.
- // When the instance goes out of scope, it and pops the node set.
- //
- class TNodeSetMaintainer {
- public:
- TNodeSetMaintainer(TDependencyGraphBuilder* factory)
- : sets(factory->mNodeSets) { sets.pushSet(); }
- ~TNodeSetMaintainer() { sets.popSet(); }
- protected:
- TNodeSetStack& sets;
- };
-
- //
- // An instance of this class pushes a new node set when instantiated.
- // When the instance goes out of scope, it and pops the top node set and adds its contents to
- // the new top node set.
- //
- class TNodeSetPropagatingMaintainer {
- public:
- TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory)
- : sets(factory->mNodeSets) { sets.pushSet(); }
- ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); }
- protected:
- TNodeSetStack& sets;
- };
-
- //
- // An instance of this class keeps track of the leftmost symbol while we're exploring an
- // assignment.
- // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree,
- // and kRightSubtree under a right subtree.
- // When it goes out of scope, it will pop the leftmost symbol at the top of the scope.
- // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol.
- // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost
- // symbol.
- //
- class TLeftmostSymbolMaintainer {
- public:
- TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree)
- : leftmostSymbols(factory->mLeftmostSymbols)
- {
- needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree;
- if (needsPlaceholderSymbol)
- leftmostSymbols.push(&subtree);
- }
-
- ~TLeftmostSymbolMaintainer()
- {
- if (needsPlaceholderSymbol)
- leftmostSymbols.pop();
- }
-
- protected:
- TSymbolStack& leftmostSymbols;
- bool needsPlaceholderSymbol;
- };
-
- TDependencyGraphBuilder(TDependencyGraph* graph)
- : TIntermTraverser(true, false, false)
- , mLeftSubtree(NULL)
- , mRightSubtree(NULL)
- , mGraph(graph) {}
- void build(TIntermNode* intermNode) { intermNode->traverse(this); }
-
- void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const;
-
- void visitAssignment(TIntermBinary*);
- void visitLogicalOp(TIntermBinary*);
- void visitBinaryChildren(TIntermBinary*);
- void visitFunctionDefinition(TIntermAggregate*);
- void visitFunctionCall(TIntermAggregate* intermFunctionCall);
- void visitAggregateChildren(TIntermAggregate*);
-
- TGraphSymbol mLeftSubtree;
- TGraphSymbol mRightSubtree;
-
- TDependencyGraph* mGraph;
- TNodeSetStack mNodeSets;
- TSymbolStack mLeftmostSymbols;
-};
-
-#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.cpp b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.cpp
deleted file mode 100644
index 6fc489e7b..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/depgraph/DependencyGraphOutput.h"
-
-void TDependencyGraphOutput::outputIndentation()
-{
- for (int i = 0; i < getDepth(); ++i)
- mSink << " ";
-}
-
-void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter)
-{
- outputIndentation();
- mSink << "argument " << parameter->getArgumentNumber() << " of call to "
- << parameter->getIntermFunctionCall()->getName() << "\n";
-}
-
-void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall)
-{
- outputIndentation();
- mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n";
-}
-
-void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol)
-{
- outputIndentation();
- mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: "
- << symbol->getIntermSymbol()->getId() << ")\n";
-}
-
-void TDependencyGraphOutput::visitSelection(TGraphSelection* selection)
-{
- outputIndentation();
- mSink << "selection\n";
-}
-
-void TDependencyGraphOutput::visitLoop(TGraphLoop* loop)
-{
- outputIndentation();
- mSink << "loop condition\n";
-}
-
-void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp)
-{
- outputIndentation();
- mSink << "logical " << logicalOp->getOpString() << "\n";
-}
-
-void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
-{
- mSink << "\n";
-
- for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter)
- {
- TGraphNode* symbol = *iter;
- mSink << "--- Dependency graph spanning tree ---\n";
- clearVisited();
- symbol->traverse(this);
- mSink << "\n";
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.h b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.h
deleted file mode 100644
index 01447da98..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphOutput.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// 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_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
-#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
-
-#include "compiler/depgraph/DependencyGraph.h"
-#include "compiler/InfoSink.h"
-
-class TDependencyGraphOutput : public TDependencyGraphTraverser {
-public:
- TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
- virtual void visitSymbol(TGraphSymbol* symbol);
- virtual void visitArgument(TGraphArgument* parameter);
- virtual void visitFunctionCall(TGraphFunctionCall* functionCall);
- virtual void visitSelection(TGraphSelection* selection);
- virtual void visitLoop(TGraphLoop* loop);
- virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
-
- void outputAllSpanningTrees(TDependencyGraph& graph);
-private:
- void outputIndentation();
-
- TInfoSinkBase& mSink;
-};
-
-#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphTraverse.cpp b/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphTraverse.cpp
deleted file mode 100644
index b158575ce..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/depgraph/DependencyGraphTraverse.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/depgraph/DependencyGraph.h"
-
-// These methods do a breadth-first traversal through the graph and mark visited nodes.
-
-void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->markVisited(this);
-}
-
-void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- TGraphNode::traverse(graphTraverser);
-
- graphTraverser->incrementDepth();
-
- // Visit the parent node's children.
- for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin();
- iter != mDependentNodes.end();
- ++iter)
- {
- TGraphNode* node = *iter;
- if (!graphTraverser->isVisited(node))
- node->traverse(graphTraverser);
- }
-
- graphTraverser->decrementDepth();
-}
-
-void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitArgument(this);
- TGraphParentNode::traverse(graphTraverser);
-}
-
-void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitFunctionCall(this);
- TGraphParentNode::traverse(graphTraverser);
-}
-
-void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitSymbol(this);
- TGraphParentNode::traverse(graphTraverser);
-}
-
-void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitSelection(this);
- TGraphNode::traverse(graphTraverser);
-}
-
-void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitLoop(this);
- TGraphNode::traverse(graphTraverser);
-}
-
-void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser)
-{
- graphTraverser->visitLogicalOp(this);
- TGraphNode::traverse(graphTraverser);
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/fuzz/translator_fuzzer.cpp b/Source/ThirdParty/ANGLE/src/compiler/fuzz/translator_fuzzer.cpp
new file mode 100644
index 000000000..518552255
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/fuzz/translator_fuzzer.cpp
@@ -0,0 +1,162 @@
+//
+// 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.
+//
+
+// translator_fuzzer.cpp: A libfuzzer fuzzer for the shader translator.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unordered_map>
+#include <iostream>
+
+#include "compiler/translator/Compiler.h"
+#include "angle_gl.h"
+
+struct TranslatorCacheKey
+{
+ bool operator==(const TranslatorCacheKey &other) const
+ {
+ return type == other.type && spec == other.spec && output == other.output;
+ }
+
+ uint32_t type = 0;
+ uint32_t spec = 0;
+ uint32_t output = 0;
+};
+
+namespace std
+{
+
+template <>
+struct hash<TranslatorCacheKey>
+{
+ std::size_t operator()(const TranslatorCacheKey &k) const
+ {
+ return (hash<uint32_t>()(k.type) << 1) ^ (hash<uint32_t>()(k.spec) >> 1) ^
+ hash<uint32_t>()(k.output);
+ }
+};
+} // namespace std
+
+static std::unordered_map<TranslatorCacheKey, TCompiler *> translators;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ // Reserve some size for future compile options
+ const size_t kHeaderSize = 128;
+
+ if (size <= kHeaderSize)
+ {
+ return 0;
+ }
+
+ // Make sure the rest of data will be a valid C string so that we don't have to copy it.
+ if (data[size - 1] != 0)
+ {
+ return 0;
+ }
+
+ uint32_t type = *reinterpret_cast<const uint32_t *>(data);
+ uint32_t spec = *reinterpret_cast<const uint32_t *>(data + 4);
+ uint32_t output = *reinterpret_cast<const uint32_t *>(data + 8);
+ uint64_t options = *reinterpret_cast<const uint64_t *>(data + 12);
+
+ if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER)
+ {
+ return 0;
+ }
+
+ if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC &&
+ spec != SH_WEBGL2_SPEC)
+ {
+ return 0;
+ }
+
+ std::vector<uint32_t> validOutputs;
+ validOutputs.push_back(SH_ESSL_OUTPUT);
+ validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
+ validOutputs.push_back(SH_GLSL_130_OUTPUT);
+ validOutputs.push_back(SH_GLSL_140_OUTPUT);
+ validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT);
+ validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT);
+ validOutputs.push_back(SH_HLSL_OUTPUT);
+ validOutputs.push_back(SH_HLSL9_OUTPUT);
+ validOutputs.push_back(SH_HLSL11_OUTPUT);
+ validOutputs.push_back(SH_HLSL_3_0_OUTPUT);
+ validOutputs.push_back(SH_HLSL_4_1_OUTPUT);
+ validOutputs.push_back(SH_HLSL_4_0_FL9_3_OUTPUT);
+ bool found = false;
+ for (auto valid : validOutputs)
+ {
+ found = found || (valid == output);
+ }
+ if (!found)
+ {
+ return 0;
+ }
+
+ size -= kHeaderSize;
+ data += kHeaderSize;
+
+ if (!ShInitialize())
+ {
+ return 0;
+ }
+
+ TranslatorCacheKey key;
+ key.type = type;
+ key.spec = spec;
+ key.output = output;
+
+ if (translators.find(key) == translators.end())
+ {
+ TCompiler *translator = ConstructCompiler(type, static_cast<ShShaderSpec>(spec),
+ static_cast<ShShaderOutput>(output));
+
+ if (!translator)
+ {
+ return 0;
+ }
+
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+
+ // Enable all the extensions to have more coverage
+ resources.OES_standard_derivatives = 1;
+ resources.OES_EGL_image_external = 1;
+ resources.OES_EGL_image_external_essl3 = 1;
+ resources.NV_EGL_stream_consumer_external = 1;
+ resources.ARB_texture_rectangle = 1;
+ resources.EXT_blend_func_extended = 1;
+ resources.EXT_draw_buffers = 1;
+ resources.EXT_frag_depth = 1;
+ resources.EXT_shader_texture_lod = 1;
+ resources.WEBGL_debug_shader_precision = 1;
+ resources.EXT_shader_framebuffer_fetch = 1;
+ resources.NV_shader_framebuffer_fetch = 1;
+ resources.ARM_shader_framebuffer_fetch = 1;
+
+ if (!translator->Init(resources))
+ {
+ DeleteCompiler(translator);
+ return 0;
+ }
+
+ translators[key] = translator;
+ }
+
+ TCompiler *translator = translators[key];
+
+ const char *shaderStrings[] = {reinterpret_cast<const char *>(data)};
+ translator->compile(shaderStrings, 1, options);
+
+ return 0;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.l b/Source/ThirdParty/ANGLE/src/compiler/glslang.l
deleted file mode 100644
index a4350d4c2..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/glslang.l
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
-//
-// 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.
-//
-
-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).
-*/
-
-%top{
-//
-// 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.
-//
-
-// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
-
-// 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: 4505)
-#pragma warning(disable: 4701)
-#endif
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunknown-pragmas"
-#pragma clang diagnostic ignored "-Wdeprecated-register"
-#endif
-}
-
-%{
-#include "compiler/glslang.h"
-#include "compiler/ParseContext.h"
-#include "compiler/preprocessor/Token.h"
-#include "compiler/util.h"
-#include "glslang_tab.h"
-
-/* windows only pragma */
-#ifdef _MSC_VER
-#pragma warning(disable : 4102)
-#endif
-
-#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 int_constant(yyscan_t yyscanner);
-static int float_constant(yyscan_t yyscanner);
-%}
-
-%option noyywrap nounput never-interactive
-%option yylineno reentrant bison-bridge bison-locations
-%option extra-type="TParseContext*"
-
-D [0-9]
-L [a-zA-Z_]
-H [a-fA-F0-9]
-E [Ee][+-]?{D}+
-O [0-7]
-
-%%
-
-"invariant" { return INVARIANT; }
-"highp" { return HIGH_PRECISION; }
-"mediump" { return MEDIUM_PRECISION; }
-"lowp" { return LOW_PRECISION; }
-"precision" { return PRECISION; }
-
-"attribute" { return ATTRIBUTE; }
-"const" { return CONST_QUAL; }
-"uniform" { return UNIFORM; }
-"varying" { return VARYING; }
-
-"break" { return BREAK; }
-"continue" { return CONTINUE; }
-"do" { return DO; }
-"for" { return FOR; }
-"while" { return WHILE; }
-
-"if" { return IF; }
-"else" { return ELSE; }
-
-"in" { return IN_QUAL; }
-"out" { return OUT_QUAL; }
-"inout" { return INOUT_QUAL; }
-
-"float" { return FLOAT_TYPE; }
-"int" { return INT_TYPE; }
-"void" { return VOID_TYPE; }
-"bool" { return BOOL_TYPE; }
-"true" { yylval->lex.b = true; return BOOLCONSTANT; }
-"false" { yylval->lex.b = false; return BOOLCONSTANT; }
-
-"discard" { return DISCARD; }
-"return" { return RETURN; }
-
-"mat2" { return MATRIX2; }
-"mat3" { return MATRIX3; }
-"mat4" { return MATRIX4; }
-
-"vec2" { return VEC2; }
-"vec3" { return VEC3; }
-"vec4" { return VEC4; }
-"ivec2" { return IVEC2; }
-"ivec3" { return IVEC3; }
-"ivec4" { return IVEC4; }
-"bvec2" { return BVEC2; }
-"bvec3" { return BVEC3; }
-"bvec4" { return BVEC4; }
-
-"sampler2D" { return SAMPLER2D; }
-"samplerCube" { return SAMPLERCUBE; }
-"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; }
-"sampler2DRect" { return SAMPLER2DRECT; }
-
-"struct" { return STRUCT; }
-
-"asm" { return reserved_word(yyscanner); }
-
-"class" { return reserved_word(yyscanner); }
-"union" { return reserved_word(yyscanner); }
-"enum" { return reserved_word(yyscanner); }
-"typedef" { return reserved_word(yyscanner); }
-"template" { return reserved_word(yyscanner); }
-"this" { return reserved_word(yyscanner); }
-"packed" { return reserved_word(yyscanner); }
-
-"goto" { return reserved_word(yyscanner); }
-"switch" { return reserved_word(yyscanner); }
-"default" { return reserved_word(yyscanner); }
-
-"inline" { return reserved_word(yyscanner); }
-"noinline" { return reserved_word(yyscanner); }
-"volatile" { return reserved_word(yyscanner); }
-"public" { return reserved_word(yyscanner); }
-"static" { return reserved_word(yyscanner); }
-"extern" { return reserved_word(yyscanner); }
-"external" { return reserved_word(yyscanner); }
-"interface" { return reserved_word(yyscanner); }
-"flat" { return reserved_word(yyscanner); }
-
-"long" { return reserved_word(yyscanner); }
-"short" { return reserved_word(yyscanner); }
-"double" { return reserved_word(yyscanner); }
-"half" { return reserved_word(yyscanner); }
-"fixed" { return reserved_word(yyscanner); }
-"unsigned" { return reserved_word(yyscanner); }
-"superp" { return reserved_word(yyscanner); }
-
-"input" { return reserved_word(yyscanner); }
-"output" { return reserved_word(yyscanner); }
-
-"hvec2" { return reserved_word(yyscanner); }
-"hvec3" { return reserved_word(yyscanner); }
-"hvec4" { return reserved_word(yyscanner); }
-"dvec2" { return reserved_word(yyscanner); }
-"dvec3" { return reserved_word(yyscanner); }
-"dvec4" { return reserved_word(yyscanner); }
-"fvec2" { return reserved_word(yyscanner); }
-"fvec3" { return reserved_word(yyscanner); }
-"fvec4" { return reserved_word(yyscanner); }
-
-"sampler1D" { return reserved_word(yyscanner); }
-"sampler3D" { return reserved_word(yyscanner); }
-"sampler1DShadow" { return reserved_word(yyscanner); }
-"sampler2DShadow" { return reserved_word(yyscanner); }
-"sampler3DRect" { return reserved_word(yyscanner); }
-"sampler2DRectShadow" { return reserved_word(yyscanner); }
-
-"sizeof" { return reserved_word(yyscanner); }
-"cast" { return reserved_word(yyscanner); }
-
-"namespace" { return reserved_word(yyscanner); }
-"using" { return reserved_word(yyscanner); }
-
-{L}({L}|{D})* {
- yylval->lex.string = NewPoolTString(yytext);
- return check_type(yyscanner);
-}
-
-0[xX]{H}+ { return int_constant(yyscanner); }
-0{O}+ { return int_constant(yyscanner); }
-{D}+ { return int_constant(yyscanner); }
-
-{D}+{E} { return float_constant(yyscanner); }
-{D}+"."{D}*({E})? { return float_constant(yyscanner); }
-"."{D}+({E})? { return float_constant(yyscanner); }
-
-"+=" { return ADD_ASSIGN; }
-"-=" { return SUB_ASSIGN; }
-"*=" { return MUL_ASSIGN; }
-"/=" { return DIV_ASSIGN; }
-"%=" { return MOD_ASSIGN; }
-"<<=" { return LEFT_ASSIGN; }
-">>=" { return RIGHT_ASSIGN; }
-"&=" { return AND_ASSIGN; }
-"^=" { return XOR_ASSIGN; }
-"|=" { return OR_ASSIGN; }
-
-"++" { return INC_OP; }
-"--" { return DEC_OP; }
-"&&" { return AND_OP; }
-"||" { return OR_OP; }
-"^^" { return XOR_OP; }
-"<=" { return LE_OP; }
-">=" { return GE_OP; }
-"==" { return EQ_OP; }
-"!=" { return NE_OP; }
-"<<" { return LEFT_OP; }
-">>" { return RIGHT_OP; }
-";" { return SEMICOLON; }
-("{"|"<%") { return LEFT_BRACE; }
-("}"|"%>") { return RIGHT_BRACE; }
-"," { return COMMA; }
-":" { return COLON; }
-"=" { return EQUAL; }
-"(" { return LEFT_PAREN; }
-")" { return RIGHT_PAREN; }
-("["|"<:") { return LEFT_BRACKET; }
-("]"|":>") { return RIGHT_BRACKET; }
-"." { return DOT; }
-"!" { return BANG; }
-"-" { return DASH; }
-"~" { return TILDE; }
-"+" { return PLUS; }
-"*" { return STAR; }
-"/" { return SLASH; }
-"%" { return PERCENT; }
-"<" { return LEFT_ANGLE; }
-">" { return RIGHT_ANGLE; }
-"|" { return VERTICAL_BAR; }
-"^" { return CARET; }
-"&" { return AMPERSAND; }
-"?" { return QUESTION; }
-
-[ \t\v\n\f\r] { }
-<<EOF>> { yyterminate(); }
-. { assert(false); return 0; }
-
-%%
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
- pp::Token token;
- yyget_extra(yyscanner)->preprocessor.lex(&token);
- yy_size_t len = token.type == 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;
- TSymbol* symbol = yyextra->symbolTable.find(yytext);
- if (symbol && symbol->isVariable()) {
- TVariable* variable = static_cast<TVariable*>(symbol);
- if (variable->isUserType())
- 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, "");
- yyextra->recover();
- return 0;
-}
-
-void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) {
- context->error(*lloc, reason, yyget_text(context->scanner));
- context->recover();
-}
-
-int int_constant(yyscan_t yyscanner) {
- struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
-
- if (!atoi_clamp(yytext, &(yylval->lex.i)))
- yyextra->warning(*yylloc, "Integer overflow", yytext, "");
- return INTCONSTANT;
-}
-
-int float_constant(yyscan_t yyscanner) {
- struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
-
- if (!atof_clamp(yytext, &(yylval->lex.f)))
- yyextra->warning(*yylloc, "Float overflow", yytext, "");
- return FLOATCONSTANT;
-}
-
-int glslang_initialize(TParseContext* context) {
- yyscan_t scanner = NULL;
- if (yylex_init_extra(context, &scanner))
- return 1;
-
- context->scanner = scanner;
- return 0;
-}
-
-int glslang_finalize(TParseContext* context) {
- yyscan_t scanner = context->scanner;
- if (scanner == NULL) return 0;
-
- context->scanner = NULL;
- yylex_destroy(scanner);
-
- return 0;
-}
-
-int glslang_scan(size_t count, const char* const string[], const int length[],
- TParseContext* context) {
- yyrestart(NULL, context->scanner);
- yyset_column(0, context->scanner);
- yyset_lineno(1, context->scanner);
-
- // Initialize preprocessor.
- if (!context->preprocessor.init(count, string, length))
- return 1;
- context->preprocessor.setMaxTokenLength(SH_MAX_TOKEN_LENGTH);
-
- // Define extension macros.
- const TExtensionBehavior& extBehavior = context->extensionBehavior();
- for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
- iter != extBehavior.end(); ++iter) {
- context->preprocessor.predefineMacro(iter->first.c_str(), 1);
- }
- if (context->fragmentPrecisionHigh)
- context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
-
- return 0;
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.y b/Source/ThirdParty/ANGLE/src/compiler/glslang.y
deleted file mode 100644
index eed5d7871..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/glslang.y
+++ /dev/null
@@ -1,2003 +0,0 @@
-/*
-//
-// 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 Yacc grammar for GLSL ES.
-Based on ANSI C Yacc grammar:
-http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
-
-IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
-WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
-*/
-
-%{
-//
-// 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.
-//
-
-// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
-
-// 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: 4505)
-#pragma warning(disable: 4701)
-#endif
-
-#include "compiler/SymbolTable.h"
-#include "compiler/ParseContext.h"
-#include "GLSLANG/ShaderLang.h"
-
-#define YYENABLE_NLS 0
-
-#define YYLEX_PARAM context->scanner
-%}
-
-%expect 1 /* One shift reduce conflict because of if | else */
-%pure-parser
-%parse-param {TParseContext* context}
-%locations
-%lex-param {YYLEX_PARAM}
-
-%code requires {
-#define YYLTYPE TSourceLoc
-#define YYLTYPE_IS_DECLARED 1
-#define SH_MAX_TOKEN_LENGTH 256 // WebGL spec.
-}
-
-%union {
- struct {
- union {
- TString *string;
- float f;
- int i;
- bool b;
- };
- TSymbol* symbol;
- } lex;
- struct {
- TOperator op;
- union {
- TIntermNode* intermNode;
- TIntermNodePair nodePair;
- TIntermTyped* intermTypedNode;
- TIntermAggregate* intermAggregate;
- };
- union {
- TPublicType type;
- TPrecision precision;
- TQualifier qualifier;
- TFunction* function;
- TParameter param;
- TField* field;
- TFieldList* fieldList;
- };
- } interm;
-}
-
-%{
-extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
-extern void yyerror(YYLTYPE* yylloc, TParseContext* context, 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) { \
- if (context->shaderType != SH_VERTEX_SHADER) { \
- context->error(L, " supported in vertex shaders only ", S); \
- context->recover(); \
- } \
-}
-
-#define FRAG_ONLY(S, L) { \
- if (context->shaderType != SH_FRAGMENT_SHADER) { \
- context->error(L, " supported in fragment shaders only ", S); \
- context->recover(); \
- } \
-}
-%}
-
-%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
-%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE
-%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN
-%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4
-%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
-%token <lex> STRUCT VOID_TYPE WHILE
-%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT
-
-%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT
-%token <lex> LEFT_OP RIGHT_OP
-%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
-%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
-%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
-%token <lex> SUB_ASSIGN
-
-%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
-%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
-%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
-
-%type <lex> identifier
-%type <interm> assignment_operator unary_operator
-%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
-%type <interm.intermTypedNode> expression integer_expression assignment_expression
-%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
-%type <interm.intermTypedNode> relational_expression equality_expression
-%type <interm.intermTypedNode> conditional_expression constant_expression
-%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
-%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
-%type <interm.intermTypedNode> function_call initializer condition conditionopt
-
-%type <interm.intermNode> translation_unit function_definition
-%type <interm.intermNode> statement simple_statement
-%type <interm.intermAggregate> statement_list compound_statement
-%type <interm.intermNode> declaration_statement selection_statement expression_statement
-%type <interm.intermNode> declaration external_declaration
-%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
-%type <interm.nodePair> selection_rest_statement for_rest_statement
-%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
-%type <interm> single_declaration init_declarator_list
-
-%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
-%type <interm.qualifier> parameter_qualifier
-
-%type <interm.precision> precision_qualifier
-%type <interm.type> type_qualifier fully_specified_type type_specifier
-%type <interm.type> type_specifier_no_prec type_specifier_nonarray
-%type <interm.type> struct_specifier
-%type <interm.field> struct_declarator
-%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
-%type <interm.function> function_header function_declarator function_identifier
-%type <interm.function> function_header_with_parameters function_call_header
-%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
-%type <interm> function_call_or_method
-
-%start translation_unit
-%%
-
-identifier
- : IDENTIFIER
- | TYPE_NAME
-
-variable_identifier
- : IDENTIFIER {
- // The symbol table search was done in the lexical phase
- const TSymbol* symbol = $1.symbol;
- const TVariable* variable;
- if (symbol == 0) {
- context->error(@1, "undeclared identifier", $1.string->c_str());
- context->recover();
- TType type(EbtFloat, EbpUndefined);
- TVariable* fakeVariable = new TVariable($1.string, type);
- context->symbolTable.insert(*fakeVariable);
- variable = fakeVariable;
- } else {
- // This identifier can only be a variable type symbol
- if (! symbol->isVariable()) {
- context->error(@1, "variable expected", $1.string->c_str());
- context->recover();
- }
-
- variable = static_cast<const TVariable*>(symbol);
-
- if (context->symbolTable.findBuiltIn(variable->getName()) &&
- !variable->getExtension().empty() &&
- context->extensionErrorCheck(@1, variable->getExtension())) {
- context->recover();
- }
- }
-
- // don't delete $1.string, it's used by error recovery, and the pool
- // pop will reclaim the memory
-
- if (variable->getType().getQualifier() == EvqConst ) {
- ConstantUnion* constArray = variable->getConstPointer();
- TType t(variable->getType());
- $$ = context->intermediate.addConstantUnion(constArray, t, @1);
- } else
- $$ = context->intermediate.addSymbol(variable->getUniqueId(),
- variable->getName(),
- variable->getType(),
- @1);
- }
- ;
-
-primary_expression
- : variable_identifier {
- $$ = $1;
- }
- | INTCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst($1.i);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1);
- }
- | FLOATCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setFConst($1.f);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
- }
- | BOOLCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst($1.b);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1);
- }
- | LEFT_PAREN expression RIGHT_PAREN {
- $$ = $2;
- }
- ;
-
-postfix_expression
- : primary_expression {
- $$ = $1;
- }
- | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
- $$ = context->addIndexExpression($1, @2, $3);
- }
- | function_call {
- $$ = $1;
- }
- | postfix_expression DOT identifier {
- if ($1->isArray()) {
- context->error(@3, "cannot apply dot operator to an array", ".");
- context->recover();
- }
-
- if ($1->isVector()) {
- TVectorFields fields;
- if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, @3)) {
- fields.num = 1;
- fields.offsets[0] = 0;
- context->recover();
- }
-
- if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields
- $$ = context->addConstVectorNode(fields, $1, @3);
- if ($$ == 0) {
- context->recover();
- $$ = $1;
- }
- else
- $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size()));
- } else {
- TString vectorString = *$3.string;
- TIntermTyped* index = context->intermediate.addSwizzle(fields, @3);
- $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, @2);
- $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size()));
- }
- } else if ($1->isMatrix()) {
- TMatrixFields fields;
- if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, @3)) {
- fields.wholeRow = false;
- fields.wholeCol = false;
- fields.row = 0;
- fields.col = 0;
- context->recover();
- }
-
- if (fields.wholeRow || fields.wholeCol) {
- context->error(@2, " non-scalar fields not implemented yet", ".");
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(0);
- TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3);
- $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2);
- $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize()));
- } else {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);
- TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3);
- $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2);
- $$->setType(TType($1->getBasicType(), $1->getPrecision()));
- }
- } else if ($1->getBasicType() == EbtStruct) {
- bool fieldFound = false;
- const TFieldList& fields = $1->getType().getStruct()->fields();
- unsigned int i;
- for (i = 0; i < fields.size(); ++i) {
- if (fields[i]->name() == *$3.string) {
- fieldFound = true;
- break;
- }
- }
- if (fieldFound) {
- if ($1->getType().getQualifier() == EvqConst) {
- $$ = context->addConstStruct(*$3.string, $1, @2);
- if ($$ == 0) {
- context->recover();
- $$ = $1;
- }
- else {
- $$->setType(*fields[i]->type());
- // change the qualifier of the return type, not of the structure field
- // as the structure definition is shared between various structures.
- $$->getTypePointer()->setQualifier(EvqConst);
- }
- } else {
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(i);
- TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *fields[i]->type(), @3);
- $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, @2);
- $$->setType(*fields[i]->type());
- }
- } else {
- context->error(@2, " no such field in structure", $3.string->c_str());
- context->recover();
- $$ = $1;
- }
- } else {
- context->error(@2, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str());
- context->recover();
- $$ = $1;
- }
- // don't delete $3.string, it's from the pool
- }
- | postfix_expression INC_OP {
- if (context->lValueErrorCheck(@2, "++", $1))
- context->recover();
- $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2, context->symbolTable);
- if ($$ == 0) {
- context->unaryOpError(@2, "++", $1->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- | postfix_expression DEC_OP {
- if (context->lValueErrorCheck(@2, "--", $1))
- context->recover();
- $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2, context->symbolTable);
- if ($$ == 0) {
- context->unaryOpError(@2, "--", $1->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- ;
-
-integer_expression
- : expression {
- if (context->integerErrorCheck($1, "[]"))
- context->recover();
- $$ = $1;
- }
- ;
-
-function_call
- : function_call_or_method {
- TFunction* fnCall = $1.function;
- TOperator op = fnCall->getBuiltInOp();
-
- if (op != EOpNull)
- {
- //
- // Then this should be a constructor.
- // Don't go through the symbol table for constructors.
- // Their parameters will be verified algorithmically.
- //
- TType type(EbtVoid, EbpUndefined); // use this to get the type back
- if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) {
- $$ = 0;
- } else {
- //
- // It's a constructor, of type 'type'.
- //
- $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1);
- }
-
- if ($$ == 0) {
- context->recover();
- $$ = context->intermediate.setAggregateOperator(0, op, @1);
- }
- $$->setType(type);
- } else {
- //
- // Not a constructor. Find it in the symbol table.
- //
- const TFunction* fnCandidate;
- bool builtIn;
- fnCandidate = context->findFunction(@1, fnCall, &builtIn);
- if (fnCandidate) {
- //
- // A declared function.
- //
- if (builtIn && !fnCandidate->getExtension().empty() &&
- context->extensionErrorCheck(@1, fnCandidate->getExtension())) {
- context->recover();
- }
- op = fnCandidate->getBuiltInOp();
- if (builtIn && op != EOpNull) {
- //
- // A function call mapped to a built-in operation.
- //
- if (fnCandidate->getParamCount() == 1) {
- //
- // Treat it like a built-in unary operator.
- //
- $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1, context->symbolTable);
- if ($$ == 0) {
- std::stringstream extraInfoStream;
- extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString();
- std::string extraInfo = extraInfoStream.str();
- context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
- YYERROR;
- }
- } else {
- $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1);
- }
- } else {
- // This is a real function call
-
- $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1);
- $$->setType(fnCandidate->getReturnType());
-
- // this is how we know whether the given function is a builtIn function or a user defined function
- // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
- // if builtIn == true, it's definitely a builtIn function with EOpNull
- if (!builtIn)
- $$->getAsAggregate()->setUserDefined();
- $$->getAsAggregate()->setName(fnCandidate->getMangledName());
-
- TQualifier qual;
- for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
- qual = fnCandidate->getParam(i).type->getQualifier();
- if (qual == EvqOut || qual == EvqInOut) {
- if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
- context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
- context->recover();
- }
- }
- }
- }
- $$->setType(fnCandidate->getReturnType());
- } else {
- // error message was put out by PaFindFunction()
- // Put on a dummy node for error recovery
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setFConst(0.0f);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
- context->recover();
- }
- }
- delete fnCall;
- }
- ;
-
-function_call_or_method
- : function_call_generic {
- $$ = $1;
- }
- | postfix_expression DOT function_call_generic {
- context->error(@3, "methods are not supported", "");
- context->recover();
- $$ = $3;
- }
- ;
-
-function_call_generic
- : function_call_header_with_parameters RIGHT_PAREN {
- $$ = $1;
- }
- | function_call_header_no_parameters RIGHT_PAREN {
- $$ = $1;
- }
- ;
-
-function_call_header_no_parameters
- : function_call_header VOID_TYPE {
- $$.function = $1;
- $$.intermNode = 0;
- }
- | function_call_header {
- $$.function = $1;
- $$.intermNode = 0;
- }
- ;
-
-function_call_header_with_parameters
- : function_call_header assignment_expression {
- TParameter param = { 0, new TType($2->getType()) };
- $1->addParameter(param);
- $$.function = $1;
- $$.intermNode = $2;
- }
- | function_call_header_with_parameters COMMA assignment_expression {
- TParameter param = { 0, new TType($3->getType()) };
- $1.function->addParameter(param);
- $$.function = $1.function;
- $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2);
- }
- ;
-
-function_call_header
- : function_identifier LEFT_PAREN {
- $$ = $1;
- }
- ;
-
-// Grammar Note: Constructors look like functions, but are recognized as types.
-
-function_identifier
- : type_specifier_nonarray {
- //
- // Constructor
- //
- TOperator op = EOpNull;
- if ($1.userDef) {
- op = EOpConstructStruct;
- } else {
- switch ($1.type) {
- case EbtFloat:
- if ($1.matrix) {
- switch($1.size) {
- case 2: op = EOpConstructMat2; break;
- case 3: op = EOpConstructMat3; break;
- case 4: op = EOpConstructMat4; break;
- }
- } else {
- switch($1.size) {
- case 1: op = EOpConstructFloat; break;
- case 2: op = EOpConstructVec2; break;
- case 3: op = EOpConstructVec3; break;
- case 4: op = EOpConstructVec4; break;
- }
- }
- break;
- case EbtInt:
- switch($1.size) {
- case 1: op = EOpConstructInt; break;
- case 2: op = EOpConstructIVec2; break;
- case 3: op = EOpConstructIVec3; break;
- case 4: op = EOpConstructIVec4; break;
- }
- break;
- case EbtBool:
- switch($1.size) {
- case 1: op = EOpConstructBool; break;
- case 2: op = EOpConstructBVec2; break;
- case 3: op = EOpConstructBVec3; break;
- case 4: op = EOpConstructBVec4; break;
- }
- break;
- default: break;
- }
- if (op == EOpNull) {
- context->error(@1, "cannot construct this type", getBasicString($1.type));
- context->recover();
- $1.type = EbtFloat;
- op = EOpConstructFloat;
- }
- }
- TString tempString;
- TType type($1);
- TFunction *function = new TFunction(&tempString, type, op);
- $$ = function;
- }
- | IDENTIFIER {
- if (context->reservedErrorCheck(@1, *$1.string))
- context->recover();
- TType type(EbtVoid, EbpUndefined);
- TFunction *function = new TFunction($1.string, type);
- $$ = function;
- }
- ;
-
-unary_expression
- : postfix_expression {
- $$ = $1;
- }
- | INC_OP unary_expression {
- if (context->lValueErrorCheck(@1, "++", $2))
- context->recover();
- $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1, context->symbolTable);
- if ($$ == 0) {
- context->unaryOpError(@1, "++", $2->getCompleteString());
- context->recover();
- $$ = $2;
- }
- }
- | DEC_OP unary_expression {
- if (context->lValueErrorCheck(@1, "--", $2))
- context->recover();
- $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1, context->symbolTable);
- if ($$ == 0) {
- context->unaryOpError(@1, "--", $2->getCompleteString());
- context->recover();
- $$ = $2;
- }
- }
- | unary_operator unary_expression {
- if ($1.op != EOpNull) {
- $$ = context->intermediate.addUnaryMath($1.op, $2, @1, context->symbolTable);
- if ($$ == 0) {
- const char* errorOp = "";
- switch($1.op) {
- case EOpNegative: errorOp = "-"; break;
- case EOpLogicalNot: errorOp = "!"; break;
- default: break;
- }
- context->unaryOpError(@1, errorOp, $2->getCompleteString());
- context->recover();
- $$ = $2;
- }
- } else
- $$ = $2;
- }
- ;
-// Grammar Note: No traditional style type casts.
-
-unary_operator
- : PLUS { $$.op = EOpNull; }
- | DASH { $$.op = EOpNegative; }
- | BANG { $$.op = EOpLogicalNot; }
- ;
-// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
-
-multiplicative_expression
- : unary_expression { $$ = $1; }
- | multiplicative_expression STAR unary_expression {
- $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- | multiplicative_expression SLASH unary_expression {
- $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- ;
-
-additive_expression
- : multiplicative_expression { $$ = $1; }
- | additive_expression PLUS multiplicative_expression {
- $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- | additive_expression DASH multiplicative_expression {
- $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- ;
-
-shift_expression
- : additive_expression { $$ = $1; }
- ;
-
-relational_expression
- : shift_expression { $$ = $1; }
- | relational_expression LEFT_ANGLE shift_expression {
- $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- | relational_expression RIGHT_ANGLE shift_expression {
- $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- | relational_expression LE_OP shift_expression {
- $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- | relational_expression GE_OP shift_expression {
- $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- ;
-
-equality_expression
- : relational_expression { $$ = $1; }
- | equality_expression EQ_OP relational_expression {
- $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- | equality_expression NE_OP relational_expression {
- $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- ;
-
-and_expression
- : equality_expression { $$ = $1; }
- ;
-
-exclusive_or_expression
- : and_expression { $$ = $1; }
- ;
-
-inclusive_or_expression
- : exclusive_or_expression { $$ = $1; }
- ;
-
-logical_and_expression
- : inclusive_or_expression { $$ = $1; }
- | logical_and_expression AND_OP inclusive_or_expression {
- $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- ;
-
-logical_xor_expression
- : logical_and_expression { $$ = $1; }
- | logical_xor_expression XOR_OP logical_and_expression {
- $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- ;
-
-logical_or_expression
- : logical_xor_expression { $$ = $1; }
- | logical_or_expression OR_OP logical_xor_expression {
- $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2, context->symbolTable);
- if ($$ == 0) {
- context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setBConst(false);
- $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
- }
- }
- ;
-
-conditional_expression
- : logical_or_expression { $$ = $1; }
- | logical_or_expression QUESTION expression COLON assignment_expression {
- if (context->boolErrorCheck(@2, $1))
- context->recover();
-
- $$ = context->intermediate.addSelection($1, $3, $5, @2);
- if ($3->getType() != $5->getType())
- $$ = 0;
-
- if ($$ == 0) {
- context->binaryOpError(@2, ":", $3->getCompleteString(), $5->getCompleteString());
- context->recover();
- $$ = $5;
- }
- }
- ;
-
-assignment_expression
- : conditional_expression { $$ = $1; }
- | unary_expression assignment_operator assignment_expression {
- if (context->lValueErrorCheck(@2, "assign", $1))
- context->recover();
- $$ = context->intermediate.addAssign($2.op, $1, $3, @2);
- if ($$ == 0) {
- context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $1;
- }
- }
- ;
-
-assignment_operator
- : EQUAL { $$.op = EOpAssign; }
- | MUL_ASSIGN { $$.op = EOpMulAssign; }
- | DIV_ASSIGN { $$.op = EOpDivAssign; }
- | ADD_ASSIGN { $$.op = EOpAddAssign; }
- | SUB_ASSIGN { $$.op = EOpSubAssign; }
- ;
-
-expression
- : assignment_expression {
- $$ = $1;
- }
- | expression COMMA assignment_expression {
- $$ = context->intermediate.addComma($1, $3, @2);
- if ($$ == 0) {
- context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $3;
- }
- }
- ;
-
-constant_expression
- : conditional_expression {
- if (context->constErrorCheck($1))
- context->recover();
- $$ = $1;
- }
- ;
-
-declaration
- : function_prototype SEMICOLON {
- TFunction &function = *($1.function);
-
- TIntermAggregate *prototype = new TIntermAggregate;
- prototype->setType(function.getReturnType());
- prototype->setName(function.getName());
-
- for (size_t i = 0; i < function.getParamCount(); i++)
- {
- const TParameter &param = function.getParam(i);
- if (param.name != 0)
- {
- TVariable variable(param.name, *param.type);
-
- prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), @1), @1);
- }
- else
- {
- prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
- }
- }
-
- prototype->setOp(EOpPrototype);
- $$ = prototype;
-
- context->symbolTable.pop();
- }
- | init_declarator_list SEMICOLON {
- if ($1.intermAggregate)
- $1.intermAggregate->setOp(EOpDeclaration);
- $$ = $1.intermAggregate;
- }
- | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
- if (($2 == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
- context->error(@1, "precision is not supported in fragment shader", "highp");
- context->recover();
- }
- if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
- context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type));
- context->recover();
- }
- $$ = 0;
- }
- ;
-
-function_prototype
- : function_declarator RIGHT_PAREN {
- //
- // Multiple declarations of the same function are allowed.
- //
- // If this is a definition, the definition production code will check for redefinitions
- // (we don't know at this point if it's a definition or not).
- //
- // Redeclarations are allowed. But, return types and parameter qualifiers must match.
- //
- TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName()));
- if (prevDec) {
- if (prevDec->getReturnType() != $1->getReturnType()) {
- context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
- context->recover();
- }
- for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
- if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
- context->error(@2, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
- context->recover();
- }
- }
- }
-
- //
- // Check for previously declared variables using the same name.
- //
- TSymbol *prevSym = context->symbolTable.find($1->getName());
- if (prevSym)
- {
- if (!prevSym->isFunction())
- {
- context->error(@2, "redefinition", $1->getName().c_str(), "function");
- context->recover();
- }
- }
- else
- {
- // Insert the unmangled name to detect potential future redefinition as a variable.
- context->symbolTable.getOuterLevel()->insert($1->getName(), *$1);
- }
-
- //
- // 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.
- //
- $$.function = $1;
-
- // We're at the inner scope level of the function's arguments and body statement.
- // Add the function prototype to the surrounding scope instead.
- context->symbolTable.getOuterLevel()->insert(*$$.function);
- }
- ;
-
-function_declarator
- : function_header {
- $$ = $1;
- }
- | function_header_with_parameters {
- $$ = $1;
- }
- ;
-
-
-function_header_with_parameters
- : function_header parameter_declaration {
- // Add the parameter
- $$ = $1;
- if ($2.param.type->getBasicType() != EbtVoid)
- $1->addParameter($2.param);
- else
- delete $2.param.type;
- }
- | function_header_with_parameters COMMA parameter_declaration {
- //
- // Only first parameter of one-parameter functions can be void
- // The check for named parameters not being void is done in parameter_declarator
- //
- if ($3.param.type->getBasicType() == EbtVoid) {
- //
- // This parameter > first is void
- //
- context->error(@2, "cannot be an argument type except for '(void)'", "void");
- context->recover();
- delete $3.param.type;
- } else {
- // Add the parameter
- $$ = $1;
- $1->addParameter($3.param);
- }
- }
- ;
-
-function_header
- : fully_specified_type IDENTIFIER LEFT_PAREN {
- if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
- context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier));
- context->recover();
- }
- // make sure a sampler is not involved as well...
- if (context->structQualifierErrorCheck(@2, $1))
- context->recover();
-
- // Add the function as a prototype after parsing it (we do not support recursion)
- TFunction *function;
- TType type($1);
- function = new TFunction($2.string, type);
- $$ = function;
-
- context->symbolTable.push();
- }
- ;
-
-parameter_declarator
- // Type + name
- : type_specifier identifier {
- if ($1.type == EbtVoid) {
- context->error(@2, "illegal use of type 'void'", $2.string->c_str());
- context->recover();
- }
- if (context->reservedErrorCheck(@2, *$2.string))
- context->recover();
- TParameter param = {$2.string, new TType($1)};
- $$.param = param;
- }
- | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
- // Check that we can make an array out of this type
- if (context->arrayTypeErrorCheck(@3, $1))
- context->recover();
-
- if (context->reservedErrorCheck(@2, *$2.string))
- context->recover();
-
- int size;
- if (context->arraySizeErrorCheck(@3, $4, size))
- context->recover();
- $1.setArray(true, size);
-
- TType* type = new TType($1);
- TParameter param = { $2.string, type };
- $$.param = param;
- }
- ;
-
-parameter_declaration
- //
- // The only parameter qualifier a parameter can have are
- // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
- //
-
- //
- // Type + name
- //
- : type_qualifier parameter_qualifier parameter_declarator {
- $$ = $3;
- if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type))
- context->recover();
- }
- | parameter_qualifier parameter_declarator {
- $$ = $2;
- if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
- context->recover();
- if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
- context->recover();
- }
- //
- // Only type
- //
- | type_qualifier parameter_qualifier parameter_type_specifier {
- $$ = $3;
- if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type))
- context->recover();
- }
- | parameter_qualifier parameter_type_specifier {
- $$ = $2;
- if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
- context->recover();
- if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
- context->recover();
- }
- ;
-
-parameter_qualifier
- : /* empty */ {
- $$ = EvqIn;
- }
- | IN_QUAL {
- $$ = EvqIn;
- }
- | OUT_QUAL {
- $$ = EvqOut;
- }
- | INOUT_QUAL {
- $$ = EvqInOut;
- }
- ;
-
-parameter_type_specifier
- : type_specifier {
- TParameter param = { 0, new TType($1) };
- $$.param = param;
- }
- ;
-
-init_declarator_list
- : single_declaration {
- $$ = $1;
- }
- | init_declarator_list COMMA identifier {
- if ($1.type.type == EbtInvariant && !$3.symbol)
- {
- context->error(@3, "undeclared identifier declared as invariant", $3.string->c_str());
- context->recover();
- }
-
- TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), @3);
- $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, @3);
-
- if (context->structQualifierErrorCheck(@3, $$.type))
- context->recover();
-
- if (context->nonInitConstErrorCheck(@3, *$3.string, $$.type, false))
- context->recover();
-
- TVariable* variable = 0;
- if (context->nonInitErrorCheck(@3, *$3.string, $$.type, variable))
- context->recover();
- if (symbol && variable)
- symbol->setId(variable->getUniqueId());
- }
- | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET {
- if (context->structQualifierErrorCheck(@3, $1.type))
- context->recover();
-
- if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true))
- context->recover();
-
- $$ = $1;
-
- if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type))
- context->recover();
- else {
- $1.type.setArray(true);
- TVariable* variable;
- if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable))
- context->recover();
- }
- }
- | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
- if (context->structQualifierErrorCheck(@3, $1.type))
- context->recover();
-
- if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true))
- context->recover();
-
- $$ = $1;
-
- if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type))
- context->recover();
- else {
- int size;
- if (context->arraySizeErrorCheck(@4, $5, size))
- context->recover();
- $1.type.setArray(true, size);
- TVariable* variable = 0;
- if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable))
- context->recover();
- TType type = TType($1.type);
- type.setArraySize(size);
- $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, @3), @3);
- }
- }
- | init_declarator_list COMMA identifier EQUAL initializer {
- if (context->structQualifierErrorCheck(@3, $1.type))
- context->recover();
-
- $$ = $1;
-
- TIntermNode* intermNode;
- if (!context->executeInitializer(@3, *$3.string, $1.type, $5, intermNode)) {
- //
- // build the intermediate representation
- //
- if (intermNode)
- $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, @4);
- else
- $$.intermAggregate = $1.intermAggregate;
- } else {
- context->recover();
- $$.intermAggregate = 0;
- }
- }
- ;
-
-single_declaration
- : fully_specified_type {
- $$.type = $1;
- $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), @1), @1);
- }
- | fully_specified_type identifier {
- TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2);
- $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
-
- if (context->structQualifierErrorCheck(@2, $$.type))
- context->recover();
-
- if (context->nonInitConstErrorCheck(@2, *$2.string, $$.type, false))
- context->recover();
-
- $$.type = $1;
-
- TVariable* variable = 0;
- if (context->nonInitErrorCheck(@2, *$2.string, $$.type, variable))
- context->recover();
- if (variable && symbol)
- symbol->setId(variable->getUniqueId());
- }
- | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
- context->error(@2, "unsized array declarations not supported", $2.string->c_str());
- context->recover();
-
- TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2);
- $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
- $$.type = $1;
- }
- | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
- TType type = TType($1);
- int size;
- if (context->arraySizeErrorCheck(@2, $4, size))
- context->recover();
- type.setArraySize(size);
- TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, @2);
- $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
-
- if (context->structQualifierErrorCheck(@2, $1))
- context->recover();
-
- if (context->nonInitConstErrorCheck(@2, *$2.string, $1, true))
- context->recover();
-
- $$.type = $1;
-
- if (context->arrayTypeErrorCheck(@3, $1) || context->arrayQualifierErrorCheck(@3, $1))
- context->recover();
- else {
- int size;
- if (context->arraySizeErrorCheck(@3, $4, size))
- context->recover();
-
- $1.setArray(true, size);
- TVariable* variable = 0;
- if (context->arrayErrorCheck(@3, *$2.string, $1, variable))
- context->recover();
- if (variable && symbol)
- symbol->setId(variable->getUniqueId());
- }
- }
- | fully_specified_type identifier EQUAL initializer {
- if (context->structQualifierErrorCheck(@2, $1))
- context->recover();
-
- $$.type = $1;
-
- TIntermNode* intermNode;
- if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode)) {
- //
- // Build intermediate representation
- //
- if(intermNode)
- $$.intermAggregate = context->intermediate.makeAggregate(intermNode, @3);
- else
- $$.intermAggregate = 0;
- } else {
- context->recover();
- $$.intermAggregate = 0;
- }
- }
- | INVARIANT IDENTIFIER {
- VERTEX_ONLY("invariant declaration", @1);
- if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
- context->recover();
- $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, @2);
- if (!$2.symbol)
- {
- context->error(@2, "undeclared identifier declared as invariant", $2.string->c_str());
- context->recover();
-
- $$.intermAggregate = 0;
- }
- else
- {
- TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), @2);
- $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
- }
- }
- ;
-
-fully_specified_type
- : type_specifier {
- $$ = $1;
-
- if ($1.array) {
- context->error(@1, "not supported", "first-class array");
- context->recover();
- $1.setArray(false);
- }
- }
- | type_qualifier type_specifier {
- if ($2.array) {
- context->error(@2, "not supported", "first-class array");
- context->recover();
- $2.setArray(false);
- }
-
- if ($1.qualifier == EvqAttribute &&
- ($2.type == EbtBool || $2.type == EbtInt)) {
- context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier));
- context->recover();
- }
- if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
- ($2.type == EbtBool || $2.type == EbtInt)) {
- context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier));
- context->recover();
- }
- $$ = $2;
- $$.qualifier = $1.qualifier;
- }
- ;
-
-type_qualifier
- : CONST_QUAL {
- $$.setBasic(EbtVoid, EvqConst, @1);
- }
- | ATTRIBUTE {
- VERTEX_ONLY("attribute", @1);
- if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute"))
- context->recover();
- $$.setBasic(EbtVoid, EvqAttribute, @1);
- }
- | VARYING {
- if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying"))
- context->recover();
- if (context->shaderType == SH_VERTEX_SHADER)
- $$.setBasic(EbtVoid, EvqVaryingOut, @1);
- else
- $$.setBasic(EbtVoid, EvqVaryingIn, @1);
- }
- | INVARIANT VARYING {
- if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
- context->recover();
- if (context->shaderType == SH_VERTEX_SHADER)
- $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1);
- else
- $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1);
- }
- | UNIFORM {
- if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform"))
- context->recover();
- $$.setBasic(EbtVoid, EvqUniform, @1);
- }
- ;
-
-type_specifier
- : type_specifier_no_prec {
- $$ = $1;
-
- if ($$.precision == EbpUndefined) {
- $$.precision = context->symbolTable.getDefaultPrecision($1.type);
- if (context->precisionErrorCheck(@1, $$.precision, $1.type)) {
- context->recover();
- }
- }
- }
- | precision_qualifier type_specifier_no_prec {
- $$ = $2;
- $$.precision = $1;
- }
- ;
-
-precision_qualifier
- : HIGH_PRECISION {
- $$ = EbpHigh;
- }
- | MEDIUM_PRECISION {
- $$ = EbpMedium;
- }
- | LOW_PRECISION {
- $$ = EbpLow;
- }
- ;
-
-type_specifier_no_prec
- : type_specifier_nonarray {
- $$ = $1;
- }
- | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
- $$ = $1;
-
- if (context->arrayTypeErrorCheck(@2, $1))
- context->recover();
- else {
- int size;
- if (context->arraySizeErrorCheck(@2, $3, size))
- context->recover();
- $$.setArray(true, size);
- }
- }
- ;
-
-type_specifier_nonarray
- : VOID_TYPE {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtVoid, qual, @1);
- }
- | FLOAT_TYPE {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- }
- | INT_TYPE {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtInt, qual, @1);
- }
- | BOOL_TYPE {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtBool, qual, @1);
- }
- | VEC2 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(2);
- }
- | VEC3 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(3);
- }
- | VEC4 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(4);
- }
- | BVEC2 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtBool, qual, @1);
- $$.setAggregate(2);
- }
- | BVEC3 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtBool, qual, @1);
- $$.setAggregate(3);
- }
- | BVEC4 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtBool, qual, @1);
- $$.setAggregate(4);
- }
- | IVEC2 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtInt, qual, @1);
- $$.setAggregate(2);
- }
- | IVEC3 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtInt, qual, @1);
- $$.setAggregate(3);
- }
- | IVEC4 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtInt, qual, @1);
- $$.setAggregate(4);
- }
- | MATRIX2 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(2, true);
- }
- | MATRIX3 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(3, true);
- }
- | MATRIX4 {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtFloat, qual, @1);
- $$.setAggregate(4, true);
- }
- | SAMPLER2D {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtSampler2D, qual, @1);
- }
- | SAMPLERCUBE {
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtSamplerCube, qual, @1);
- }
- | SAMPLER_EXTERNAL_OES {
- if (!context->supportsExtension("GL_OES_EGL_image_external")) {
- context->error(@1, "unsupported type", "samplerExternalOES");
- context->recover();
- }
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtSamplerExternalOES, qual, @1);
- }
- | SAMPLER2DRECT {
- if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
- context->error(@1, "unsupported type", "sampler2DRect");
- context->recover();
- }
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtSampler2DRect, qual, @1);
- }
- | struct_specifier {
- $$ = $1;
- $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- }
- | TYPE_NAME {
- //
- // This is for user defined type names. The lexical phase looked up the
- // type.
- //
- TType& structure = static_cast<TVariable*>($1.symbol)->getType();
- TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
- $$.setBasic(EbtStruct, qual, @1);
- $$.userDef = &structure;
- }
- ;
-
-struct_specifier
- : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
- if (context->reservedErrorCheck(@2, *$2.string))
- context->recover();
-
- TType* structure = new TType(new TStructure($2.string, $5));
- TVariable* userTypeDef = new TVariable($2.string, *structure, true);
- if (! context->symbolTable.insert(*userTypeDef)) {
- context->error(@2, "redefinition", $2.string->c_str(), "struct");
- context->recover();
- }
- $$.setBasic(EbtStruct, EvqTemporary, @1);
- $$.userDef = structure;
- context->exitStructDeclaration();
- }
- | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
- TType* structure = new TType(new TStructure(NewPoolTString(""), $4));
- $$.setBasic(EbtStruct, EvqTemporary, @1);
- $$.userDef = structure;
- context->exitStructDeclaration();
- }
- ;
-
-struct_declaration_list
- : struct_declaration {
- $$ = $1;
- }
- | struct_declaration_list struct_declaration {
- $$ = $1;
- for (size_t i = 0; i < $2->size(); ++i) {
- TField* field = (*$2)[i];
- for (size_t j = 0; j < $$->size(); ++j) {
- if ((*$$)[j]->name() == field->name()) {
- context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str());
- context->recover();
- }
- }
- $$->push_back(field);
- }
- }
- ;
-
-struct_declaration
- : type_specifier struct_declarator_list SEMICOLON {
- $$ = $2;
-
- if (context->voidErrorCheck(@1, (*$2)[0]->name(), $1)) {
- context->recover();
- }
- for (unsigned int i = 0; i < $$->size(); ++i) {
- //
- // Careful not to replace already known aspects of type, like array-ness
- //
- TType* type = (*$$)[i]->type();
- type->setBasicType($1.type);
- type->setNominalSize($1.size);
- type->setMatrix($1.matrix);
- type->setPrecision($1.precision);
-
- // don't allow arrays of arrays
- if (type->isArray()) {
- if (context->arrayTypeErrorCheck(@1, $1))
- context->recover();
- }
- if ($1.array)
- type->setArraySize($1.arraySize);
- if ($1.userDef)
- type->setStruct($1.userDef->getStruct());
-
- if (context->structNestingErrorCheck(@1, *(*$$)[i]))
- context->recover();
- }
- }
- ;
-
-struct_declarator_list
- : struct_declarator {
- $$ = NewPoolTFieldList();
- $$->push_back($1);
- }
- | struct_declarator_list COMMA struct_declarator {
- $$->push_back($3);
- }
- ;
-
-struct_declarator
- : identifier {
- if (context->reservedErrorCheck(@1, *$1.string))
- context->recover();
-
- TType* type = new TType(EbtVoid, EbpUndefined);
- $$ = new TField(type, $1.string);
- }
- | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
- if (context->reservedErrorCheck(@1, *$1.string))
- context->recover();
-
- TType* type = new TType(EbtVoid, EbpUndefined);
- int size = 0;
- if (context->arraySizeErrorCheck(@3, $3, size))
- context->recover();
- type->setArraySize(size);
-
- $$ = new TField(type, $1.string);
- }
- ;
-
-initializer
- : assignment_expression { $$ = $1; }
- ;
-
-declaration_statement
- : declaration { $$ = $1; }
- ;
-
-statement
- : compound_statement { $$ = $1; }
- | simple_statement { $$ = $1; }
- ;
-
-// Grammar Note: No labeled statements; 'goto' is not supported.
-
-simple_statement
- : declaration_statement { $$ = $1; }
- | expression_statement { $$ = $1; }
- | selection_statement { $$ = $1; }
- | iteration_statement { $$ = $1; }
- | jump_statement { $$ = $1; }
- ;
-
-compound_statement
- : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
- | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
- if ($3 != 0) {
- $3->setOp(EOpSequence);
- $3->setLine(@$);
- }
- $$ = $3;
- }
- ;
-
-statement_no_new_scope
- : compound_statement_no_new_scope { $$ = $1; }
- | simple_statement { $$ = $1; }
- ;
-
-statement_with_scope
- : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; }
- | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; }
- ;
-
-compound_statement_no_new_scope
- // Statement that doesn't create a new scope, for selection_statement, iteration_statement
- : LEFT_BRACE RIGHT_BRACE {
- $$ = 0;
- }
- | LEFT_BRACE statement_list RIGHT_BRACE {
- if ($2) {
- $2->setOp(EOpSequence);
- $2->setLine(@$);
- }
- $$ = $2;
- }
- ;
-
-statement_list
- : statement {
- $$ = context->intermediate.makeAggregate($1, @$);
- }
- | statement_list statement {
- $$ = context->intermediate.growAggregate($1, $2, @$);
- }
- ;
-
-expression_statement
- : SEMICOLON { $$ = 0; }
- | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
- ;
-
-selection_statement
- : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
- if (context->boolErrorCheck(@1, $3))
- context->recover();
- $$ = context->intermediate.addSelection($3, $5, @1);
- }
- ;
-
-selection_rest_statement
- : statement_with_scope ELSE statement_with_scope {
- $$.node1 = $1;
- $$.node2 = $3;
- }
- | statement_with_scope {
- $$.node1 = $1;
- $$.node2 = 0;
- }
- ;
-
-// Grammar Note: No 'switch'. Switch statements not supported.
-
-condition
- // In 1996 c++ draft, conditions can include single declarations
- : expression {
- $$ = $1;
- if (context->boolErrorCheck($1->getLine(), $1))
- context->recover();
- }
- | fully_specified_type identifier EQUAL initializer {
- TIntermNode* intermNode;
- if (context->structQualifierErrorCheck(@2, $1))
- context->recover();
- if (context->boolErrorCheck(@2, $1))
- context->recover();
-
- if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode))
- $$ = $4;
- else {
- context->recover();
- $$ = 0;
- }
- }
- ;
-
-iteration_statement
- : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
- context->symbolTable.pop();
- $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
- --context->loopNestingLevel;
- }
- | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
- if (context->boolErrorCheck(@8, $6))
- context->recover();
-
- $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
- --context->loopNestingLevel;
- }
- | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
- context->symbolTable.pop();
- $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
- --context->loopNestingLevel;
- }
- ;
-
-for_init_statement
- : expression_statement {
- $$ = $1;
- }
- | declaration_statement {
- $$ = $1;
- }
- ;
-
-conditionopt
- : condition {
- $$ = $1;
- }
- | /* May be null */ {
- $$ = 0;
- }
- ;
-
-for_rest_statement
- : conditionopt SEMICOLON {
- $$.node1 = $1;
- $$.node2 = 0;
- }
- | conditionopt SEMICOLON expression {
- $$.node1 = $1;
- $$.node2 = $3;
- }
- ;
-
-jump_statement
- : CONTINUE SEMICOLON {
- if (context->loopNestingLevel <= 0) {
- context->error(@1, "continue statement only allowed in loops", "");
- context->recover();
- }
- $$ = context->intermediate.addBranch(EOpContinue, @1);
- }
- | BREAK SEMICOLON {
- if (context->loopNestingLevel <= 0) {
- context->error(@1, "break statement only allowed in loops", "");
- context->recover();
- }
- $$ = context->intermediate.addBranch(EOpBreak, @1);
- }
- | RETURN SEMICOLON {
- $$ = context->intermediate.addBranch(EOpReturn, @1);
- if (context->currentFunctionType->getBasicType() != EbtVoid) {
- context->error(@1, "non-void function must return a value", "return");
- context->recover();
- }
- }
- | RETURN expression SEMICOLON {
- $$ = context->intermediate.addBranch(EOpReturn, $2, @1);
- context->functionReturnsValue = true;
- if (context->currentFunctionType->getBasicType() == EbtVoid) {
- context->error(@1, "void function cannot return a value", "return");
- context->recover();
- } else if (*(context->currentFunctionType) != $2->getType()) {
- context->error(@1, "function return is not matching type:", "return");
- context->recover();
- }
- }
- | DISCARD SEMICOLON {
- FRAG_ONLY("discard", @1);
- $$ = context->intermediate.addBranch(EOpKill, @1);
- }
- ;
-
-// Grammar Note: No 'goto'. Gotos are not supported.
-
-translation_unit
- : external_declaration {
- $$ = $1;
- context->treeRoot = $$;
- }
- | translation_unit external_declaration {
- $$ = context->intermediate.growAggregate($1, $2, @$);
- context->treeRoot = $$;
- }
- ;
-
-external_declaration
- : function_definition {
- $$ = $1;
- }
- | declaration {
- $$ = $1;
- }
- ;
-
-function_definition
- : function_prototype {
- TFunction* function = $1.function;
-
- const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName());
-
- if (builtIn)
- {
- context->error(@1, "built-in functions cannot be redefined", function->getName().c_str());
- context->recover();
- }
-
- TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
- //
- // Note: 'prevDec' 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 (prevDec->isDefined()) {
- //
- // Then this function already has a body.
- //
- context->error(@1, "function already has a body", function->getName().c_str());
- context->recover();
- }
- prevDec->setDefined();
-
- //
- // Raise error message if main function takes any parameters or return anything other than void
- //
- if (function->getName() == "main") {
- if (function->getParamCount() > 0) {
- context->error(@1, "function cannot take any parameter(s)", function->getName().c_str());
- context->recover();
- }
- if (function->getReturnType().getBasicType() != EbtVoid) {
- context->error(@1, "", function->getReturnType().getBasicString(), "main function cannot return a value");
- context->recover();
- }
- }
-
- //
- // Remember the return type for later checking for RETURN statements.
- //
- context->currentFunctionType = &(prevDec->getReturnType());
- context->functionReturnsValue = false;
-
- //
- // Insert parameters into the symbol table.
- // If the parameter has no name, it's not an error, just don't insert it
- // (could be used for unused args).
- //
- // Also, accumulate the list of parameters into the HIL, so lower level code
- // knows where to find parameters.
- //
- TIntermAggregate* paramNodes = new TIntermAggregate;
- for (size_t i = 0; i < function->getParamCount(); i++) {
- const TParameter& param = function->getParam(i);
- if (param.name != 0) {
- TVariable *variable = new TVariable(param.name, *param.type);
- //
- // Insert the parameters with name in the symbol table.
- //
- if (! context->symbolTable.insert(*variable)) {
- context->error(@1, "redefinition", variable->getName().c_str());
- context->recover();
- delete variable;
- }
-
- //
- // Add the parameter to the HIL
- //
- paramNodes = context->intermediate.growAggregate(
- paramNodes,
- context->intermediate.addSymbol(variable->getUniqueId(),
- variable->getName(),
- variable->getType(),
- @1),
- @1);
- } else {
- paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
- }
- }
- context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
- $1.intermAggregate = paramNodes;
- context->loopNestingLevel = 0;
- }
- compound_statement_no_new_scope {
- //?? Check that all paths return a value if return type != void ?
- // May be best done as post process phase on intermediate code
- if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
- context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
- context->recover();
- }
-
- $$ = context->intermediate.growAggregate($1.intermAggregate, $3, @$);
- context->intermediate.setAggregateOperator($$, EOpFunction, @1);
- $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
- $$->getAsAggregate()->setType($1.function->getReturnType());
-
- // store the pragma information for debug and optimize and other vendor specific
- // information. This information can be queried from the parse tree
- $$->getAsAggregate()->setOptimize(context->pragma().optimize);
- $$->getAsAggregate()->setDebug(context->pragma().debug);
-
- context->symbolTable.pop();
- }
- ;
-
-%%
-
-int glslang_parse(TParseContext* context) {
- return yyparse(context);
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp b/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp
deleted file mode 100644
index 13aa96af6..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-//
-// 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/localintermediate.h"
-
-//
-// 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.
-// See the last function for how to get started.
-// 2. Print out a text based description of the tree.
-//
-
-//
-// Use this class to carry along data from node to node in
-// the traversal
-//
-class TOutputTraverser : public TIntermTraverser {
-public:
- TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
- TInfoSinkBase& sink;
-
-protected:
- void visitSymbol(TIntermSymbol*);
- void visitConstantUnion(TIntermConstantUnion*);
- bool visitBinary(Visit visit, TIntermBinary*);
- bool visitUnary(Visit visit, TIntermUnary*);
- bool visitSelection(Visit visit, TIntermSelection*);
- bool visitAggregate(Visit visit, TIntermAggregate*);
- bool visitLoop(Visit visit, TIntermLoop*);
- bool visitBranch(Visit visit, TIntermBranch*);
-};
-
-TString TType::getCompleteString() const
-{
- TStringStream stream;
-
- if (qualifier != EvqTemporary && qualifier != EvqGlobal)
- stream << getQualifierString() << " " << getPrecisionString() << " ";
- if (array)
- stream << "array[" << getArraySize() << "] of ";
- if (matrix)
- stream << size << "X" << size << " matrix of ";
- else if (size > 1)
- stream << size << "-component vector of ";
-
- stream << getBasicString();
- return stream.str();
-}
-
-//
-// Helper functions for printing, not part of traversing.
-//
-
-void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
-{
- int i;
-
- sink.location(node->getLine());
-
- for (i = 0; i < depth; ++i)
- sink << " ";
-}
-
-//
-// 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(sink, node, depth);
-
- sink << "'" << node->getSymbol() << "' ";
- sink << "(" << node->getCompleteString() << ")\n";
-}
-
-bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
-{
- TInfoSinkBase& out = sink;
-
- OutputTreeText(out, node, depth);
-
- switch (node->getOp()) {
- case EOpAssign: out << "move second child to first child"; break;
- case EOpInitialize: out << "initialize first child with second child"; break;
- case EOpAddAssign: out << "add second child into first child"; break;
- case EOpSubAssign: out << "subtract second child into first child"; break;
- case EOpMulAssign: out << "multiply second child into first child"; break;
- case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break;
- case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break;
- case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break;
- case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break;
- case EOpDivAssign: out << "divide second child into first child"; break;
- case EOpIndexDirect: out << "direct index"; break;
- case EOpIndexIndirect: out << "indirect index"; break;
- case EOpIndexDirectStruct: out << "direct index for structure"; break;
- case EOpVectorSwizzle: out << "vector swizzle"; break;
-
- case EOpAdd: out << "add"; break;
- case EOpSub: out << "subtract"; break;
- case EOpMul: out << "component-wise multiply"; break;
- case EOpDiv: out << "divide"; break;
- case EOpEqual: out << "Compare Equal"; break;
- case EOpNotEqual: out << "Compare Not Equal"; break;
- case EOpLessThan: out << "Compare Less Than"; break;
- case EOpGreaterThan: out << "Compare Greater Than"; break;
- case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
- case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
-
- case EOpVectorTimesScalar: out << "vector-scale"; break;
- case EOpVectorTimesMatrix: out << "vector-times-matrix"; break;
- case EOpMatrixTimesVector: out << "matrix-times-vector"; break;
- case EOpMatrixTimesScalar: out << "matrix-scale"; break;
- case EOpMatrixTimesMatrix: out << "matrix-multiply"; break;
-
- case EOpLogicalOr: out << "logical-or"; break;
- case EOpLogicalXor: out << "logical-xor"; break;
- case EOpLogicalAnd: out << "logical-and"; break;
- default: out << "<unknown op>";
- }
-
- out << " (" << node->getCompleteString() << ")";
-
- out << "\n";
-
- return true;
-}
-
-bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
-{
- TInfoSinkBase& out = sink;
-
- OutputTreeText(out, node, depth);
-
- switch (node->getOp()) {
- case EOpNegative: out << "Negate value"; break;
- case EOpVectorLogicalNot:
- case EOpLogicalNot: out << "Negate conditional"; break;
-
- case EOpPostIncrement: out << "Post-Increment"; break;
- case EOpPostDecrement: out << "Post-Decrement"; break;
- case EOpPreIncrement: out << "Pre-Increment"; break;
- case EOpPreDecrement: out << "Pre-Decrement"; break;
-
- case EOpConvIntToBool: out << "Convert int to bool"; break;
- case EOpConvFloatToBool:out << "Convert float to bool";break;
- case EOpConvBoolToFloat:out << "Convert bool to float";break;
- case EOpConvIntToFloat: out << "Convert int to float"; break;
- case EOpConvFloatToInt: out << "Convert float to int"; break;
- case EOpConvBoolToInt: out << "Convert bool to int"; break;
-
- case EOpRadians: out << "radians"; break;
- case EOpDegrees: out << "degrees"; break;
- case EOpSin: out << "sine"; break;
- case EOpCos: out << "cosine"; break;
- case EOpTan: out << "tangent"; break;
- case EOpAsin: out << "arc sine"; break;
- case EOpAcos: out << "arc cosine"; break;
- case EOpAtan: out << "arc tangent"; break;
-
- case EOpExp: out << "exp"; break;
- case EOpLog: out << "log"; break;
- case EOpExp2: out << "exp2"; break;
- case EOpLog2: out << "log2"; break;
- case EOpSqrt: out << "sqrt"; break;
- case EOpInverseSqrt: out << "inverse sqrt"; break;
-
- case EOpAbs: out << "Absolute value"; break;
- case EOpSign: out << "Sign"; break;
- case EOpFloor: out << "Floor"; break;
- case EOpCeil: out << "Ceiling"; break;
- case EOpFract: out << "Fraction"; break;
-
- case EOpLength: out << "length"; break;
- case EOpNormalize: out << "normalize"; break;
- // case EOpDPdx: out << "dPdx"; break;
- // case EOpDPdy: out << "dPdy"; break;
- // case EOpFwidth: out << "fwidth"; break;
-
- case EOpAny: out << "any"; break;
- case EOpAll: out << "all"; break;
-
- default:
- out.prefix(EPrefixError);
- out << "Bad unary op";
- }
-
- out << " (" << node->getCompleteString() << ")";
-
- out << "\n";
-
- return true;
-}
-
-bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- TInfoSinkBase& out = sink;
-
- if (node->getOp() == EOpNull) {
- out.prefix(EPrefixError);
- out << "node is still EOpNull!";
- return true;
- }
-
- OutputTreeText(out, node, depth);
-
- switch (node->getOp()) {
- case EOpSequence: out << "Sequence\n"; return true;
- case EOpComma: out << "Comma\n"; return true;
- case EOpFunction: out << "Function Definition: " << node->getName(); break;
- case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
- case EOpParameters: out << "Function Parameters: "; break;
-
- case EOpConstructFloat: out << "Construct float"; break;
- case EOpConstructVec2: out << "Construct vec2"; break;
- case EOpConstructVec3: out << "Construct vec3"; break;
- case EOpConstructVec4: out << "Construct vec4"; break;
- case EOpConstructBool: out << "Construct bool"; break;
- case EOpConstructBVec2: out << "Construct bvec2"; break;
- case EOpConstructBVec3: out << "Construct bvec3"; break;
- case EOpConstructBVec4: out << "Construct bvec4"; break;
- case EOpConstructInt: out << "Construct int"; break;
- case EOpConstructIVec2: out << "Construct ivec2"; break;
- case EOpConstructIVec3: out << "Construct ivec3"; break;
- case EOpConstructIVec4: out << "Construct ivec4"; break;
- case EOpConstructMat2: out << "Construct mat2"; break;
- case EOpConstructMat3: out << "Construct mat3"; break;
- case EOpConstructMat4: out << "Construct mat4"; break;
- case EOpConstructStruct: out << "Construct structure"; break;
-
- case EOpLessThan: out << "Compare Less Than"; break;
- case EOpGreaterThan: out << "Compare Greater Than"; break;
- case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
- case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
- case EOpVectorEqual: out << "Equal"; break;
- case EOpVectorNotEqual: out << "NotEqual"; break;
-
- case EOpMod: out << "mod"; break;
- case EOpPow: out << "pow"; break;
-
- case EOpAtan: out << "arc tangent"; break;
-
- case EOpMin: out << "min"; break;
- case EOpMax: out << "max"; break;
- case EOpClamp: out << "clamp"; break;
- case EOpMix: out << "mix"; break;
- case EOpStep: out << "step"; break;
- case EOpSmoothStep: out << "smoothstep"; break;
-
- case EOpDistance: out << "distance"; break;
- case EOpDot: out << "dot-product"; break;
- case EOpCross: out << "cross-product"; break;
- case EOpFaceForward: out << "face-forward"; break;
- case EOpReflect: out << "reflect"; break;
- case EOpRefract: out << "refract"; break;
- case EOpMul: out << "component-wise multiply"; break;
-
- case EOpDeclaration: out << "Declaration: "; break;
-
- default:
- out.prefix(EPrefixError);
- out << "Bad aggregation op";
- }
-
- if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
- out << " (" << node->getCompleteString() << ")";
-
- out << "\n";
-
- return true;
-}
-
-bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
-{
- TInfoSinkBase& out = sink;
-
- OutputTreeText(out, node, depth);
-
- out << "Test condition and select";
- out << " (" << node->getCompleteString() << ")\n";
-
- ++depth;
-
- OutputTreeText(sink, node, depth);
- out << "Condition\n";
- node->getCondition()->traverse(this);
-
- OutputTreeText(sink, node, depth);
- if (node->getTrueBlock()) {
- out << "true case\n";
- node->getTrueBlock()->traverse(this);
- } else
- out << "true case is null\n";
-
- if (node->getFalseBlock()) {
- OutputTreeText(sink, node, depth);
- out << "false case\n";
- node->getFalseBlock()->traverse(this);
- }
-
- --depth;
-
- return false;
-}
-
-void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
-{
- TInfoSinkBase& out = sink;
-
- size_t size = node->getType().getObjectSize();
-
- for (size_t i = 0; i < size; i++) {
- OutputTreeText(out, node, depth);
- switch (node->getUnionArrayPointer()[i].getType()) {
- case EbtBool:
- if (node->getUnionArrayPointer()[i].getBConst())
- out << "true";
- else
- out << "false";
-
- out << " (" << "const bool" << ")";
- out << "\n";
- break;
- case EbtFloat:
- out << node->getUnionArrayPointer()[i].getFConst();
- out << " (const float)\n";
- break;
- case EbtInt:
- out << node->getUnionArrayPointer()[i].getIConst();
- out << " (const int)\n";
- break;
- default:
- out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
- break;
- }
- }
-}
-
-bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
-{
- TInfoSinkBase& out = sink;
-
- OutputTreeText(out, node, depth);
-
- out << "Loop with condition ";
- if (node->getType() == ELoopDoWhile)
- out << "not ";
- out << "tested first\n";
-
- ++depth;
-
- OutputTreeText(sink, node, depth);
- if (node->getCondition()) {
- out << "Loop Condition\n";
- node->getCondition()->traverse(this);
- } else
- out << "No loop condition\n";
-
- OutputTreeText(sink, node, depth);
- if (node->getBody()) {
- out << "Loop Body\n";
- node->getBody()->traverse(this);
- } else
- out << "No loop body\n";
-
- if (node->getExpression()) {
- OutputTreeText(sink, node, depth);
- out << "Loop Terminal Expression\n";
- node->getExpression()->traverse(this);
- }
-
- --depth;
-
- return false;
-}
-
-bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
-{
- TInfoSinkBase& out = sink;
-
- OutputTreeText(out, node, depth);
-
- switch (node->getFlowOp()) {
- case EOpKill: out << "Branch: Kill"; break;
- case EOpBreak: out << "Branch: Break"; break;
- case EOpContinue: out << "Branch: Continue"; break;
- case EOpReturn: out << "Branch: Return"; break;
- default: out << "Branch: Unknown Branch"; break;
- }
-
- if (node->getExpression()) {
- out << " with expression\n";
- ++depth;
- node->getExpression()->traverse(this);
- --depth;
- } else
- out << "\n";
-
- return false;
-}
-
-//
-// This function is the one to call externally to start the traversal.
-// Individual functions can be initialized to 0 to skip processing of that
-// type of node. It's children will still be processed.
-//
-void TIntermediate::outputTree(TIntermNode* root)
-{
- if (root == 0)
- return;
-
- TOutputTraverser it(infoSink.info);
-
- root->traverse(&it);
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/intermediate.h b/Source/ThirdParty/ANGLE/src/compiler/intermediate.h
deleted file mode 100644
index 14e39fd56..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/intermediate.h
+++ /dev/null
@@ -1,635 +0,0 @@
-//
-// 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.
-//
-
-//
-// 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 __INTERMEDIATE_H
-#define __INTERMEDIATE_H
-
-#include "GLSLANG/ShaderLang.h"
-
-#include <algorithm>
-#include "compiler/Common.h"
-#include "compiler/Types.h"
-#include "compiler/ConstantUnion.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
- EOpSequence, // denotes a list of statements, or parameters, etc.
- EOpFunctionCall,
- EOpFunction, // For function definition
- EOpParameters, // an aggregate listing the parameters to a function
-
- EOpDeclaration,
- EOpPrototype,
-
- //
- // Unary operators
- //
-
- EOpNegative,
- EOpLogicalNot,
- EOpVectorLogicalNot,
-
- EOpPostIncrement,
- EOpPostDecrement,
- EOpPreIncrement,
- EOpPreDecrement,
-
- EOpConvIntToBool,
- EOpConvFloatToBool,
- EOpConvBoolToFloat,
- EOpConvIntToFloat,
- EOpConvFloatToInt,
- EOpConvBoolToInt,
-
- //
- // binary operations
- //
-
- EOpAdd,
- EOpSub,
- EOpMul,
- EOpDiv,
- EOpEqual,
- EOpNotEqual,
- EOpVectorEqual,
- EOpVectorNotEqual,
- EOpLessThan,
- EOpGreaterThan,
- EOpLessThanEqual,
- EOpGreaterThanEqual,
- EOpComma,
-
- EOpVectorTimesScalar,
- EOpVectorTimesMatrix,
- EOpMatrixTimesVector,
- EOpMatrixTimesScalar,
-
- EOpLogicalOr,
- EOpLogicalXor,
- EOpLogicalAnd,
-
- EOpIndexDirect,
- EOpIndexIndirect,
- EOpIndexDirectStruct,
-
- EOpVectorSwizzle,
-
- //
- // Built-in functions potentially mapped to operators
- //
-
- EOpRadians,
- EOpDegrees,
- EOpSin,
- EOpCos,
- EOpTan,
- EOpAsin,
- EOpAcos,
- EOpAtan,
-
- EOpPow,
- EOpExp,
- EOpLog,
- EOpExp2,
- EOpLog2,
- EOpSqrt,
- EOpInverseSqrt,
-
- EOpAbs,
- EOpSign,
- EOpFloor,
- EOpCeil,
- EOpFract,
- EOpMod,
- EOpMin,
- EOpMax,
- EOpClamp,
- EOpMix,
- EOpStep,
- EOpSmoothStep,
-
- 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
-
- EOpMatrixTimesMatrix,
-
- EOpAny,
- EOpAll,
-
- //
- // Branch
- //
-
- EOpKill, // Fragment only
- EOpReturn,
- EOpBreak,
- EOpContinue,
-
- //
- // Constructors
- //
-
- EOpConstructInt,
- EOpConstructBool,
- EOpConstructFloat,
- EOpConstructVec2,
- EOpConstructVec3,
- EOpConstructVec4,
- EOpConstructBVec2,
- EOpConstructBVec3,
- EOpConstructBVec4,
- EOpConstructIVec2,
- EOpConstructIVec3,
- EOpConstructIVec4,
- EOpConstructMat2,
- EOpConstructMat3,
- EOpConstructMat4,
- EOpConstructStruct,
-
- //
- // moves
- //
-
- EOpAssign,
- EOpInitialize,
- EOpAddAssign,
- EOpSubAssign,
- EOpMulAssign,
- EOpVectorTimesMatrixAssign,
- EOpVectorTimesScalarAssign,
- EOpMatrixTimesScalarAssign,
- EOpMatrixTimesMatrixAssign,
- EOpDivAssign
-};
-
-extern const char* getOperatorString(TOperator op);
-
-class TIntermTraverser;
-class TIntermAggregate;
-class TIntermBinary;
-class TIntermUnary;
-class TIntermConstantUnion;
-class TIntermSelection;
-class TIntermTyped;
-class TIntermSymbol;
-class TIntermLoop;
-class TInfoSink;
-
-//
-// Base class for the tree nodes
-//
-class TIntermNode {
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TIntermNode() {
- // TODO: Move this to TSourceLoc constructor
- // after getting rid of TPublicType.
- line.first_file = line.last_file = 0;
- line.first_line = line.last_line = 0;
- }
- virtual ~TIntermNode() { }
-
- const TSourceLoc& getLine() const { return line; }
- void setLine(const TSourceLoc& l) { line = l; }
-
- virtual void traverse(TIntermTraverser*) = 0;
- virtual TIntermTyped* getAsTyped() { return 0; }
- virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
- virtual TIntermAggregate* getAsAggregate() { return 0; }
- virtual TIntermBinary* getAsBinaryNode() { return 0; }
- virtual TIntermUnary* getAsUnaryNode() { return 0; }
- virtual TIntermSelection* getAsSelectionNode() { return 0; }
- virtual TIntermSymbol* getAsSymbolNode() { return 0; }
- virtual TIntermLoop* getAsLoopNode() { return 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 line;
-};
-
-//
-// 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(const TType& t) : type(t) { }
- virtual TIntermTyped* getAsTyped() { return this; }
-
- virtual bool hasSideEffects() const = 0;
-
- void setType(const TType& t) { type = t; }
- const TType& getType() const { return type; }
- TType* getTypePointer() { return &type; }
-
- TBasicType getBasicType() const { return type.getBasicType(); }
- TQualifier getQualifier() const { return type.getQualifier(); }
- TPrecision getPrecision() const { return type.getPrecision(); }
- int getNominalSize() const { return type.getNominalSize(); }
-
- bool isMatrix() const { return type.isMatrix(); }
- bool isArray() const { return type.isArray(); }
- bool isVector() const { return type.isVector(); }
- bool isScalar() const { return type.isScalar(); }
- const char* getBasicString() const { return type.getBasicString(); }
- const char* getQualifierString() const { return type.getQualifierString(); }
- TString getCompleteString() const { return type.getCompleteString(); }
-
- int totalRegisterCount() const { return type.totalRegisterCount(); }
- int elementRegisterCount() const { return type.elementRegisterCount(); }
- int getArraySize() const { return type.getArraySize(); }
-
-protected:
- TType type;
-};
-
-//
-// Handle for, do-while, and while loops.
-//
-enum TLoopType {
- ELoopFor,
- ELoopWhile,
- ELoopDoWhile
-};
-
-class TIntermLoop : public TIntermNode {
-public:
- TIntermLoop(TLoopType aType,
- TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
- TIntermNode* aBody) :
- type(aType),
- init(aInit),
- cond(aCond),
- expr(aExpr),
- body(aBody),
- unrollFlag(false) { }
-
- virtual TIntermLoop* getAsLoopNode() { return this; }
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- TLoopType getType() const { return type; }
- TIntermNode* getInit() { return init; }
- TIntermTyped* getCondition() { return cond; }
- TIntermTyped* getExpression() { return expr; }
- TIntermNode* getBody() { return body; }
-
- void setUnrollFlag(bool flag) { unrollFlag = flag; }
- bool getUnrollFlag() { return unrollFlag; }
-
-protected:
- TLoopType type;
- TIntermNode* init; // for-loop initialization
- TIntermTyped* cond; // loop exit condition
- TIntermTyped* expr; // for-loop expression
- TIntermNode* body; // loop body
-
- bool unrollFlag; // Whether the loop should be unrolled or not.
-};
-
-//
-// Handle break, continue, return, and kill.
-//
-class TIntermBranch : public TIntermNode {
-public:
- TIntermBranch(TOperator op, TIntermTyped* e) :
- flowOp(op),
- expression(e) { }
-
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- TOperator getFlowOp() { return flowOp; }
- TIntermTyped* getExpression() { return expression; }
-
-protected:
- TOperator flowOp;
- TIntermTyped* expression; // non-zero except for "return exp;" statements
-};
-
-//
-// Nodes that correspond to symbols or constants in the source code.
-//
-class TIntermSymbol : public TIntermTyped {
-public:
- // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
- // per process globalpoolallocator, then it causes increased memory usage per compile
- // it is essential to use "symbol = sym" to assign to symbol
- TIntermSymbol(int i, const TString& sym, const TType& t) :
- TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; }
-
- virtual bool hasSideEffects() const { return false; }
-
- int getId() const { return id; }
- const TString& getSymbol() const { return symbol; }
-
- void setId(int newId) { id = newId; }
- void setSymbol(const TString& sym) { symbol = sym; }
-
- const TString& getOriginalSymbol() const { return originalSymbol; }
-
- virtual void traverse(TIntermTraverser*);
- virtual TIntermSymbol* getAsSymbolNode() { return this; }
- virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
-
-protected:
- int id;
- TString symbol;
- TString originalSymbol;
-};
-
-class TIntermConstantUnion : public TIntermTyped {
-public:
- TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
-
- virtual bool hasSideEffects() const { return false; }
-
- ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
-
- int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
- float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
- bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
-
- virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
-
- TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
-
-protected:
- ConstantUnion *unionArrayPointer;
-};
-
-//
-// Intermediate class for node types that hold operators.
-//
-class TIntermOperator : public TIntermTyped {
-public:
- TOperator getOp() const { return op; }
- void setOp(TOperator o) { op = o; }
-
- bool isAssignment() const;
- bool isConstructor() const;
-
- virtual bool hasSideEffects() const { return isAssignment(); }
-
-protected:
- TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
- TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
- TOperator op;
-};
-
-//
-// Nodes for all the basic binary math operators.
-//
-class TIntermBinary : public TIntermOperator {
-public:
- TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
-
- virtual TIntermBinary* getAsBinaryNode() { return this; }
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); }
-
- void setLeft(TIntermTyped* n) { left = n; }
- void setRight(TIntermTyped* n) { right = n; }
- TIntermTyped* getLeft() const { return left; }
- TIntermTyped* getRight() const { return right; }
- bool promote(TInfoSink&);
-
- void setAddIndexClamp() { addIndexClamp = true; }
- bool getAddIndexClamp() { return addIndexClamp; }
-
-protected:
- TIntermTyped* left;
- TIntermTyped* right;
-
- // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
- bool addIndexClamp;
-};
-
-//
-// Nodes for unary math operators.
-//
-class TIntermUnary : public TIntermOperator {
-public:
- TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
- TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
-
- virtual void traverse(TIntermTraverser*);
- virtual TIntermUnary* getAsUnaryNode() { return this; }
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); }
-
- void setOperand(TIntermTyped* o) { operand = o; }
- TIntermTyped* getOperand() { return operand; }
- bool promote(TInfoSink&);
-
- void setUseEmulatedFunction() { useEmulatedFunction = true; }
- bool getUseEmulatedFunction() { return useEmulatedFunction; }
-
-protected:
- TIntermTyped* operand;
-
- // If set to true, replace the built-in function call with an emulated one
- // to work around driver bugs.
- bool useEmulatedFunction;
-};
-
-typedef TVector<TIntermNode*> TIntermSequence;
-typedef TVector<int> TQualifierList;
-
-//
-// Nodes that operate on an arbitrary sized set of children.
-//
-class TIntermAggregate : public TIntermOperator {
-public:
- TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { }
- TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
- ~TIntermAggregate() { }
-
- virtual TIntermAggregate* getAsAggregate() { return this; }
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- // Conservatively assume function calls and other aggregate operators have side-effects
- virtual bool hasSideEffects() const { return true; }
-
- TIntermSequence& getSequence() { return sequence; }
-
- void setName(const TString& n) { name = n; }
- const TString& getName() const { return name; }
-
- void setUserDefined() { userDefined = true; }
- bool isUserDefined() const { return userDefined; }
-
- void setOptimize(bool o) { optimize = o; }
- bool getOptimize() { return optimize; }
- void setDebug(bool d) { debug = d; }
- bool getDebug() { return debug; }
-
- void setUseEmulatedFunction() { useEmulatedFunction = true; }
- bool getUseEmulatedFunction() { return useEmulatedFunction; }
-
-protected:
- TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
- TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
- TIntermSequence sequence;
- TString name;
- bool userDefined; // used for user defined function names
-
- bool optimize;
- bool debug;
-
- // If set to true, replace the built-in function call with an emulated one
- // to work around driver bugs.
- bool useEmulatedFunction;
-};
-
-//
-// For if tests. Simplified since there is no switch statement.
-//
-class TIntermSelection : public TIntermTyped {
-public:
- TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
- TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
- TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
- TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
-
- virtual void traverse(TIntermTraverser*);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
-
- // Conservatively assume selections have side-effects
- virtual bool hasSideEffects() const { return true; }
-
- bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
- TIntermNode* getCondition() const { return condition; }
- TIntermNode* getTrueBlock() const { return trueBlock; }
- TIntermNode* getFalseBlock() const { return falseBlock; }
- TIntermSelection* getAsSelectionNode() { return this; }
-
-protected:
- TIntermTyped* condition;
- TIntermNode* trueBlock;
- TIntermNode* falseBlock;
-};
-
-enum Visit
-{
- PreVisit,
- InVisit,
- PostVisit
-};
-
-//
-// For traversing the tree. User should derive from this,
-// put their traversal specific data in it, and then pass
-// it to a Traverse method.
-//
-// 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.
-//
-class TIntermTraverser
-{
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
- preVisit(preVisit),
- inVisit(inVisit),
- postVisit(postVisit),
- rightToLeft(rightToLeft),
- depth(0),
- maxDepth(0) {}
- virtual ~TIntermTraverser() {}
-
- virtual void visitSymbol(TIntermSymbol*) {}
- virtual void visitConstantUnion(TIntermConstantUnion*) {}
- virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
- virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
- virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
- virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
- virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
- virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
-
- int getMaxDepth() const {return maxDepth;}
-
- void incrementDepth(TIntermNode *current)
- {
- depth++;
- maxDepth = std::max(maxDepth, depth);
- path.push_back(current);
- }
-
- void decrementDepth()
- {
- depth--;
- path.pop_back();
- }
-
- TIntermNode *getParentNode()
- {
- return path.size() == 0 ? NULL : path.back();
- }
-
- // Return the original name if hash function pointer is NULL;
- // otherwise return the hashed name.
- static TString hash(const TString& name, ShHashFunction64 hashFunction);
-
- const bool preVisit;
- const bool inVisit;
- const bool postVisit;
- const bool rightToLeft;
-
-protected:
- int depth;
- int maxDepth;
-
- // All the nodes from root to the current node's parent during traversing.
- TVector<TIntermNode *> path;
-};
-
-#endif // __INTERMEDIATE_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h b/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h
deleted file mode 100644
index ccbc40178..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// 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 _LOCAL_INTERMEDIATE_INCLUDED_
-#define _LOCAL_INTERMEDIATE_INCLUDED_
-
-#include "GLSLANG/ShaderLang.h"
-#include "compiler/intermediate.h"
-#include "compiler/SymbolTable.h"
-
-struct TVectorFields {
- int offsets[4];
- int num;
-};
-
-//
-// Set of helper functions to help parse and build the tree.
-//
-class TInfoSink;
-class TIntermediate {
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TIntermediate(TInfoSink& i) : infoSink(i) { }
-
- TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&);
- TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
- TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&, TSymbolTable&);
- TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
- TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
- TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, const TSourceLoc&, TSymbolTable&);
- TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
- TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
- TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, const TSourceLoc&);
- TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
- TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
- TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
- TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, const TSourceLoc&);
- TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
- bool parseConstTree(const TSourceLoc&, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false);
- TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, const TSourceLoc&);
- TIntermBranch* addBranch(TOperator, const TSourceLoc&);
- TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
- bool postProcess(TIntermNode*);
- void remove(TIntermNode*);
- void outputTree(TIntermNode*);
-
-private:
- void operator=(TIntermediate&); // prevent assignments
-
- TInfoSink& infoSink;
-};
-
-#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/osinclude.h b/Source/ThirdParty/ANGLE/src/compiler/osinclude.h
deleted file mode 100644
index d8bb1a797..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/osinclude.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// 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 __OSINCLUDE_H
-#define __OSINCLUDE_H
-
-//
-// This file contains contains os-specific datatypes and
-// declares any os-specific functions.
-//
-
-#if defined(_WIN32) || defined(_WIN64)
-#define ANGLE_OS_WIN
-#elif defined(__APPLE__) || defined(__linux__) || \
- defined(__FreeBSD__) || defined(__OpenBSD__) || \
- defined(__sun) || defined(ANDROID) || \
- defined(__GLIBC__) || defined(__GNU__) || \
- defined(__QNX__)
-#define ANGLE_OS_POSIX
-#else
-#error Unsupported platform.
-#endif
-
-#if defined(ANGLE_OS_WIN)
-#define STRICT
-#define VC_EXTRALEAN 1
-#include <windows.h>
-#elif defined(ANGLE_OS_POSIX)
-#include <pthread.h>
-#include <semaphore.h>
-#include <errno.h>
-#endif // ANGLE_OS_WIN
-
-
-#include "compiler/debug.h"
-
-//
-// Thread Local Storage Operations
-//
-#if defined(ANGLE_OS_WIN)
-typedef DWORD OS_TLSIndex;
-#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES)
-#elif defined(ANGLE_OS_POSIX)
-typedef pthread_key_t OS_TLSIndex;
-#define OS_INVALID_TLS_INDEX (static_cast<OS_TLSIndex>(-1))
-#endif // ANGLE_OS_WIN
-
-OS_TLSIndex OS_AllocTLSIndex();
-bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
-bool OS_FreeTLSIndex(OS_TLSIndex nIndex);
-
-inline void* OS_GetTLSValue(OS_TLSIndex nIndex)
-{
- ASSERT(nIndex != OS_INVALID_TLS_INDEX);
-#if defined(ANGLE_OS_WIN)
- return TlsGetValue(nIndex);
-#elif defined(ANGLE_OS_POSIX)
- return pthread_getspecific(nIndex);
-#endif // ANGLE_OS_WIN
-}
-
-#endif // __OSINCLUDE_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp b/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp
deleted file mode 100644
index 1e1e699ae..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// 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.
-//
-
-//
-// This file contains the posix specific functions
-//
-#include "compiler/osinclude.h"
-
-#if !defined(ANGLE_OS_POSIX)
-#error Trying to build a posix specific file in a non-posix build.
-#endif
-
-//
-// Thread Local Storage Operations
-//
-OS_TLSIndex OS_AllocTLSIndex()
-{
- pthread_key_t pPoolIndex;
-
- //
- // Create global pool key.
- //
- if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
- assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
- return false;
- }
- else {
- return pPoolIndex;
- }
-}
-
-
-bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
-{
- if (nIndex == OS_INVALID_TLS_INDEX) {
- assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
- return false;
- }
-
- if (pthread_setspecific(nIndex, lpvValue) == 0)
- return true;
- else
- return false;
-}
-
-
-bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
-{
- if (nIndex == OS_INVALID_TLS_INDEX) {
- assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
- return false;
- }
-
- //
- // Delete the global pool key.
- //
- if (pthread_key_delete(nIndex) == 0)
- return true;
- else
- return false;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp b/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp
deleted file mode 100644
index 89922fef3..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// 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/osinclude.h"
-//
-// This file contains contains the window's specific functions
-//
-
-#if !defined(ANGLE_OS_WIN)
-#error Trying to build a windows specific file in a non windows build.
-#endif
-
-
-//
-// Thread Local Storage Operations
-//
-OS_TLSIndex OS_AllocTLSIndex()
-{
- DWORD dwIndex = TlsAlloc();
- if (dwIndex == TLS_OUT_OF_INDEXES) {
- assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
- return OS_INVALID_TLS_INDEX;
- }
-
- return dwIndex;
-}
-
-
-bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
-{
- if (nIndex == OS_INVALID_TLS_INDEX) {
- assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
- return false;
- }
-
- if (TlsSetValue(nIndex, lpvValue))
- return true;
- else
- return false;
-}
-
-
-bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
-{
- if (nIndex == OS_INVALID_TLS_INDEX) {
- assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
- return false;
- }
-
- if (TlsFree(nIndex))
- return true;
- else
- return false;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp b/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp
deleted file mode 100644
index 65ed115cb..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-//
-// 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/ParseContext.h"
-
-//
-// Use this class to carry along data from node to node in
-// the traversal
-//
-class TConstTraverser : public TIntermTraverser {
-public:
- TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t)
- : error(false),
- index(0),
- unionArray(cUnion),
- type(t),
- constructorType(constructType),
- singleConstantParam(singleConstParam),
- infoSink(sink),
- symbolTable(symTable),
- size(0),
- isMatrix(false),
- matrixSize(0) {
- }
-
- bool error;
-
-protected:
- void visitSymbol(TIntermSymbol*);
- void visitConstantUnion(TIntermConstantUnion*);
- bool visitBinary(Visit visit, TIntermBinary*);
- bool visitUnary(Visit visit, TIntermUnary*);
- bool visitSelection(Visit visit, TIntermSelection*);
- bool visitAggregate(Visit visit, TIntermAggregate*);
- bool visitLoop(Visit visit, TIntermLoop*);
- bool visitBranch(Visit visit, TIntermBranch*);
-
- size_t index;
- ConstantUnion *unionArray;
- TType type;
- TOperator constructorType;
- bool singleConstantParam;
- TInfoSink& infoSink;
- TSymbolTable& symbolTable;
- size_t size; // size of the constructor ( 4 for vec4)
- bool isMatrix;
- size_t matrixSize; // dimension of the matrix (nominal size and not the instance size)
-};
-
-//
-// 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 TConstTraverser::visitSymbol(TIntermSymbol* node)
-{
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor");
- return;
-
-}
-
-bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
-{
- TQualifier qualifier = node->getType().getQualifier();
-
- if (qualifier != EvqConst) {
- TString buf;
- buf.append("'constructor' : assigning non-constant to ");
- buf.append(type.getCompleteString());
- infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
- error = true;
- return false;
- }
-
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor");
-
- return false;
-}
-
-bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
-{
- TString buf;
- buf.append("'constructor' : assigning non-constant to ");
- buf.append(type.getCompleteString());
- infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
- error = true;
- return false;
-}
-
-bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
-{
- if (!node->isConstructor() && node->getOp() != EOpComma) {
- TString buf;
- buf.append("'constructor' : assigning non-constant to ");
- buf.append(type.getCompleteString());
- infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
- error = true;
- return false;
- }
-
- if (node->getSequence().size() == 0) {
- error = true;
- return false;
- }
-
- bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
- if (flag)
- {
- singleConstantParam = true;
- constructorType = node->getOp();
- size = node->getType().getObjectSize();
-
- if (node->getType().isMatrix()) {
- isMatrix = true;
- matrixSize = node->getType().getNominalSize();
- }
- }
-
- for (TIntermSequence::iterator p = node->getSequence().begin();
- p != node->getSequence().end(); p++) {
-
- if (node->getOp() == EOpComma)
- index = 0;
-
- (*p)->traverse(this);
- }
- if (flag)
- {
- singleConstantParam = false;
- constructorType = EOpNull;
- size = 0;
- isMatrix = false;
- matrixSize = 0;
- }
- return false;
-}
-
-bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
-{
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor");
- error = true;
- return false;
-}
-
-void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
-{
- if (!node->getUnionArrayPointer())
- {
- // The constant was not initialized, this should already have been logged
- assert(infoSink.info.size() != 0);
- return;
- }
-
- ConstantUnion* leftUnionArray = unionArray;
- size_t instanceSize = type.getObjectSize();
-
- if (index >= instanceSize)
- return;
-
- if (!singleConstantParam) {
- size_t size = node->getType().getObjectSize();
-
- ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
- for (size_t i = 0; i < size; i++) {
- if (index >= instanceSize)
- return;
- leftUnionArray[index] = rightUnionArray[i];
-
- (index)++;
- }
- } else {
- size_t totalSize = index + size;
- ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
- if (!isMatrix) {
- size_t count = 0;
- for (size_t i = index; i < totalSize; i++) {
- if (i >= instanceSize)
- return;
-
- leftUnionArray[i] = rightUnionArray[count];
-
- (index)++;
-
- if (node->getType().getObjectSize() > 1)
- count++;
- }
- } else { // for matrix constructors
- size_t count = 0;
- size_t element = index;
- for (size_t i = index; i < totalSize; i++) {
- if (i >= instanceSize)
- return;
- if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
- leftUnionArray[i] = rightUnionArray[count];
- else
- leftUnionArray[i].setFConst(0.0f);
-
- (index)++;
-
- if (node->getType().getObjectSize() > 1)
- count++;
- }
- }
- }
-}
-
-bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
-{
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor");
- error = true;
- return false;
-}
-
-bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
-{
- infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor");
- error = true;
- return false;
-}
-
-//
-// This function is the one to call externally to start the traversal.
-// Individual functions can be initialized to 0 to skip processing of that
-// type of node. It's children will still be processed.
-//
-bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
-{
- if (root == 0)
- return false;
-
- TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
-
- root->traverse(&it);
- if (it.error)
- return true;
- else
- return false;
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/64bit-tokenizer-safety.patch b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/64bit-tokenizer-safety.patch
new file mode 100644
index 000000000..912520c74
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/64bit-tokenizer-safety.patch
@@ -0,0 +1,79 @@
+diff --git a/src/compiler/preprocessor/Tokenizer.cpp b/src/compiler/preprocessor/Tokenizer.cpp
+index 0d7ad58..5ef0e5e 100644
+--- a/src/compiler/preprocessor/Tokenizer.cpp
++++ b/src/compiler/preprocessor/Tokenizer.cpp
+@@ -1703,7 +1703,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+ else
+ {
+ int num_to_read =
+- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
++ static_cast<int>(YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+@@ -1737,8 +1737,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ 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;
++ num_to_read = static_cast<int>(YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
++ number_to_move - 1);
+
+ }
+
+@@ -1746,8 +1746,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
++ yy_size_t ret = 0;
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- yyg->yy_n_chars, num_to_read );
++ ret, num_to_read );
++ yyg->yy_n_chars = static_cast<int>(ret);
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+@@ -1773,13 +1775,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ if ((int) (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_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+- yyg->yy_n_chars += number_to_move;
++ yyg->yy_n_chars += static_cast<int>(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;
+
+@@ -2171,7 +2173,7 @@ void pppop_buffer_state (yyscan_t yyscanner)
+ */
+ static void ppensure_buffer_stack (yyscan_t yyscanner)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+@@ -2238,7 +2240,7 @@ YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" );
+
+- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
++ b->yy_buf_size = static_cast<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;
+@@ -2293,7 +2295,7 @@ YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, int _yybytes_len , yysc
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" );
+
+- for ( i = 0; i < _yybytes_len; ++i )
++ for ( i = 0; i < static_cast<yy_size_t>(_yybytes_len); ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.cpp
index 3e22e1f1c..fcb24e4e8 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.cpp
@@ -4,9 +4,9 @@
// found in the LICENSE file.
//
-#include "DiagnosticsBase.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
-#include <cassert>
+#include "common/debug.h"
namespace pp
{
@@ -16,8 +16,8 @@ Diagnostics::~Diagnostics()
}
void Diagnostics::report(ID id,
- const SourceLocation& loc,
- const std::string& text)
+ const SourceLocation &loc,
+ const std::string &text)
{
// TODO(alokp): Keep a count of errors and warnings.
print(id, loc, text);
@@ -25,14 +25,14 @@ void Diagnostics::report(ID id,
Diagnostics::Severity Diagnostics::severity(ID id)
{
- if ((id > ERROR_BEGIN) && (id < ERROR_END))
- return ERROR;
+ if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END))
+ return PP_ERROR;
- if ((id > WARNING_BEGIN) && (id < WARNING_END))
- return WARNING;
+ if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
+ return PP_WARNING;
- assert(false);
- return ERROR;
+ UNREACHABLE();
+ return PP_ERROR;
}
std::string Diagnostics::message(ID id)
@@ -40,86 +40,100 @@ std::string Diagnostics::message(ID id)
switch (id)
{
// Errors begin.
- case INTERNAL_ERROR:
- return "internal error";
- case OUT_OF_MEMORY:
- return "out of memory";
- case INVALID_CHARACTER:
- return "invalid character";
- case INVALID_NUMBER:
- return "invalid number";
- case INTEGER_OVERFLOW:
- return "integer overflow";
- case FLOAT_OVERFLOW:
- return "float overflow";
- case TOKEN_TOO_LONG:
- return "token too long";
- case INVALID_EXPRESSION:
- return "invalid expression";
- case DIVISION_BY_ZERO:
- return "division by zero";
- case EOF_IN_COMMENT:
- return "unexpected end of file found in comment";
- case UNEXPECTED_TOKEN:
- return "unexpected token";
- case DIRECTIVE_INVALID_NAME:
- return "invalid directive name";
- case MACRO_NAME_RESERVED:
- return "macro name is reserved";
- case MACRO_REDEFINED:
- return "macro redefined";
- case MACRO_PREDEFINED_REDEFINED:
- return "predefined macro redefined";
- case MACRO_PREDEFINED_UNDEFINED:
- return "predefined macro undefined";
- case MACRO_UNTERMINATED_INVOCATION:
- return "unterminated macro invocation";
- case MACRO_TOO_FEW_ARGS:
- return "Not enough arguments for macro";
- case MACRO_TOO_MANY_ARGS:
- return "Too many arguments for macro";
- case CONDITIONAL_ENDIF_WITHOUT_IF:
- return "unexpected #endif found without a matching #if";
- case CONDITIONAL_ELSE_WITHOUT_IF:
- return "unexpected #else found without a matching #if";
- case CONDITIONAL_ELSE_AFTER_ELSE:
- return "unexpected #else found after another #else";
- case CONDITIONAL_ELIF_WITHOUT_IF:
- return "unexpected #elif found without a matching #if";
- case CONDITIONAL_ELIF_AFTER_ELSE:
- return "unexpected #elif found after #else";
- case CONDITIONAL_UNTERMINATED:
- return "unexpected end of file found in conditional block";
- case INVALID_EXTENSION_NAME:
- return "invalid extension name";
- case INVALID_EXTENSION_BEHAVIOR:
- return "invalid extension behavior";
- case INVALID_EXTENSION_DIRECTIVE:
- return "invalid extension directive";
- case INVALID_VERSION_NUMBER:
- return "invalid version number";
- case INVALID_VERSION_DIRECTIVE:
- return "invalid version directive";
- case VERSION_NOT_FIRST_STATEMENT:
+ case PP_INTERNAL_ERROR:
+ return "internal error";
+ case PP_OUT_OF_MEMORY:
+ return "out of memory";
+ case PP_INVALID_CHARACTER:
+ return "invalid character";
+ case PP_INVALID_NUMBER:
+ return "invalid number";
+ case PP_INTEGER_OVERFLOW:
+ return "integer overflow";
+ case PP_FLOAT_OVERFLOW:
+ return "float overflow";
+ case PP_TOKEN_TOO_LONG:
+ return "token too long";
+ case PP_INVALID_EXPRESSION:
+ return "invalid expression";
+ case PP_DIVISION_BY_ZERO:
+ return "division by zero";
+ case PP_EOF_IN_COMMENT:
+ return "unexpected end of file found in comment";
+ case PP_UNEXPECTED_TOKEN:
+ return "unexpected token";
+ case PP_DIRECTIVE_INVALID_NAME:
+ return "invalid directive name";
+ case PP_MACRO_NAME_RESERVED:
+ return "macro name is reserved";
+ case PP_MACRO_REDEFINED:
+ return "macro redefined";
+ case PP_MACRO_PREDEFINED_REDEFINED:
+ return "predefined macro redefined";
+ case PP_MACRO_PREDEFINED_UNDEFINED:
+ return "predefined macro undefined";
+ case PP_MACRO_UNTERMINATED_INVOCATION:
+ return "unterminated macro invocation";
+ case PP_MACRO_UNDEFINED_WHILE_INVOKED:
+ return "macro undefined while being invoked";
+ case PP_MACRO_TOO_FEW_ARGS:
+ return "Not enough arguments for macro";
+ case PP_MACRO_TOO_MANY_ARGS:
+ return "Too many arguments for macro";
+ case PP_MACRO_DUPLICATE_PARAMETER_NAMES:
+ return "duplicate macro parameter name";
+ case PP_CONDITIONAL_ENDIF_WITHOUT_IF:
+ return "unexpected #endif found without a matching #if";
+ case PP_CONDITIONAL_ELSE_WITHOUT_IF:
+ return "unexpected #else found without a matching #if";
+ case PP_CONDITIONAL_ELSE_AFTER_ELSE:
+ return "unexpected #else found after another #else";
+ case PP_CONDITIONAL_ELIF_WITHOUT_IF:
+ return "unexpected #elif found without a matching #if";
+ case PP_CONDITIONAL_ELIF_AFTER_ELSE:
+ return "unexpected #elif found after #else";
+ case PP_CONDITIONAL_UNTERMINATED:
+ return "unexpected end of file found in conditional block";
+ case PP_INVALID_EXTENSION_NAME:
+ return "invalid extension name";
+ case PP_INVALID_EXTENSION_BEHAVIOR:
+ return "invalid extension behavior";
+ case PP_INVALID_EXTENSION_DIRECTIVE:
+ return "invalid extension directive";
+ case PP_INVALID_VERSION_NUMBER:
+ return "invalid version number";
+ case PP_INVALID_VERSION_DIRECTIVE:
+ return "invalid version directive";
+ case PP_VERSION_NOT_FIRST_STATEMENT:
return "#version directive must occur before anything else, "
"except for comments and white space";
- case INVALID_LINE_NUMBER:
- return "invalid line number";
- case INVALID_FILE_NUMBER:
- return "invalid file number";
- case INVALID_LINE_DIRECTIVE:
- return "invalid line directive";
+ case PP_VERSION_NOT_FIRST_LINE_ESSL3:
+ return "#version directive must occur on the first line of the shader";
+ case PP_INVALID_LINE_NUMBER:
+ return "invalid line number";
+ case PP_INVALID_FILE_NUMBER:
+ return "invalid file number";
+ case PP_INVALID_LINE_DIRECTIVE:
+ return "invalid line directive";
+ case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3:
+ return "extension directive must occur before any non-preprocessor tokens in ESSL3";
+ case PP_UNDEFINED_SHIFT:
+ return "shift exponent is negative or undefined";
// Errors end.
// Warnings begin.
- case EOF_IN_DIRECTIVE:
- return "unexpected end of file found in directive";
- case CONDITIONAL_UNEXPECTED_TOKEN:
- return "unexpected token after conditional expression";
- case UNRECOGNIZED_PRAGMA:
- return "unrecognized pragma";
+ case PP_EOF_IN_DIRECTIVE:
+ return "unexpected end of file found in directive";
+ case PP_CONDITIONAL_UNEXPECTED_TOKEN:
+ return "unexpected token after conditional expression";
+ case PP_UNRECOGNIZED_PRAGMA:
+ return "unrecognized pragma";
+ case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1:
+ return "extension directive should occur before any non-preprocessor tokens";
+ case PP_WARNING_MACRO_NAME_RESERVED:
+ return "macro name with a double underscore is reserved - unintented behavior is possible";
// Warnings end.
default:
- assert(false);
+ UNREACHABLE();
return "";
}
}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.h
index 07bc41184..6c3fe9ee9 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DiagnosticsBase.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
-#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
+#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
#include <string>
@@ -21,67 +21,75 @@ class Diagnostics
public:
enum Severity
{
- ERROR,
- WARNING
+ PP_ERROR,
+ PP_WARNING
};
enum ID
{
- ERROR_BEGIN,
- INTERNAL_ERROR,
- OUT_OF_MEMORY,
- INVALID_CHARACTER,
- INVALID_NUMBER,
- INTEGER_OVERFLOW,
- FLOAT_OVERFLOW,
- TOKEN_TOO_LONG,
- INVALID_EXPRESSION,
- DIVISION_BY_ZERO,
- EOF_IN_COMMENT,
- UNEXPECTED_TOKEN,
- DIRECTIVE_INVALID_NAME,
- MACRO_NAME_RESERVED,
- MACRO_REDEFINED,
- MACRO_PREDEFINED_REDEFINED,
- MACRO_PREDEFINED_UNDEFINED,
- MACRO_UNTERMINATED_INVOCATION,
- MACRO_TOO_FEW_ARGS,
- MACRO_TOO_MANY_ARGS,
- CONDITIONAL_ENDIF_WITHOUT_IF,
- CONDITIONAL_ELSE_WITHOUT_IF,
- CONDITIONAL_ELSE_AFTER_ELSE,
- CONDITIONAL_ELIF_WITHOUT_IF,
- CONDITIONAL_ELIF_AFTER_ELSE,
- CONDITIONAL_UNTERMINATED,
- INVALID_EXTENSION_NAME,
- INVALID_EXTENSION_BEHAVIOR,
- INVALID_EXTENSION_DIRECTIVE,
- INVALID_VERSION_NUMBER,
- INVALID_VERSION_DIRECTIVE,
- VERSION_NOT_FIRST_STATEMENT,
- INVALID_LINE_NUMBER,
- INVALID_FILE_NUMBER,
- INVALID_LINE_DIRECTIVE,
- ERROR_END,
+ PP_ERROR_BEGIN,
+ PP_INTERNAL_ERROR,
+ PP_OUT_OF_MEMORY,
+ PP_INVALID_CHARACTER,
+ PP_INVALID_NUMBER,
+ PP_INTEGER_OVERFLOW,
+ PP_FLOAT_OVERFLOW,
+ PP_TOKEN_TOO_LONG,
+ PP_INVALID_EXPRESSION,
+ PP_DIVISION_BY_ZERO,
+ PP_EOF_IN_COMMENT,
+ PP_UNEXPECTED_TOKEN,
+ PP_DIRECTIVE_INVALID_NAME,
+ PP_MACRO_NAME_RESERVED,
+ PP_MACRO_REDEFINED,
+ PP_MACRO_PREDEFINED_REDEFINED,
+ PP_MACRO_PREDEFINED_UNDEFINED,
+ PP_MACRO_UNTERMINATED_INVOCATION,
+ PP_MACRO_UNDEFINED_WHILE_INVOKED,
+ PP_MACRO_TOO_FEW_ARGS,
+ PP_MACRO_TOO_MANY_ARGS,
+ PP_MACRO_DUPLICATE_PARAMETER_NAMES,
+ PP_CONDITIONAL_ENDIF_WITHOUT_IF,
+ PP_CONDITIONAL_ELSE_WITHOUT_IF,
+ PP_CONDITIONAL_ELSE_AFTER_ELSE,
+ PP_CONDITIONAL_ELIF_WITHOUT_IF,
+ PP_CONDITIONAL_ELIF_AFTER_ELSE,
+ PP_CONDITIONAL_UNTERMINATED,
+ PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ PP_INVALID_EXTENSION_NAME,
+ PP_INVALID_EXTENSION_BEHAVIOR,
+ PP_INVALID_EXTENSION_DIRECTIVE,
+ PP_INVALID_VERSION_NUMBER,
+ PP_INVALID_VERSION_DIRECTIVE,
+ PP_VERSION_NOT_FIRST_STATEMENT,
+ PP_VERSION_NOT_FIRST_LINE_ESSL3,
+ PP_INVALID_LINE_NUMBER,
+ PP_INVALID_FILE_NUMBER,
+ PP_INVALID_LINE_DIRECTIVE,
+ PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+ PP_UNDEFINED_SHIFT,
+ PP_ERROR_END,
- WARNING_BEGIN,
- EOF_IN_DIRECTIVE,
- CONDITIONAL_UNEXPECTED_TOKEN,
- UNRECOGNIZED_PRAGMA,
- WARNING_END
+ PP_WARNING_BEGIN,
+ PP_EOF_IN_DIRECTIVE,
+ PP_UNRECOGNIZED_PRAGMA,
+ PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+ PP_WARNING_MACRO_NAME_RESERVED,
+ PP_WARNING_END
};
virtual ~Diagnostics();
- void report(ID id, const SourceLocation& loc, const std::string& text);
+ void report(ID id, const SourceLocation &loc, const std::string &text);
protected:
Severity severity(ID id);
std::string message(ID id);
virtual void print(ID id,
- const SourceLocation& loc,
- const std::string& text) = 0;
+ const SourceLocation &loc,
+ const std::string &text) = 0;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+
+#endif // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.cpp
index ef35c6ed5..049dae907 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.cpp
@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
-#include "DirectiveHandlerBase.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
namespace pp
{
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.h
index 2aaeec281..cf6789576 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveHandlerBase.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
-#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
#include <string>
@@ -23,21 +23,23 @@ class DirectiveHandler
public:
virtual ~DirectiveHandler();
- virtual void handleError(const SourceLocation& loc,
- const std::string& msg) = 0;
+ virtual void handleError(const SourceLocation &loc,
+ const std::string &msg) = 0;
// Handle pragma of form: #pragma name[(value)]
- virtual void handlePragma(const SourceLocation& loc,
- const std::string& name,
- const std::string& value) = 0;
+ virtual void handlePragma(const SourceLocation &loc,
+ const std::string &name,
+ const std::string &value,
+ bool stdgl) = 0;
- virtual void handleExtension(const SourceLocation& loc,
- const std::string& name,
- const std::string& behavior) = 0;
+ virtual void handleExtension(const SourceLocation &loc,
+ const std::string &name,
+ const std::string &behavior) = 0;
- virtual void handleVersion(const SourceLocation& loc,
+ virtual void handleVersion(const SourceLocation &loc,
int version) = 0;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+
+#endif // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.cpp
index 94dfdf513..643f73bd9 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.cpp
@@ -1,21 +1,22 @@
//
-// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2011-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 "DirectiveParser.h"
+#include "compiler/preprocessor/DirectiveParser.h"
-#include <cassert>
+#include <algorithm>
#include <cstdlib>
#include <sstream>
-#include "DiagnosticsBase.h"
-#include "DirectiveHandlerBase.h"
-#include "ExpressionParser.h"
-#include "MacroExpander.h"
-#include "Token.h"
-#include "Tokenizer.h"
+#include "common/debug.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+#include "compiler/preprocessor/ExpressionParser.h"
+#include "compiler/preprocessor/MacroExpander.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/preprocessor/Tokenizer.h"
namespace {
enum DirectiveType
@@ -35,58 +36,57 @@ enum DirectiveType
DIRECTIVE_VERSION,
DIRECTIVE_LINE
};
-} // namespace
-static DirectiveType getDirective(const pp::Token* token)
+DirectiveType getDirective(const pp::Token *token)
{
- static const std::string kDirectiveDefine("define");
- static const std::string kDirectiveUndef("undef");
- static const std::string kDirectiveIf("if");
- static const std::string kDirectiveIfdef("ifdef");
- static const std::string kDirectiveIfndef("ifndef");
- static const std::string kDirectiveElse("else");
- static const std::string kDirectiveElif("elif");
- static const std::string kDirectiveEndif("endif");
- static const std::string kDirectiveError("error");
- static const std::string kDirectivePragma("pragma");
- static const std::string kDirectiveExtension("extension");
- static const std::string kDirectiveVersion("version");
- static const std::string kDirectiveLine("line");
+ const char kDirectiveDefine[] = "define";
+ const char kDirectiveUndef[] = "undef";
+ const char kDirectiveIf[] = "if";
+ const char kDirectiveIfdef[] = "ifdef";
+ const char kDirectiveIfndef[] = "ifndef";
+ const char kDirectiveElse[] = "else";
+ const char kDirectiveElif[] = "elif";
+ const char kDirectiveEndif[] = "endif";
+ const char kDirectiveError[] = "error";
+ const char kDirectivePragma[] = "pragma";
+ const char kDirectiveExtension[] = "extension";
+ const char kDirectiveVersion[] = "version";
+ const char kDirectiveLine[] = "line";
if (token->type != pp::Token::IDENTIFIER)
return DIRECTIVE_NONE;
if (token->text == kDirectiveDefine)
return DIRECTIVE_DEFINE;
- else if (token->text == kDirectiveUndef)
+ if (token->text == kDirectiveUndef)
return DIRECTIVE_UNDEF;
- else if (token->text == kDirectiveIf)
+ if (token->text == kDirectiveIf)
return DIRECTIVE_IF;
- else if (token->text == kDirectiveIfdef)
+ if (token->text == kDirectiveIfdef)
return DIRECTIVE_IFDEF;
- else if (token->text == kDirectiveIfndef)
+ if (token->text == kDirectiveIfndef)
return DIRECTIVE_IFNDEF;
- else if (token->text == kDirectiveElse)
+ if (token->text == kDirectiveElse)
return DIRECTIVE_ELSE;
- else if (token->text == kDirectiveElif)
+ if (token->text == kDirectiveElif)
return DIRECTIVE_ELIF;
- else if (token->text == kDirectiveEndif)
+ if (token->text == kDirectiveEndif)
return DIRECTIVE_ENDIF;
- else if (token->text == kDirectiveError)
+ if (token->text == kDirectiveError)
return DIRECTIVE_ERROR;
- else if (token->text == kDirectivePragma)
+ if (token->text == kDirectivePragma)
return DIRECTIVE_PRAGMA;
- else if (token->text == kDirectiveExtension)
+ if (token->text == kDirectiveExtension)
return DIRECTIVE_EXTENSION;
- else if (token->text == kDirectiveVersion)
+ if (token->text == kDirectiveVersion)
return DIRECTIVE_VERSION;
- else if (token->text == kDirectiveLine)
+ if (token->text == kDirectiveLine)
return DIRECTIVE_LINE;
return DIRECTIVE_NONE;
}
-static bool isConditionalDirective(DirectiveType directive)
+bool isConditionalDirective(DirectiveType directive)
{
switch (directive)
{
@@ -103,12 +103,12 @@ static bool isConditionalDirective(DirectiveType directive)
}
// Returns true if the token represents End Of Directive.
-static bool isEOD(const pp::Token* token)
+bool isEOD(const pp::Token *token)
{
return (token->type == '\n') || (token->type == pp::Token::LAST);
}
-static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
{
while(!isEOD(token))
{
@@ -116,45 +116,41 @@ static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
}
}
-static bool isMacroNameReserved(const std::string& name)
+bool isMacroNameReserved(const std::string &name)
{
- // Names prefixed with "GL_" are reserved.
- if (name.substr(0, 3) == "GL_")
- return true;
-
- // Names containing two consecutive underscores are reserved.
- if (name.find("__") != std::string::npos)
- return true;
+ // Names prefixed with "GL_" and the name "defined" are reserved.
+ return name == "defined" || (name.substr(0, 3) == "GL_");
+}
- return false;
+bool hasDoubleUnderscores(const std::string &name)
+{
+ return (name.find("__") != std::string::npos);
}
-static bool isMacroPredefined(const std::string& name,
- const pp::MacroSet& macroSet)
+bool isMacroPredefined(const std::string &name,
+ const pp::MacroSet &macroSet)
{
pp::MacroSet::const_iterator iter = macroSet.find(name);
return iter != macroSet.end() ? iter->second.predefined : false;
}
+} // namespace anonymous
+
namespace pp
{
class DefinedParser : public Lexer
{
public:
- DefinedParser(Lexer* lexer,
- const MacroSet* macroSet,
- Diagnostics* diagnostics) :
- mLexer(lexer),
- mMacroSet(macroSet),
- mDiagnostics(diagnostics)
+ DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
+ : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
{
}
protected:
- virtual void lex(Token* token)
+ void lex(Token *token) override
{
- static const std::string kDefined("defined");
+ const char kDefined[] = "defined";
mLexer->lex(token);
if (token->type != Token::IDENTIFIER)
@@ -172,21 +168,20 @@ class DefinedParser : public Lexer
if (token->type != Token::IDENTIFIER)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
- token->location, token->text);
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
skipUntilEOD(mLexer, token);
return;
}
MacroSet::const_iterator iter = mMacroSet->find(token->text);
- std::string expression = iter != mMacroSet->end() ? "1" : "0";
+ std::string expression = iter != mMacroSet->end() ? "1" : "0";
if (paren)
{
mLexer->lex(token);
if (token->type != ')')
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
- token->location, token->text);
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+ token->text);
skipUntilEOD(mLexer, token);
return;
}
@@ -199,24 +194,26 @@ class DefinedParser : public Lexer
}
private:
- Lexer* mLexer;
- const MacroSet* mMacroSet;
- Diagnostics* mDiagnostics;
+ Lexer *mLexer;
+ const MacroSet *mMacroSet;
+ Diagnostics *mDiagnostics;
};
-DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
- MacroSet* macroSet,
- Diagnostics* diagnostics,
- DirectiveHandler* directiveHandler) :
- mPastFirstStatement(false),
- mTokenizer(tokenizer),
- mMacroSet(macroSet),
- mDiagnostics(diagnostics),
- mDirectiveHandler(directiveHandler)
+DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
+ MacroSet *macroSet,
+ Diagnostics *diagnostics,
+ DirectiveHandler *directiveHandler)
+ : mPastFirstStatement(false),
+ mSeenNonPreprocessorToken(false),
+ mTokenizer(tokenizer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics),
+ mDirectiveHandler(directiveHandler),
+ mShaderVersion(100)
{
}
-void DirectiveParser::lex(Token* token)
+void DirectiveParser::lex(Token *token)
{
do
{
@@ -227,26 +224,31 @@ void DirectiveParser::lex(Token* token)
parseDirective(token);
mPastFirstStatement = true;
}
+ else if (!isEOD(token))
+ {
+ mSeenNonPreprocessorToken = true;
+ }
if (token->type == Token::LAST)
{
if (!mConditionalStack.empty())
{
- const ConditionalBlock& block = mConditionalStack.back();
- mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+ const ConditionalBlock &block = mConditionalStack.back();
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
block.location, block.type);
}
break;
}
- } while (skipping() || (token->type == '\n'));
+ }
+ while (skipping() || (token->type == '\n'));
mPastFirstStatement = true;
}
-void DirectiveParser::parseDirective(Token* token)
+void DirectiveParser::parseDirective(Token *token)
{
- assert(token->type == Token::PP_HASH);
+ ASSERT(token->type == Token::PP_HASH);
mTokenizer->lex(token);
if (isEOD(token))
@@ -268,7 +270,7 @@ void DirectiveParser::parseDirective(Token* token)
switch(directive)
{
case DIRECTIVE_NONE:
- mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+ mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
break;
@@ -312,41 +314,51 @@ void DirectiveParser::parseDirective(Token* token)
parseLine(token);
break;
default:
- assert(false);
- break;
+ UNREACHABLE();
+ break;
}
skipUntilEOD(mTokenizer, token);
if (token->type == Token::LAST)
{
- mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+ mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
token->location, token->text);
}
}
-void DirectiveParser::parseDefine(Token* token)
+void DirectiveParser::parseDefine(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_DEFINE);
+ ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
return;
}
if (isMacroPredefined(token->text, *mMacroSet))
{
- mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
token->location, token->text);
return;
}
if (isMacroNameReserved(token->text))
{
- mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+ mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
token->location, token->text);
return;
}
+ // Using double underscores is allowed, but may result in unintended
+ // behavior, so a warning is issued. At the time of writing this was
+ // specified in ESSL 3.10, but the intent judging from Khronos
+ // discussions and dEQP tests was that double underscores should be
+ // allowed in earlier ESSL versions too.
+ if (hasDoubleUnderscores(token->text))
+ {
+ mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
+ token->text);
+ }
Macro macro;
macro.type = Macro::kTypeObj;
@@ -357,18 +369,28 @@ void DirectiveParser::parseDefine(Token* token)
{
// Function-like macro. Collect arguments.
macro.type = Macro::kTypeFunc;
- do {
+ do
+ {
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
break;
+
+ if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
+ {
+ mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
+ token->location, token->text);
+ return;
+ }
+
macro.parameters.push_back(token->text);
mTokenizer->lex(token); // Get ','.
- } while (token->type == ',');
+ }
+ while (token->type == ',');
if (token->type != ')')
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location,
token->text);
return;
@@ -396,7 +418,7 @@ void DirectiveParser::parseDefine(Token* token)
MacroSet::const_iterator iter = mMacroSet->find(macro.name);
if (iter != mMacroSet->end() && !macro.equals(iter->second))
{
- mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
+ mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
token->location,
macro.name);
return;
@@ -404,14 +426,14 @@ void DirectiveParser::parseDefine(Token* token)
mMacroSet->insert(std::make_pair(macro.name, macro));
}
-void DirectiveParser::parseUndef(Token* token)
+void DirectiveParser::parseUndef(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_UNDEF);
+ ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
return;
}
@@ -421,8 +443,15 @@ void DirectiveParser::parseUndef(Token* token)
{
if (iter->second.predefined)
{
- mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
token->location, token->text);
+ return;
+ }
+ else if (iter->second.expansionCount > 0)
+ {
+ mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
+ token->text);
+ return;
}
else
{
@@ -431,39 +460,45 @@ void DirectiveParser::parseUndef(Token* token)
}
mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
}
-void DirectiveParser::parseIf(Token* token)
+void DirectiveParser::parseIf(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_IF);
+ ASSERT(getDirective(token) == DIRECTIVE_IF);
parseConditionalIf(token);
}
-void DirectiveParser::parseIfdef(Token* token)
+void DirectiveParser::parseIfdef(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_IFDEF);
+ ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
parseConditionalIf(token);
}
-void DirectiveParser::parseIfndef(Token* token)
+void DirectiveParser::parseIfndef(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_IFNDEF);
+ ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
parseConditionalIf(token);
}
-void DirectiveParser::parseElse(Token* token)
+void DirectiveParser::parseElse(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_ELSE);
+ ASSERT(getDirective(token) == DIRECTIVE_ELSE);
if (mConditionalStack.empty())
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
}
- ConditionalBlock& block = mConditionalStack.back();
+ ConditionalBlock &block = mConditionalStack.back();
if (block.skipBlock)
{
// No diagnostics. Just skip the whole line.
@@ -472,7 +507,7 @@ void DirectiveParser::parseElse(Token* token)
}
if (block.foundElseGroup)
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
@@ -482,29 +517,29 @@ void DirectiveParser::parseElse(Token* token)
block.skipGroup = block.foundValidGroup;
block.foundValidGroup = true;
- // Warn if there are extra tokens after #else.
+ // Check if there are extra tokens after #else.
mTokenizer->lex(token);
if (!isEOD(token))
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
}
}
-void DirectiveParser::parseElif(Token* token)
+void DirectiveParser::parseElif(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_ELIF);
+ ASSERT(getDirective(token) == DIRECTIVE_ELIF);
if (mConditionalStack.empty())
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
}
- ConditionalBlock& block = mConditionalStack.back();
+ ConditionalBlock &block = mConditionalStack.back();
if (block.skipBlock)
{
// No diagnostics. Just skip the whole line.
@@ -513,7 +548,7 @@ void DirectiveParser::parseElif(Token* token)
}
if (block.foundElseGroup)
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
@@ -532,13 +567,13 @@ void DirectiveParser::parseElif(Token* token)
block.foundValidGroup = expression != 0;
}
-void DirectiveParser::parseEndif(Token* token)
+void DirectiveParser::parseEndif(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_ENDIF);
+ ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
if (mConditionalStack.empty())
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
@@ -546,19 +581,19 @@ void DirectiveParser::parseEndif(Token* token)
mConditionalStack.pop_back();
- // Warn if there are tokens after #endif.
+ // Check if there are tokens after #endif.
mTokenizer->lex(token);
if (!isEOD(token))
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
}
}
-void DirectiveParser::parseError(Token* token)
+void DirectiveParser::parseError(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_ERROR);
+ ASSERT(getDirective(token) == DIRECTIVE_ERROR);
std::ostringstream stream;
mTokenizer->lex(token);
@@ -571,9 +606,9 @@ void DirectiveParser::parseError(Token* token)
}
// Parses pragma of form: #pragma name[(value)].
-void DirectiveParser::parsePragma(Token* token)
+void DirectiveParser::parsePragma(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_PRAGMA);
+ ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
enum State
{
@@ -588,6 +623,11 @@ void DirectiveParser::parsePragma(Token* token)
int state = PRAGMA_NAME;
mTokenizer->lex(token);
+ bool stdgl = token->text == "STDGL";
+ if (stdgl)
+ {
+ mTokenizer->lex(token);
+ }
while ((token->type != '\n') && (token->type != Token::LAST))
{
switch(state++)
@@ -618,18 +658,18 @@ void DirectiveParser::parsePragma(Token* token)
(state == RIGHT_PAREN + 1)); // With value.
if (!valid)
{
- mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
+ mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
token->location, name);
}
else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
{
- mDirectiveHandler->handlePragma(token->location, name, value);
+ mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
}
}
-void DirectiveParser::parseExtension(Token* token)
+void DirectiveParser::parseExtension(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_EXTENSION);
+ ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
enum State
{
@@ -650,7 +690,7 @@ void DirectiveParser::parseExtension(Token* token)
case EXT_NAME:
if (valid && (token->type != Token::IDENTIFIER))
{
- mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
+ mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
token->location, token->text);
valid = false;
}
@@ -659,7 +699,7 @@ void DirectiveParser::parseExtension(Token* token)
case COLON:
if (valid && (token->type != ':'))
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
valid = false;
}
@@ -667,7 +707,7 @@ void DirectiveParser::parseExtension(Token* token)
case EXT_BEHAVIOR:
if (valid && (token->type != Token::IDENTIFIER))
{
- mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
+ mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
token->location, token->text);
valid = false;
}
@@ -676,7 +716,7 @@ void DirectiveParser::parseExtension(Token* token)
default:
if (valid)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
valid = false;
}
@@ -686,21 +726,35 @@ void DirectiveParser::parseExtension(Token* token)
}
if (valid && (state != EXT_BEHAVIOR + 1))
{
- mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
+ mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
token->location, token->text);
valid = false;
}
+ if (valid && mSeenNonPreprocessorToken)
+ {
+ if (mShaderVersion >= 300)
+ {
+ mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+ token->location, token->text);
+ valid = false;
+ }
+ else
+ {
+ mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+ token->location, token->text);
+ }
+ }
if (valid)
mDirectiveHandler->handleExtension(token->location, name, behavior);
}
-void DirectiveParser::parseVersion(Token* token)
+void DirectiveParser::parseVersion(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_VERSION);
+ ASSERT(getDirective(token) == DIRECTIVE_VERSION);
if (mPastFirstStatement)
{
- mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return;
@@ -708,7 +762,9 @@ void DirectiveParser::parseVersion(Token* token)
enum State
{
- VERSION_NUMBER
+ VERSION_NUMBER,
+ VERSION_PROFILE,
+ VERSION_ENDLINE
};
bool valid = true;
@@ -716,127 +772,141 @@ void DirectiveParser::parseVersion(Token* token)
int state = VERSION_NUMBER;
mTokenizer->lex(token);
- while ((token->type != '\n') && (token->type != Token::LAST))
+ while (valid && (token->type != '\n') && (token->type != Token::LAST))
{
- switch (state++)
+ switch (state)
{
case VERSION_NUMBER:
- if (valid && (token->type != Token::CONST_INT))
+ if (token->type != Token::CONST_INT)
{
- mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+ mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
token->location, token->text);
valid = false;
}
if (valid && !token->iValue(&version))
{
- mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
token->location, token->text);
valid = false;
}
- break;
- default:
if (valid)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
+ }
+ break;
+ case VERSION_PROFILE:
+ if (token->type != Token::IDENTIFIER || token->text != "es")
+ {
+ mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
token->location, token->text);
valid = false;
}
+ state = VERSION_ENDLINE;
+ break;
+ default:
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
break;
}
+
mTokenizer->lex(token);
}
- if (valid && (state != VERSION_NUMBER + 1))
+
+ if (valid && (state != VERSION_ENDLINE))
{
- mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+ mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
token->location, token->text);
valid = false;
}
+
+ if (valid && version >= 300 && token->location.line > 1)
+ {
+ mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
+ token->location, token->text);
+ valid = false;
+ }
+
if (valid)
+ {
mDirectiveHandler->handleVersion(token->location, version);
+ mShaderVersion = version;
+ PredefineMacro(mMacroSet, "__VERSION__", version);
+ }
}
-void DirectiveParser::parseLine(Token* token)
+void DirectiveParser::parseLine(Token *token)
{
- assert(getDirective(token) == DIRECTIVE_LINE);
-
- enum State
- {
- LINE_NUMBER,
- FILE_NUMBER
- };
+ ASSERT(getDirective(token) == DIRECTIVE_LINE);
bool valid = true;
+ bool parsedFileNumber = false;
int line = 0, file = 0;
- int state = LINE_NUMBER;
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
+
+ // Lex the first token after "#line" so we can check it for EOD.
macroExpander.lex(token);
- while ((token->type != '\n') && (token->type != Token::LAST))
+
+ if (isEOD(token))
{
- switch (state++)
+ mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
+ valid = false;
+ }
+ else
+ {
+ ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+ ExpressionParser::ErrorSettings errorSettings;
+
+ // See GLES3 section 12.42
+ errorSettings.integerLiteralsMustFit32BitSignedRange = true;
+
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
+ // The first token was lexed earlier to check if it was EOD. Include
+ // the token in parsing for a second time by setting the
+ // parsePresetToken flag to true.
+ expressionParser.parse(token, &line, true, errorSettings, &valid);
+ if (!isEOD(token) && valid)
+ {
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
+ // After parsing the line expression expressionParser has also
+ // advanced to the first token of the file expression - this is the
+ // token that makes the parser reduce the "input" rule for the line
+ // expression and stop. So we're using parsePresetToken = true here
+ // as well.
+ expressionParser.parse(token, &file, true, errorSettings, &valid);
+ parsedFileNumber = true;
+ }
+ if (!isEOD(token))
{
- case LINE_NUMBER:
- if (valid && (token->type != Token::CONST_INT))
- {
- mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
- token->location, token->text);
- valid = false;
- }
- if (valid && !token->iValue(&line))
- {
- mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
- token->location, token->text);
- valid = false;
- }
- break;
- case FILE_NUMBER:
- if (valid && (token->type != Token::CONST_INT))
- {
- mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
- token->location, token->text);
- valid = false;
- }
- if (valid && !token->iValue(&file))
- {
- mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
- token->location, token->text);
- valid = false;
- }
- break;
- default:
if (valid)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
valid = false;
}
- break;
+ skipUntilEOD(mTokenizer, token);
}
- macroExpander.lex(token);
}
- if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
- {
- mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
- token->location, token->text);
- valid = false;
- }
if (valid)
{
mTokenizer->setLineNumber(line);
- if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+ if (parsedFileNumber)
+ mTokenizer->setFileNumber(file);
}
}
bool DirectiveParser::skipping() const
{
- if (mConditionalStack.empty()) return false;
+ if (mConditionalStack.empty())
+ return false;
const ConditionalBlock& block = mConditionalStack.back();
return block.skipBlock || block.skipGroup;
}
-void DirectiveParser::parseConditionalIf(Token* token)
+void DirectiveParser::parseConditionalIf(Token *token)
{
ConditionalBlock block;
block.type = token->text;
@@ -868,8 +938,8 @@ void DirectiveParser::parseConditionalIf(Token* token)
expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
break;
default:
- assert(false);
- break;
+ UNREACHABLE();
+ break;
}
block.skipGroup = expression == 0;
block.foundValidGroup = expression != 0;
@@ -877,23 +947,26 @@ void DirectiveParser::parseConditionalIf(Token* token)
mConditionalStack.push_back(block);
}
-int DirectiveParser::parseExpressionIf(Token* token)
+int DirectiveParser::parseExpressionIf(Token *token)
{
- assert((getDirective(token) == DIRECTIVE_IF) ||
- (getDirective(token) == DIRECTIVE_ELIF));
+ ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
ExpressionParser expressionParser(&macroExpander, mDiagnostics);
int expression = 0;
- macroExpander.lex(token);
- expressionParser.parse(token, &expression);
+ ExpressionParser::ErrorSettings errorSettings;
+ errorSettings.integerLiteralsMustFit32BitSignedRange = false;
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
+
+ bool valid = true;
+ expressionParser.parse(token, &expression, false, errorSettings, &valid);
- // Warn if there are tokens after #if expression.
+ // Check if there are tokens after #if expression.
if (!isEOD(token))
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
}
@@ -901,15 +974,14 @@ int DirectiveParser::parseExpressionIf(Token* token)
return expression;
}
-int DirectiveParser::parseExpressionIfdef(Token* token)
+int DirectiveParser::parseExpressionIfdef(Token *token)
{
- assert((getDirective(token) == DIRECTIVE_IFDEF) ||
- (getDirective(token) == DIRECTIVE_IFNDEF));
+ ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
{
- mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
return 0;
@@ -918,11 +990,11 @@ int DirectiveParser::parseExpressionIfdef(Token* token)
MacroSet::const_iterator iter = mMacroSet->find(token->text);
int expression = iter != mMacroSet->end() ? 1 : 0;
- // Warn if there are tokens after #ifdef expression.
+ // Check if there are tokens after #ifdef expression.
mTokenizer->lex(token);
if (!isEOD(token))
{
- mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mTokenizer, token);
}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.h
index 8a7f0072b..f0e889c8a 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/DirectiveParser.h
@@ -4,13 +4,12 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
-#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_
-#include "Lexer.h"
-#include "Macro.h"
-#include "pp_utils.h"
-#include "SourceLocation.h"
+#include "compiler/preprocessor/Lexer.h"
+#include "compiler/preprocessor/Macro.h"
+#include "compiler/preprocessor/SourceLocation.h"
namespace pp
{
@@ -22,35 +21,34 @@ class Tokenizer;
class DirectiveParser : public Lexer
{
public:
- DirectiveParser(Tokenizer* tokenizer,
- MacroSet* macroSet,
- Diagnostics* diagnostics,
- DirectiveHandler* directiveHandler);
+ DirectiveParser(Tokenizer *tokenizer,
+ MacroSet *macroSet,
+ Diagnostics *diagnostics,
+ DirectiveHandler *directiveHandler);
- virtual void lex(Token* token);
+ void lex(Token *token) override;
private:
- PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
- void parseDirective(Token* token);
- void parseDefine(Token* token);
- void parseUndef(Token* token);
- void parseIf(Token* token);
- void parseIfdef(Token* token);
- void parseIfndef(Token* token);
- void parseElse(Token* token);
- void parseElif(Token* token);
- void parseEndif(Token* token);
- void parseError(Token* token);
- void parsePragma(Token* token);
- void parseExtension(Token* token);
- void parseVersion(Token* token);
- void parseLine(Token* token);
+ void parseDirective(Token *token);
+ void parseDefine(Token *token);
+ void parseUndef(Token *token);
+ void parseIf(Token *token);
+ void parseIfdef(Token *token);
+ void parseIfndef(Token *token);
+ void parseElse(Token *token);
+ void parseElif(Token *token);
+ void parseEndif(Token *token);
+ void parseError(Token *token);
+ void parsePragma(Token *token);
+ void parseExtension(Token *token);
+ void parseVersion(Token *token);
+ void parseLine(Token *token);
bool skipping() const;
- void parseConditionalIf(Token* token);
- int parseExpressionIf(Token* token);
- int parseExpressionIfdef(Token* token);
+ void parseConditionalIf(Token *token);
+ int parseExpressionIf(Token *token);
+ int parseExpressionIfdef(Token *token);
struct ConditionalBlock
{
@@ -61,22 +59,25 @@ class DirectiveParser : public Lexer
bool foundValidGroup;
bool foundElseGroup;
- ConditionalBlock() :
- skipBlock(false),
- skipGroup(false),
- foundValidGroup(false),
- foundElseGroup(false)
+ ConditionalBlock()
+ : skipBlock(false),
+ skipGroup(false),
+ foundValidGroup(false),
+ foundElseGroup(false)
{
}
};
bool mPastFirstStatement;
+ bool mSeenNonPreprocessorToken; // Tracks if a non-preprocessor token has been seen yet. Some macros, such as
+ // #extension must be declared before all shader code.
std::vector<ConditionalBlock> mConditionalStack;
- Tokenizer* mTokenizer;
- MacroSet* mMacroSet;
- Diagnostics* mDiagnostics;
- DirectiveHandler* mDirectiveHandler;
+ Tokenizer *mTokenizer;
+ MacroSet *mMacroSet;
+ Diagnostics *mDiagnostics;
+ DirectiveHandler *mDirectiveHandler;
+ int mShaderVersion;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+#endif // COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.cpp
index 1fae00945..a8df2351e 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.cpp
@@ -1,10 +1,10 @@
-/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
+/* A Bison parser, made by GNU Bison 3.0.4. */
-/* A Bison parser, made by GNU Bison 3.0.1. */
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+ 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
@@ -46,7 +46,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "3.0.1"
+#define YYBISON_VERSION "3.0.4"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -88,7 +88,7 @@
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#elif defined(_MSC_VER)
-#pragma warning(disable: 4065 4701)
+#pragma warning(disable: 4065 4244 4701 4702)
#endif
#include "ExpressionParser.h"
@@ -101,17 +101,16 @@
#include <cassert>
#include <sstream>
+#include <stdint.h>
#include "DiagnosticsBase.h"
#include "Lexer.h"
#include "Token.h"
+#include "common/mathutil.h"
+
+typedef int32_t YYSTYPE;
+typedef uint32_t UNSIGNED_TYPE;
-#if defined(_MSC_VER)
-typedef __int64 YYSTYPE;
-#else
-#include <stdint.h>
-typedef intmax_t YYSTYPE;
-#endif // _MSC_VER
#define YYENABLE_NLS 0
#define YYLTYPE_IS_TRIVIAL 1
#define YYSTYPE_IS_TRIVIAL 1
@@ -124,6 +123,17 @@ struct Context
pp::Lexer* lexer;
pp::Token* token;
int* result;
+ bool parsePresetToken;
+
+ pp::ExpressionParser::ErrorSettings errorSettings;
+ bool *valid;
+
+ void startIgnoreErrors() { ++ignoreErrors; }
+ void endIgnoreErrors() { --ignoreErrors; }
+
+ bool isIgnoringErrors() { return ignoreErrors > 0; }
+
+ int ignoreErrors;
};
} // namespace
@@ -164,15 +174,16 @@ extern int ppdebug;
enum yytokentype
{
TOK_CONST_INT = 258,
- TOK_OP_OR = 259,
- TOK_OP_AND = 260,
- TOK_OP_EQ = 261,
- TOK_OP_NE = 262,
- TOK_OP_LE = 263,
- TOK_OP_GE = 264,
- TOK_OP_LEFT = 265,
- TOK_OP_RIGHT = 266,
- TOK_UNARY = 267
+ TOK_IDENTIFIER = 259,
+ TOK_OP_OR = 260,
+ TOK_OP_AND = 261,
+ TOK_OP_EQ = 262,
+ TOK_OP_NE = 263,
+ TOK_OP_LE = 264,
+ TOK_OP_GE = 265,
+ TOK_OP_LEFT = 266,
+ TOK_OP_RIGHT = 267,
+ TOK_UNARY = 268
};
#endif
@@ -431,23 +442,23 @@ union yyalloc
#endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 14
+#define YYFINAL 15
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 175
+#define YYLAST 176
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 27
+#define YYNTOKENS 28
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 3
+#define YYNNTS 5
/* YYNRULES -- Number of rules. */
-#define YYNRULES 26
+#define YYNRULES 29
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 52
+#define YYNSTATES 55
/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
by yylex, with out-of-bounds checking. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 267
+#define YYMAXUTOK 268
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -459,16 +470,16 @@ 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, 23, 2, 2, 2, 21, 8, 2,
- 25, 26, 19, 17, 2, 18, 2, 20, 2, 2,
+ 2, 2, 2, 24, 2, 2, 2, 22, 9, 2,
+ 26, 27, 20, 18, 2, 19, 2, 21, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 11, 2, 12, 2, 2, 2, 2, 2, 2, 2,
+ 12, 2, 13, 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, 7, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 8, 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, 6, 2, 24, 2, 2, 2,
+ 2, 2, 2, 2, 7, 2, 25, 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,
@@ -482,16 +493,16 @@ static const yytype_uint8 yytranslate[] =
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, 9, 10, 13, 14, 15, 16, 22
+ 5, 6, 10, 11, 14, 15, 16, 17, 23
};
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
-static const yytype_uint8 yyrline[] =
+static const yytype_uint16 yyrline[] =
{
- 0, 97, 97, 104, 105, 108, 111, 114, 117, 120,
- 123, 126, 129, 132, 135, 138, 141, 144, 147, 150,
- 163, 176, 179, 182, 185, 188, 191
+ 0, 108, 108, 115, 116, 127, 127, 148, 148, 169,
+ 172, 175, 178, 181, 184, 187, 190, 193, 196, 221,
+ 246, 249, 252, 272, 299, 302, 305, 308, 320, 323
};
#endif
@@ -500,11 +511,11 @@ static const yytype_uint8 yyrline[] =
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
- "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_OP_OR",
- "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE", "'<'",
- "'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT", "'+'",
- "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('", "')'",
- "$accept", "input", "expression", YY_NULLPTR
+ "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_IDENTIFIER",
+ "TOK_OP_OR", "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE",
+ "'<'", "'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT",
+ "'+'", "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('",
+ "')'", "$accept", "input", "expression", "$@1", "$@2", YY_NULLPTR
};
#endif
@@ -513,16 +524,16 @@ static const char *const yytname[] =
(internal) symbol number NUM (which must be that of a token). */
static const yytype_uint16 yytoknum[] =
{
- 0, 256, 257, 258, 259, 260, 124, 94, 38, 261,
- 262, 60, 62, 263, 264, 265, 266, 43, 45, 42,
- 47, 37, 267, 33, 126, 40, 41
+ 0, 256, 257, 258, 259, 260, 261, 124, 94, 38,
+ 262, 263, 60, 62, 264, 265, 266, 267, 43, 45,
+ 42, 47, 37, 268, 33, 126, 40, 41
};
# endif
-#define YYPACT_NINF -11
+#define YYPACT_NINF -12
#define yypact_value_is_default(Yystate) \
- (!!((Yystate) == (-11)))
+ (!!((Yystate) == (-12)))
#define YYTABLE_NINF -1
@@ -533,12 +544,12 @@ static const yytype_uint16 yytoknum[] =
STATE-NUM. */
static const yytype_int16 yypact[] =
{
- 46, -11, 46, 46, 46, 46, 46, 12, 68, -11,
- -11, -11, -11, 27, -11, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, -11, 85, 101, 116, 130, 143, 154,
- 154, -10, -10, -10, -10, 37, 37, 31, 31, -11,
- -11, -11
+ 31, -12, -12, 31, 31, 31, 31, 31, 51, 76,
+ -12, -12, -12, -12, 53, -12, -12, -12, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, -12, 31, 31, 124, 138, 26,
+ 149, 149, -11, -11, -11, -11, 154, 154, -8, -8,
+ -12, -12, -12, 93, 109
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -546,24 +557,24 @@ static const yytype_int16 yypact[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 0, 3, 0, 0, 0, 0, 0, 0, 2, 25,
- 24, 22, 23, 0, 1, 0, 0, 0, 0, 0,
+ 0, 3, 4, 0, 0, 0, 0, 0, 0, 2,
+ 28, 27, 25, 26, 0, 1, 5, 7, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 26, 4, 5, 6, 7, 8, 10,
- 9, 14, 13, 12, 11, 16, 15, 18, 17, 21,
- 20, 19
+ 0, 0, 0, 0, 29, 0, 0, 9, 10, 11,
+ 13, 12, 17, 16, 15, 14, 19, 18, 21, 20,
+ 24, 23, 22, 6, 8
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -11, -11, -2
+ -12, -12, -3, -12, -12
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
- -1, 7, 8
+ -1, 8, 9, 35, 36
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
@@ -571,74 +582,74 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_uint8 yytable[] =
{
- 9, 10, 11, 12, 13, 26, 27, 28, 29, 30,
- 31, 32, 14, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 1,
- 30, 31, 32, 33, 28, 29, 30, 31, 32, 0,
- 0, 0, 0, 2, 3, 0, 0, 0, 0, 4,
- 5, 6, 15, 16, 17, 18, 19, 20, 21, 22,
+ 10, 11, 12, 13, 14, 27, 28, 29, 30, 31,
+ 32, 33, 31, 32, 33, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 0, 53, 54, 1, 2, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 3,
+ 4, 15, 0, 0, 0, 5, 6, 7, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 0, 0, 0, 0,
+ 34, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 32, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 31, 32
+ 33, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 29, 30, 31, 32, 33
};
static const yytype_int8 yycheck[] =
{
- 2, 3, 4, 5, 6, 15, 16, 17, 18, 19,
- 20, 21, 0, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 13, 14, 15, 16, 17, 18, 19, 20, 21, 3,
- 19, 20, 21, 26, 17, 18, 19, 20, 21, -1,
- -1, -1, -1, 17, 18, -1, -1, -1, -1, 23,
- 24, 25, 4, 5, 6, 7, 8, 9, 10, 11,
+ 3, 4, 5, 6, 7, 16, 17, 18, 19, 20,
+ 21, 22, 20, 21, 22, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, -1, 35, 36, 3, 4, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 18,
+ 19, 0, -1, -1, -1, 24, 25, 26, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, -1, -1, -1, -1,
+ 27, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 20, 21, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21
+ 22, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 18, 19, 20, 21, 22
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 3, 17, 18, 23, 24, 25, 28, 29, 29,
- 29, 29, 29, 29, 0, 4, 5, 6, 7, 8,
+ 0, 3, 4, 18, 19, 24, 25, 26, 29, 30,
+ 30, 30, 30, 30, 30, 0, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 26, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29
+ 19, 20, 21, 22, 27, 31, 32, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30
};
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 27, 28, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29
+ 0, 28, 29, 30, 30, 31, 30, 32, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
};
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
- 0, 2, 1, 1, 3, 3, 3, 3, 3, 3,
+ 0, 2, 1, 1, 1, 0, 4, 0, 4, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 2, 2, 2, 2, 3
+ 3, 3, 3, 3, 3, 2, 2, 2, 2, 3
};
@@ -1332,7 +1343,15 @@ yyreduce:
case 4:
{
- (yyval) = (yyvsp[-2]) || (yyvsp[0]);
+ if (!context->isIgnoringErrors())
+ {
+ // This rule should be applied right after the token is lexed, so we can
+ // refer to context->token in the error message.
+ context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
+ context->token->location, context->token->text);
+ *(context->valid) = false;
+ }
+ (yyval) = (yyvsp[0]);
}
break;
@@ -1340,7 +1359,15 @@ yyreduce:
case 5:
{
- (yyval) = (yyvsp[-2]) && (yyvsp[0]);
+ if ((yyvsp[-1]) != 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
}
break;
@@ -1348,7 +1375,15 @@ yyreduce:
case 6:
{
- (yyval) = (yyvsp[-2]) | (yyvsp[0]);
+ if ((yyvsp[-3]) != 0)
+ {
+ context->endIgnoreErrors();
+ (yyval) = static_cast<YYSTYPE>(1);
+ }
+ else
+ {
+ (yyval) = (yyvsp[-3]) || (yyvsp[0]);
+ }
}
break;
@@ -1356,7 +1391,15 @@ yyreduce:
case 7:
{
- (yyval) = (yyvsp[-2]) ^ (yyvsp[0]);
+ if ((yyvsp[-1]) == 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
}
break;
@@ -1364,7 +1407,15 @@ yyreduce:
case 8:
{
- (yyval) = (yyvsp[-2]) & (yyvsp[0]);
+ if ((yyvsp[-3]) == 0)
+ {
+ context->endIgnoreErrors();
+ (yyval) = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
+ (yyval) = (yyvsp[-3]) && (yyvsp[0]);
+ }
}
break;
@@ -1372,7 +1423,7 @@ yyreduce:
case 9:
{
- (yyval) = (yyvsp[-2]) != (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) | (yyvsp[0]);
}
break;
@@ -1380,7 +1431,7 @@ yyreduce:
case 10:
{
- (yyval) = (yyvsp[-2]) == (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) ^ (yyvsp[0]);
}
break;
@@ -1388,7 +1439,7 @@ yyreduce:
case 11:
{
- (yyval) = (yyvsp[-2]) >= (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) & (yyvsp[0]);
}
break;
@@ -1396,7 +1447,7 @@ yyreduce:
case 12:
{
- (yyval) = (yyvsp[-2]) <= (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) != (yyvsp[0]);
}
break;
@@ -1404,7 +1455,7 @@ yyreduce:
case 13:
{
- (yyval) = (yyvsp[-2]) > (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) == (yyvsp[0]);
}
break;
@@ -1412,7 +1463,7 @@ yyreduce:
case 14:
{
- (yyval) = (yyvsp[-2]) < (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) >= (yyvsp[0]);
}
break;
@@ -1420,7 +1471,7 @@ yyreduce:
case 15:
{
- (yyval) = (yyvsp[-2]) >> (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) <= (yyvsp[0]);
}
break;
@@ -1428,7 +1479,7 @@ yyreduce:
case 16:
{
- (yyval) = (yyvsp[-2]) << (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) > (yyvsp[0]);
}
break;
@@ -1436,7 +1487,7 @@ yyreduce:
case 17:
{
- (yyval) = (yyvsp[-2]) - (yyvsp[0]);
+ (yyval) = (yyvsp[-2]) < (yyvsp[0]);
}
break;
@@ -1444,7 +1495,29 @@ yyreduce:
case 18:
{
- (yyval) = (yyvsp[-2]) + (yyvsp[0]);
+ if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << (yyvsp[-2]) << " >> " << (yyvsp[0]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ (yyval) = static_cast<YYSTYPE>(0);
+ }
+ else if ((yyvsp[-2]) < 0)
+ {
+ // Logical shift right.
+ (yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) >> (yyvsp[0]));
+ }
+ else
+ {
+ (yyval) = (yyvsp[-2]) >> (yyvsp[0]);
+ }
}
break;
@@ -1452,16 +1525,28 @@ yyreduce:
case 19:
{
- if ((yyvsp[0]) == 0) {
- std::ostringstream stream;
- stream << (yyvsp[-2]) << " % " << (yyvsp[0]);
- std::string text = stream.str();
- context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
- context->token->location,
- text.c_str());
- YYABORT;
- } else {
- (yyval) = (yyvsp[-2]) % (yyvsp[0]);
+ if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << (yyvsp[-2]) << " << " << (yyvsp[0]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ (yyval) = static_cast<YYSTYPE>(0);
+ }
+ else if ((yyvsp[-2]) < 0)
+ {
+ // Logical shift left.
+ (yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) << (yyvsp[0]));
+ }
+ else
+ {
+ (yyval) = (yyvsp[-2]) << (yyvsp[0]);
}
}
@@ -1470,17 +1555,7 @@ yyreduce:
case 20:
{
- if ((yyvsp[0]) == 0) {
- std::ostringstream stream;
- stream << (yyvsp[-2]) << " / " << (yyvsp[0]);
- std::string text = stream.str();
- context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
- context->token->location,
- text.c_str());
- YYABORT;
- } else {
- (yyval) = (yyvsp[-2]) / (yyvsp[0]);
- }
+ (yyval) = gl::WrappingDiff<YYSTYPE>((yyvsp[-2]), (yyvsp[0]));
}
break;
@@ -1488,7 +1563,7 @@ yyreduce:
case 21:
{
- (yyval) = (yyvsp[-2]) * (yyvsp[0]);
+ (yyval) = gl::WrappingSum<YYSTYPE>((yyvsp[-2]), (yyvsp[0]));
}
break;
@@ -1496,7 +1571,24 @@ yyreduce:
case 22:
{
- (yyval) = ! (yyvsp[0]);
+ if ((yyvsp[0]) == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << (yyvsp[-2]) << " % " << (yyvsp[0]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ (yyval) = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
+ (yyval) = (yyvsp[-2]) % (yyvsp[0]);
+ }
}
break;
@@ -1504,7 +1596,31 @@ yyreduce:
case 23:
{
- (yyval) = ~ (yyvsp[0]);
+ if ((yyvsp[0]) == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << (yyvsp[-2]) << " / " << (yyvsp[0]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ (yyval) = static_cast<YYSTYPE>(0);
+ }
+ else if ((yyvsp[-2]) == std::numeric_limits<YYSTYPE>::min() && (yyvsp[0]) == -1)
+ {
+ // Check for the special case where the minimum representable number is
+ // divided by -1. If left alone this leads to integer overflow in C++, which
+ // has undefined results.
+ (yyval) = std::numeric_limits<YYSTYPE>::max();
+ }
+ else
+ {
+ (yyval) = (yyvsp[-2]) / (yyvsp[0]);
+ }
}
break;
@@ -1512,7 +1628,7 @@ yyreduce:
case 24:
{
- (yyval) = - (yyvsp[0]);
+ (yyval) = gl::WrappingMul((yyvsp[-2]), (yyvsp[0]));
}
break;
@@ -1520,7 +1636,7 @@ yyreduce:
case 25:
{
- (yyval) = + (yyvsp[0]);
+ (yyval) = ! (yyvsp[0]);
}
break;
@@ -1528,6 +1644,39 @@ yyreduce:
case 26:
{
+ (yyval) = ~ (yyvsp[0]);
+ }
+
+ break;
+
+ case 27:
+
+ {
+ // Check for negation of minimum representable integer to prevent undefined signed int
+ // overflow.
+ if ((yyvsp[0]) == std::numeric_limits<YYSTYPE>::min())
+ {
+ (yyval) = std::numeric_limits<YYSTYPE>::min();
+ }
+ else
+ {
+ (yyval) = -(yyvsp[0]);
+ }
+ }
+
+ break;
+
+ case 28:
+
+ {
+ (yyval) = + (yyvsp[0]);
+ }
+
+ break;
+
+ case 29:
+
+ {
(yyval) = (yyvsp[-1]);
}
@@ -1765,79 +1914,115 @@ yyreturn:
-int yylex(YYSTYPE* lvalp, Context* context)
+int yylex(YYSTYPE *lvalp, Context *context)
{
+ pp::Token *token = context->token;
+ if (!context->parsePresetToken)
+ {
+ context->lexer->lex(token);
+ }
+ context->parsePresetToken = false;
+
int type = 0;
- pp::Token* token = context->token;
switch (token->type)
{
- case pp::Token::CONST_INT:
- {
+ case pp::Token::CONST_INT: {
unsigned int val = 0;
- if (!token->uValue(&val))
+ int testVal = 0;
+ if (!token->uValue(&val) || (!token->iValue(&testVal) &&
+ context->errorSettings.integerLiteralsMustFit32BitSignedRange))
{
- context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+ context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
token->location, token->text);
+ *(context->valid) = false;
}
*lvalp = static_cast<YYSTYPE>(val);
type = TOK_CONST_INT;
break;
}
- case pp::Token::OP_OR: type = TOK_OP_OR; break;
- case pp::Token::OP_AND: type = TOK_OP_AND; break;
- case pp::Token::OP_NE: type = TOK_OP_NE; break;
- case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
- case pp::Token::OP_GE: type = TOK_OP_GE; break;
- case pp::Token::OP_LE: type = TOK_OP_LE; break;
- case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
- case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
- case '|': type = '|'; break;
- case '^': type = '^'; break;
- case '&': type = '&'; break;
- case '>': type = '>'; break;
- case '<': type = '<'; break;
- case '-': type = '-'; break;
- case '+': type = '+'; break;
- case '%': type = '%'; break;
- case '/': type = '/'; break;
- case '*': type = '*'; break;
- case '!': type = '!'; break;
- case '~': type = '~'; break;
- case '(': type = '('; break;
- case ')': type = ')'; break;
+ case pp::Token::IDENTIFIER:
+ *lvalp = static_cast<YYSTYPE>(-1);
+ type = TOK_IDENTIFIER;
+ break;
+ case pp::Token::OP_OR:
+ type = TOK_OP_OR;
+ break;
+ case pp::Token::OP_AND:
+ type = TOK_OP_AND;
+ break;
+ case pp::Token::OP_NE:
+ type = TOK_OP_NE;
+ break;
+ case pp::Token::OP_EQ:
+ type = TOK_OP_EQ;
+ break;
+ case pp::Token::OP_GE:
+ type = TOK_OP_GE;
+ break;
+ case pp::Token::OP_LE:
+ type = TOK_OP_LE;
+ break;
+ case pp::Token::OP_RIGHT:
+ type = TOK_OP_RIGHT;
+ break;
+ case pp::Token::OP_LEFT:
+ type = TOK_OP_LEFT;
+ break;
+ case '|':
+ case '^':
+ case '&':
+ case '>':
+ case '<':
+ case '-':
+ case '+':
+ case '%':
+ case '/':
+ case '*':
+ case '!':
+ case '~':
+ case '(':
+ case ')':
+ type = token->type;
+ break;
- default: break;
+ default:
+ break;
}
- // Advance to the next token if the current one is valid.
- if (type != 0) context->lexer->lex(token);
-
return type;
}
-void yyerror(Context* context, const char* reason)
+void yyerror(Context *context, const char *reason)
{
- context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+ context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
context->token->location,
reason);
}
namespace pp {
-ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
- mLexer(lexer),
- mDiagnostics(diagnostics)
+ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
+ : mLexer(lexer),
+ mDiagnostics(diagnostics)
{
}
-bool ExpressionParser::parse(Token* token, int* result)
+bool ExpressionParser::parse(Token *token,
+ int *result,
+ bool parsePresetToken,
+ const ErrorSettings &errorSettings,
+ bool *valid)
{
Context context;
context.diagnostics = mDiagnostics;
context.lexer = mLexer;
context.token = token;
context.result = result;
+ context.ignoreErrors = 0;
+ context.parsePresetToken = parsePresetToken;
+ context.errorSettings = errorSettings;
+ context.valid = valid;
int ret = yyparse(&context);
switch (ret)
{
@@ -1846,12 +2031,12 @@ bool ExpressionParser::parse(Token* token, int* result)
break;
case 2:
- mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+ mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
break;
default:
assert(false);
- mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+ mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
break;
}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.h
index 092d05941..0f2901b87 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.h
@@ -4,31 +4,40 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
-#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+#ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
+#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
-#include "pp_utils.h"
+#include "common/angleutils.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
namespace pp
{
-class Diagnostics;
class Lexer;
struct Token;
-class ExpressionParser
+class ExpressionParser : angle::NonCopyable
{
public:
- ExpressionParser(Lexer* lexer, Diagnostics* diagnostics);
+ struct ErrorSettings
+ {
+ Diagnostics::ID unexpectedIdentifier;
+ bool integerLiteralsMustFit32BitSignedRange;
+ };
- bool parse(Token* token, int* result);
+ ExpressionParser(Lexer *lexer, Diagnostics *diagnostics);
- private:
- PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
+ bool parse(Token *token,
+ int *result,
+ bool parsePresetToken,
+ const ErrorSettings &errorSettings,
+ bool *valid);
- Lexer* mLexer;
- Diagnostics* mDiagnostics;
+ private:
+ Lexer *mLexer;
+ Diagnostics *mDiagnostics;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+
+#endif // COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.y b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.y
new file mode 100644
index 000000000..a98638a8d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/ExpressionParser.y
@@ -0,0 +1,459 @@
+/*
+//
+// 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.
+//
+
+This file contains the Yacc grammar for GLSL ES preprocessor expression.
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES preprocessor expression parser.
+*/
+
+%{
+//
+// 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.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated pplval variable.
+#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#else
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065 4244 4701 4702)
+#endif
+
+#include "ExpressionParser.h"
+
+#if defined(_MSC_VER)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include <cassert>
+#include <sstream>
+#include <stdint.h>
+
+#include "DiagnosticsBase.h"
+#include "Lexer.h"
+#include "Token.h"
+#include "common/mathutil.h"
+
+typedef int32_t YYSTYPE;
+typedef uint32_t UNSIGNED_TYPE;
+
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_DECLARED 1
+
+namespace {
+struct Context
+{
+ pp::Diagnostics* diagnostics;
+ pp::Lexer* lexer;
+ pp::Token* token;
+ int* result;
+ bool parsePresetToken;
+
+ pp::ExpressionParser::ErrorSettings errorSettings;
+ bool *valid;
+
+ void startIgnoreErrors() { ++ignoreErrors; }
+ void endIgnoreErrors() { --ignoreErrors; }
+
+ bool isIgnoringErrors() { return ignoreErrors > 0; }
+
+ int ignoreErrors;
+};
+} // namespace
+%}
+
+%pure-parser
+%name-prefix "pp"
+%parse-param {Context *context}
+%lex-param {Context *context}
+
+%{
+static int yylex(YYSTYPE* lvalp, Context* context);
+static void yyerror(Context* context, const char* reason);
+%}
+
+%token TOK_CONST_INT
+%token TOK_IDENTIFIER
+%left TOK_OP_OR
+%left TOK_OP_AND
+%left '|'
+%left '^'
+%left '&'
+%left TOK_OP_EQ TOK_OP_NE
+%left '<' '>' TOK_OP_LE TOK_OP_GE
+%left TOK_OP_LEFT TOK_OP_RIGHT
+%left '+' '-'
+%left '*' '/' '%'
+%right TOK_UNARY
+
+%%
+
+input
+ : expression {
+ *(context->result) = static_cast<int>($1);
+ YYACCEPT;
+ }
+;
+
+expression
+ : TOK_CONST_INT
+ | TOK_IDENTIFIER {
+ if (!context->isIgnoringErrors())
+ {
+ // This rule should be applied right after the token is lexed, so we can
+ // refer to context->token in the error message.
+ context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
+ context->token->location, context->token->text);
+ *(context->valid) = false;
+ }
+ $$ = $1;
+ }
+ | expression TOK_OP_OR {
+ if ($1 != 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
+ } expression {
+ if ($1 != 0)
+ {
+ context->endIgnoreErrors();
+ $$ = static_cast<YYSTYPE>(1);
+ }
+ else
+ {
+ $$ = $1 || $4;
+ }
+ }
+ | expression TOK_OP_AND {
+ if ($1 == 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
+ } expression {
+ if ($1 == 0)
+ {
+ context->endIgnoreErrors();
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
+ $$ = $1 && $4;
+ }
+ }
+ | expression '|' expression {
+ $$ = $1 | $3;
+ }
+ | expression '^' expression {
+ $$ = $1 ^ $3;
+ }
+ | expression '&' expression {
+ $$ = $1 & $3;
+ }
+ | expression TOK_OP_NE expression {
+ $$ = $1 != $3;
+ }
+ | expression TOK_OP_EQ expression {
+ $$ = $1 == $3;
+ }
+ | expression TOK_OP_GE expression {
+ $$ = $1 >= $3;
+ }
+ | expression TOK_OP_LE expression {
+ $$ = $1 <= $3;
+ }
+ | expression '>' expression {
+ $$ = $1 > $3;
+ }
+ | expression '<' expression {
+ $$ = $1 < $3;
+ }
+ | expression TOK_OP_RIGHT expression {
+ if ($3 < 0 || $3 > 31)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " >> " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else if ($1 < 0)
+ {
+ // Logical shift right.
+ $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
+ }
+ else
+ {
+ $$ = $1 >> $3;
+ }
+ }
+ | expression TOK_OP_LEFT expression {
+ if ($3 < 0 || $3 > 31)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " << " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else if ($1 < 0)
+ {
+ // Logical shift left.
+ $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
+ }
+ else
+ {
+ $$ = $1 << $3;
+ }
+ }
+ | expression '-' expression {
+ $$ = gl::WrappingDiff<YYSTYPE>($1, $3);
+ }
+ | expression '+' expression {
+ $$ = gl::WrappingSum<YYSTYPE>($1, $3);
+ }
+ | expression '%' expression {
+ if ($3 == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " % " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
+ $$ = $1 % $3;
+ }
+ }
+ | expression '/' expression {
+ if ($3 == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " / " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else if ($1 == std::numeric_limits<YYSTYPE>::min() && $3 == -1)
+ {
+ // Check for the special case where the minimum representable number is
+ // divided by -1. If left alone this leads to integer overflow in C++, which
+ // has undefined results.
+ $$ = std::numeric_limits<YYSTYPE>::max();
+ }
+ else
+ {
+ $$ = $1 / $3;
+ }
+ }
+ | expression '*' expression {
+ $$ = gl::WrappingMul($1, $3);
+ }
+ | '!' expression %prec TOK_UNARY {
+ $$ = ! $2;
+ }
+ | '~' expression %prec TOK_UNARY {
+ $$ = ~ $2;
+ }
+ | '-' expression %prec TOK_UNARY {
+ // Check for negation of minimum representable integer to prevent undefined signed int
+ // overflow.
+ if ($2 == std::numeric_limits<YYSTYPE>::min())
+ {
+ $$ = std::numeric_limits<YYSTYPE>::min();
+ }
+ else
+ {
+ $$ = -$2;
+ }
+ }
+ | '+' expression %prec TOK_UNARY {
+ $$ = + $2;
+ }
+ | '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+%%
+
+int yylex(YYSTYPE *lvalp, Context *context)
+{
+ pp::Token *token = context->token;
+ if (!context->parsePresetToken)
+ {
+ context->lexer->lex(token);
+ }
+ context->parsePresetToken = false;
+
+ int type = 0;
+
+ switch (token->type)
+ {
+ case pp::Token::CONST_INT: {
+ unsigned int val = 0;
+ int testVal = 0;
+ if (!token->uValue(&val) || (!token->iValue(&testVal) &&
+ context->errorSettings.integerLiteralsMustFit32BitSignedRange))
+ {
+ context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
+ token->location, token->text);
+ *(context->valid) = false;
+ }
+ *lvalp = static_cast<YYSTYPE>(val);
+ type = TOK_CONST_INT;
+ break;
+ }
+ case pp::Token::IDENTIFIER:
+ *lvalp = static_cast<YYSTYPE>(-1);
+ type = TOK_IDENTIFIER;
+ break;
+ case pp::Token::OP_OR:
+ type = TOK_OP_OR;
+ break;
+ case pp::Token::OP_AND:
+ type = TOK_OP_AND;
+ break;
+ case pp::Token::OP_NE:
+ type = TOK_OP_NE;
+ break;
+ case pp::Token::OP_EQ:
+ type = TOK_OP_EQ;
+ break;
+ case pp::Token::OP_GE:
+ type = TOK_OP_GE;
+ break;
+ case pp::Token::OP_LE:
+ type = TOK_OP_LE;
+ break;
+ case pp::Token::OP_RIGHT:
+ type = TOK_OP_RIGHT;
+ break;
+ case pp::Token::OP_LEFT:
+ type = TOK_OP_LEFT;
+ break;
+ case '|':
+ case '^':
+ case '&':
+ case '>':
+ case '<':
+ case '-':
+ case '+':
+ case '%':
+ case '/':
+ case '*':
+ case '!':
+ case '~':
+ case '(':
+ case ')':
+ type = token->type;
+ break;
+
+ default:
+ break;
+ }
+
+ return type;
+}
+
+void yyerror(Context *context, const char *reason)
+{
+ context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
+ context->token->location,
+ reason);
+}
+
+namespace pp {
+
+ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
+ : mLexer(lexer),
+ mDiagnostics(diagnostics)
+{
+}
+
+bool ExpressionParser::parse(Token *token,
+ int *result,
+ bool parsePresetToken,
+ const ErrorSettings &errorSettings,
+ bool *valid)
+{
+ Context context;
+ context.diagnostics = mDiagnostics;
+ context.lexer = mLexer;
+ context.token = token;
+ context.result = result;
+ context.ignoreErrors = 0;
+ context.parsePresetToken = parsePresetToken;
+ context.errorSettings = errorSettings;
+ context.valid = valid;
+ int ret = yyparse(&context);
+ switch (ret)
+ {
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
+ break;
+
+ default:
+ assert(false);
+ mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
+ break;
+ }
+
+ return ret == 0;
+}
+
+} // namespace pp
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.cpp
index b4d970a97..8bce56ff2 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.cpp
@@ -4,12 +4,13 @@
// found in the LICENSE file.
//
-#include "Input.h"
+#include "compiler/preprocessor/Input.h"
#include <algorithm>
-#include <cassert>
#include <cstring>
+#include "common/debug.h"
+
namespace pp
{
@@ -17,7 +18,7 @@ Input::Input() : mCount(0), mString(0)
{
}
-Input::Input(size_t count, const char* const string[], const int length[]) :
+Input::Input(size_t count, const char *const string[], const int length[]) :
mCount(count),
mString(string)
{
@@ -29,13 +30,75 @@ Input::Input(size_t count, const char* const string[], const int length[]) :
}
}
-size_t Input::read(char* buf, size_t maxSize)
+const char *Input::skipChar()
+{
+ // This function should only be called when there is a character to skip.
+ ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
+ ++mReadLoc.cIndex;
+ if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
+ {
+ ++mReadLoc.sIndex;
+ mReadLoc.cIndex = 0;
+ }
+ if (mReadLoc.sIndex >= mCount)
+ {
+ return nullptr;
+ }
+ return mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+}
+
+size_t Input::read(char *buf, size_t maxSize, int *lineNo)
{
size_t nRead = 0;
- while ((nRead < maxSize) && (mReadLoc.sIndex < mCount))
+ // The previous call to read might have stopped copying the string when encountering a line
+ // continuation. Check for this possibility first.
+ if (mReadLoc.sIndex < mCount && maxSize > 0)
+ {
+ const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+ if ((*c) == '\\')
+ {
+ c = skipChar();
+ if (c != nullptr && (*c) == '\n')
+ {
+ // Line continuation of backslash + newline.
+ skipChar();
+ ++(*lineNo);
+ }
+ else if (c != nullptr && (*c) == '\r')
+ {
+ // Line continuation. Could be backslash + '\r\n' or just backslash + '\r'.
+ c = skipChar();
+ if (c != nullptr && (*c) == '\n')
+ {
+ skipChar();
+ }
+ ++(*lineNo);
+ }
+ else
+ {
+ // Not line continuation, so write the skipped backslash to buf.
+ *buf = '\\';
+ ++nRead;
+ }
+ }
+ }
+
+ size_t maxRead = maxSize;
+ while ((nRead < maxRead) && (mReadLoc.sIndex < mCount))
{
size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
size = std::min(size, maxSize);
+ for (size_t i = 0; i < size; ++i)
+ {
+ // Stop if a possible line continuation is encountered.
+ // It will be processed on the next call on input, which skips it
+ // and increments line number if necessary.
+ if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\')
+ {
+ size = i;
+ maxRead = nRead + size; // Stop reading right before the backslash.
+ }
+ }
std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
nRead += size;
mReadLoc.cIndex += size;
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.h
index 14b7597cb..ecbb04962 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Input.h
@@ -7,7 +7,7 @@
#ifndef COMPILER_PREPROCESSOR_INPUT_H_
#define COMPILER_PREPROCESSOR_INPUT_H_
-#include <stddef.h>
+#include <cstddef>
#include <vector>
namespace pp
@@ -18,32 +18,49 @@ class Input
{
public:
Input();
- Input(size_t count, const char* const string[], const int length[]);
+ Input(size_t count, const char *const string[], const int length[]);
- size_t count() const { return mCount; }
- const char* string(size_t index) const { return mString[index]; }
- size_t length(size_t index) const { return mLength[index]; }
+ size_t count() const
+ {
+ return mCount;
+ }
+ const char *string(size_t index) const
+ {
+ return mString[index];
+ }
+ size_t length(size_t index) const
+ {
+ return mLength[index];
+ }
- size_t read(char* buf, size_t maxSize);
+ size_t read(char *buf, size_t maxSize, int *lineNo);
struct Location
{
size_t sIndex; // String index;
size_t cIndex; // Char index.
- Location() : sIndex(0), cIndex(0) { }
+ Location()
+ : sIndex(0),
+ cIndex(0)
+ {
+ }
};
- const Location& readLoc() const { return mReadLoc; }
+ const Location &readLoc() const { return mReadLoc; }
private:
+ // Skip a character and return the next character after the one that was skipped.
+ // Return nullptr if data runs out.
+ const char *skipChar();
+
// Input.
size_t mCount;
- const char* const* mString;
+ const char * const *mString;
std::vector<size_t> mLength;
Location mReadLoc;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_INPUT_H_
+#endif // COMPILER_PREPROCESSOR_INPUT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.cpp
index 7c663ee76..89cb3cf44 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.cpp
@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
-#include "Lexer.h"
+#include "compiler/preprocessor/Lexer.h"
namespace pp
{
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.h
index eb85cea87..775bc0a20 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Lexer.h
@@ -7,19 +7,21 @@
#ifndef COMPILER_PREPROCESSOR_LEXER_H_
#define COMPILER_PREPROCESSOR_LEXER_H_
+#include "common/angleutils.h"
+
namespace pp
{
struct Token;
-class Lexer
+class Lexer : angle::NonCopyable
{
public:
virtual ~Lexer();
- virtual void lex(Token* token) = 0;
+ virtual void lex(Token *token) = 0;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_LEXER_H_
+#endif // COMPILER_PREPROCESSOR_LEXER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.cpp
index b2e3088e3..f5c94399d 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.cpp
@@ -4,14 +4,15 @@
// found in the LICENSE file.
//
-#include "Macro.h"
+#include "compiler/preprocessor/Macro.h"
-#include "Token.h"
+#include "common/angleutils.h"
+#include "compiler/preprocessor/Token.h"
namespace pp
{
-bool Macro::equals(const Macro& other) const
+bool Macro::equals(const Macro &other) const
{
return (type == other.type) &&
(name == other.name) &&
@@ -19,5 +20,20 @@ bool Macro::equals(const Macro& other) const
(replacements == other.replacements);
}
+void PredefineMacro(MacroSet *macroSet, const char *name, int value)
+{
+ Token token;
+ token.type = Token::CONST_INT;
+ token.text = ToString(value);
+
+ Macro macro;
+ macro.predefined = true;
+ macro.type = Macro::kTypeObj;
+ macro.name = name;
+ macro.replacements.push_back(token);
+
+ (*macroSet)[name] = macro;
+}
+
} // namespace pp
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.h
index 7ec014911..557df163c 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Macro.h
@@ -26,11 +26,12 @@ struct Macro
typedef std::vector<std::string> Parameters;
typedef std::vector<Token> Replacements;
- Macro() : predefined(false), disabled(false), type(kTypeObj) { }
- bool equals(const Macro& other) const;
+ Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj) {}
+ bool equals(const Macro &other) const;
bool predefined;
mutable bool disabled;
+ mutable int expansionCount;
Type type;
std::string name;
@@ -40,5 +41,8 @@ struct Macro
typedef std::map<std::string, Macro> MacroSet;
+void PredefineMacro(MacroSet *macroSet, const char *name, int value);
+
} // namespace pp
+
#endif // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp
index 1116c516f..f38b39635 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp
@@ -4,29 +4,34 @@
// found in the LICENSE file.
//
-#include "MacroExpander.h"
+#include "compiler/preprocessor/MacroExpander.h"
#include <algorithm>
-#include <sstream>
-#include "DiagnosticsBase.h"
-#include "Token.h"
+#include "common/debug.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/preprocessor/Token.h"
namespace pp
{
+namespace
+{
+
+const size_t kMaxContextTokens = 10000;
+
class TokenLexer : public Lexer
{
public:
typedef std::vector<Token> TokenVector;
- TokenLexer(TokenVector* tokens)
+ TokenLexer(TokenVector *tokens)
{
tokens->swap(mTokens);
mIter = mTokens.begin();
}
- virtual void lex(Token* token)
+ void lex(Token *token) override
{
if (mIter == mTokens.end())
{
@@ -40,30 +45,26 @@ class TokenLexer : public Lexer
}
private:
- PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
-
TokenVector mTokens;
TokenVector::const_iterator mIter;
};
-MacroExpander::MacroExpander(Lexer* lexer,
- MacroSet* macroSet,
- Diagnostics* diagnostics) :
- mLexer(lexer),
- mMacroSet(macroSet),
- mDiagnostics(diagnostics)
+} // anonymous namespace
+
+MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics)
+ : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mTotalTokensInContexts(0)
{
}
MacroExpander::~MacroExpander()
{
- for (std::size_t i = 0; i < mContextStack.size(); ++i)
+ for (MacroContext *context : mContextStack)
{
- delete mContextStack[i];
+ delete context;
}
}
-void MacroExpander::lex(Token* token)
+void MacroExpander::lex(Token *token)
{
while (true)
{
@@ -97,7 +98,7 @@ void MacroExpander::lex(Token* token)
}
}
-void MacroExpander::getToken(Token* token)
+void MacroExpander::getToken(Token *token)
{
if (mReserveToken.get())
{
@@ -118,21 +119,22 @@ void MacroExpander::getToken(Token* token)
}
else
{
+ ASSERT(mTotalTokensInContexts == 0);
mLexer->lex(token);
}
}
-void MacroExpander::ungetToken(const Token& token)
+void MacroExpander::ungetToken(const Token &token)
{
if (!mContextStack.empty())
{
- MacroContext* context = mContextStack.back();
+ MacroContext *context = mContextStack.back();
context->unget();
- assert(context->replacements[context->index] == token);
+ ASSERT(context->replacements[context->index] == token);
}
else
{
- assert(!mReserveToken.get());
+ ASSERT(!mReserveToken.get());
mReserveToken.reset(new Token(token));
}
}
@@ -148,12 +150,14 @@ bool MacroExpander::isNextTokenLeftParen()
return lparen;
}
-bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
+bool MacroExpander::pushMacro(const Macro &macro, const Token &identifier)
{
- assert(!macro.disabled);
- assert(!identifier.expansionDisabled());
- assert(identifier.type == Token::IDENTIFIER);
- assert(identifier.text == macro.name);
+ ASSERT(!macro.disabled);
+ ASSERT(!identifier.expansionDisabled());
+ ASSERT(identifier.type == Token::IDENTIFIER);
+ ASSERT(identifier.text == macro.name);
+
+ macro.expansionCount++;
std::vector<Token> replacements;
if (!expandMacro(macro, identifier, &replacements))
@@ -162,31 +166,41 @@ bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
// Macro is disabled for expansion until it is popped off the stack.
macro.disabled = true;
- MacroContext* context = new MacroContext;
+ MacroContext *context = new MacroContext;
context->macro = &macro;
context->replacements.swap(replacements);
mContextStack.push_back(context);
+ mTotalTokensInContexts += context->replacements.size();
return true;
}
void MacroExpander::popMacro()
{
- assert(!mContextStack.empty());
+ ASSERT(!mContextStack.empty());
- MacroContext* context = mContextStack.back();
+ MacroContext *context = mContextStack.back();
mContextStack.pop_back();
- assert(context->empty());
- assert(context->macro->disabled);
+ ASSERT(context->empty());
+ ASSERT(context->macro->disabled);
+ ASSERT(context->macro->expansionCount > 0);
context->macro->disabled = false;
+ context->macro->expansionCount--;
+ mTotalTokensInContexts -= context->replacements.size();
delete context;
}
-bool MacroExpander::expandMacro(const Macro& macro,
- const Token& identifier,
- std::vector<Token>* replacements)
+bool MacroExpander::expandMacro(const Macro &macro,
+ const Token &identifier,
+ std::vector<Token> *replacements)
{
replacements->clear();
+
+ // In the case of an object-like macro, the replacement list gets its location
+ // from the identifier, but in the case of a function-like macro, the replacement
+ // list gets its location from the closing parenthesis of the macro invocation.
+ // This is tested by dEQP-GLES3.functional.shaders.preprocessor.predefined_macros.*
+ SourceLocation replacementLocation = identifier.location;
if (macro.type == Macro::kTypeObj)
{
replacements->assign(macro.replacements.begin(),
@@ -194,31 +208,27 @@ bool MacroExpander::expandMacro(const Macro& macro,
if (macro.predefined)
{
- static const std::string kLine = "__LINE__";
- static const std::string kFile = "__FILE__";
+ const char kLine[] = "__LINE__";
+ const char kFile[] = "__FILE__";
- assert(replacements->size() == 1);
+ ASSERT(replacements->size() == 1);
Token& repl = replacements->front();
if (macro.name == kLine)
{
- std::ostringstream stream;
- stream << identifier.location.line;
- repl.text = stream.str();
+ repl.text = ToString(identifier.location.line);
}
else if (macro.name == kFile)
{
- std::ostringstream stream;
- stream << identifier.location.file;
- repl.text = stream.str();
+ repl.text = ToString(identifier.location.file);
}
}
}
else
{
- assert(macro.type == Macro::kTypeFunc);
+ ASSERT(macro.type == Macro::kTypeFunc);
std::vector<MacroArg> args;
args.reserve(macro.parameters.size());
- if (!collectMacroArgs(macro, identifier, &args))
+ if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
return false;
replaceMacroParams(macro, args, replacements);
@@ -234,27 +244,30 @@ bool MacroExpander::expandMacro(const Macro& macro,
repl.setAtStartOfLine(identifier.atStartOfLine());
repl.setHasLeadingSpace(identifier.hasLeadingSpace());
}
- repl.location = identifier.location;
+ repl.location = replacementLocation;
}
return true;
}
-bool MacroExpander::collectMacroArgs(const Macro& macro,
- const Token& identifier,
- std::vector<MacroArg>* args)
+bool MacroExpander::collectMacroArgs(const Macro &macro,
+ const Token &identifier,
+ std::vector<MacroArg> *args,
+ SourceLocation *closingParenthesisLocation)
{
Token token;
getToken(&token);
- assert(token.type == '(');
+ ASSERT(token.type == '(');
args->push_back(MacroArg());
- for (int openParens = 1; openParens != 0; )
+
+ int openParens = 1;
+ while (openParens != 0)
{
getToken(&token);
if (token.type == Token::LAST)
{
- mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
+ mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION,
identifier.location, identifier.text);
// Do not lose EOF token.
ungetToken(token);
@@ -271,12 +284,14 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
case ')':
--openParens;
isArg = openParens != 0;
+ *closingParenthesisLocation = token.location;
break;
case ',':
// The individual arguments are separated by comma tokens, but
// the comma tokens between matching inner parentheses do not
// seperate arguments.
- if (openParens == 1) args->push_back(MacroArg());
+ if (openParens == 1)
+ args->push_back(MacroArg());
isArg = openParens != 1;
break;
default:
@@ -285,14 +300,15 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
}
if (isArg)
{
- MacroArg& arg = args->back();
+ MacroArg &arg = args->back();
// Initial whitespace is not part of the argument.
- if (arg.empty()) token.setHasLeadingSpace(false);
+ if (arg.empty())
+ token.setHasLeadingSpace(false);
arg.push_back(token);
}
}
- const Macro::Parameters& params = macro.parameters;
+ const Macro::Parameters &params = macro.parameters;
// If there is only one empty argument, it is equivalent to no argument.
if (params.empty() && (args->size() == 1) && args->front().empty())
{
@@ -302,8 +318,8 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
if (args->size() != params.size())
{
Diagnostics::ID id = args->size() < macro.parameters.size() ?
- Diagnostics::MACRO_TOO_FEW_ARGS :
- Diagnostics::MACRO_TOO_MANY_ARGS;
+ Diagnostics::PP_MACRO_TOO_FEW_ARGS :
+ Diagnostics::PP_MACRO_TOO_MANY_ARGS;
mDiagnostics->report(id, identifier.location, identifier.text);
return false;
}
@@ -311,9 +327,9 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
// Pre-expand each argument before substitution.
// This step expands each argument individually before they are
// inserted into the macro body.
- for (std::size_t i = 0; i < args->size(); ++i)
+ size_t numTokens = 0;
+ for (auto &arg : *args)
{
- MacroArg& arg = args->at(i);
TokenLexer lexer(&arg);
MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
@@ -323,18 +339,32 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
{
arg.push_back(token);
expander.lex(&token);
+ numTokens++;
+ if (numTokens + mTotalTokensInContexts > kMaxContextTokens)
+ {
+ mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
+ return false;
+ }
}
}
return true;
}
-void MacroExpander::replaceMacroParams(const Macro& macro,
- const std::vector<MacroArg>& args,
- std::vector<Token>* replacements)
+void MacroExpander::replaceMacroParams(const Macro &macro,
+ const std::vector<MacroArg> &args,
+ std::vector<Token> *replacements)
{
for (std::size_t i = 0; i < macro.replacements.size(); ++i)
{
- const Token& repl = macro.replacements[i];
+ if (!replacements->empty() &&
+ replacements->size() + mTotalTokensInContexts > kMaxContextTokens)
+ {
+ const Token &token = replacements->back();
+ mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
+ return;
+ }
+
+ const Token &repl = macro.replacements[i];
if (repl.type != Token::IDENTIFIER)
{
replacements->push_back(repl);
@@ -353,7 +383,7 @@ void MacroExpander::replaceMacroParams(const Macro& macro,
}
std::size_t iArg = std::distance(macro.parameters.begin(), iter);
- const MacroArg& arg = args[iArg];
+ const MacroArg &arg = args[iArg];
if (arg.empty())
{
continue;
@@ -366,5 +396,25 @@ void MacroExpander::replaceMacroParams(const Macro& macro,
}
}
+MacroExpander::MacroContext::MacroContext() : macro(0), index(0)
+{
+}
+
+bool MacroExpander::MacroContext::empty() const
+{
+ return index == replacements.size();
+}
+
+const Token &MacroExpander::MacroContext::get()
+{
+ return replacements[index++];
+}
+
+void MacroExpander::MacroContext::unget()
+{
+ ASSERT(index > 0);
+ --index;
+}
+
} // namespace pp
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.h
index 21b67571f..77c767c34 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.h
@@ -4,72 +4,71 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
-#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+#ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_
+#define COMPILER_PREPROCESSOR_MACROEXPANDER_H_
-#include <cassert>
#include <memory>
#include <vector>
-#include "Lexer.h"
-#include "Macro.h"
-#include "pp_utils.h"
+#include "compiler/preprocessor/Lexer.h"
+#include "compiler/preprocessor/Macro.h"
namespace pp
{
class Diagnostics;
+struct SourceLocation;
class MacroExpander : public Lexer
{
public:
- MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
- virtual ~MacroExpander();
+ MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics);
+ ~MacroExpander() override;
- virtual void lex(Token* token);
+ void lex(Token *token) override;
private:
- PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
-
- void getToken(Token* token);
- void ungetToken(const Token& token);
+ void getToken(Token *token);
+ void ungetToken(const Token &token);
bool isNextTokenLeftParen();
- bool pushMacro(const Macro& macro, const Token& identifier);
+ bool pushMacro(const Macro &macro, const Token &identifier);
void popMacro();
- bool expandMacro(const Macro& macro,
- const Token& identifier,
- std::vector<Token>* replacements);
+ bool expandMacro(const Macro &macro,
+ const Token &identifier,
+ std::vector<Token> *replacements);
typedef std::vector<Token> MacroArg;
- bool collectMacroArgs(const Macro& macro,
- const Token& identifier,
- std::vector<MacroArg>* args);
- void replaceMacroParams(const Macro& macro,
- const std::vector<MacroArg>& args,
- std::vector<Token>* replacements);
+ bool collectMacroArgs(const Macro &macro,
+ const Token &identifier,
+ std::vector<MacroArg> *args,
+ SourceLocation *closingParenthesisLocation);
+ void replaceMacroParams(const Macro &macro,
+ const std::vector<MacroArg> &args,
+ std::vector<Token> *replacements);
struct MacroContext
{
- const Macro* macro;
+ MacroContext();
+ bool empty() const;
+ const Token &get();
+ void unget();
+
+ const Macro *macro;
std::size_t index;
std::vector<Token> replacements;
-
- MacroContext() : macro(0), index(0) { }
- bool empty() const { return index == replacements.size(); }
- const Token& get() { return replacements[index++]; }
- void unget() { assert(index > 0); --index; }
};
- Lexer* mLexer;
- MacroSet* mMacroSet;
- Diagnostics* mDiagnostics;
+ Lexer *mLexer;
+ MacroSet *mMacroSet;
+ Diagnostics *mDiagnostics;
- std::auto_ptr<Token> mReserveToken;
- std::vector<MacroContext*> mContextStack;
+ std::unique_ptr<Token> mReserveToken;
+ std::vector<MacroContext *> mContextStack;
+ size_t mTotalTokensInContexts;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+#endif // COMPILER_PREPROCESSOR_MACROEXPANDER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.cpp
index b615c85dc..1709d6673 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.cpp
@@ -4,41 +4,38 @@
// found in the LICENSE file.
//
-#include "Preprocessor.h"
+#include "compiler/preprocessor/Preprocessor.h"
-#include <cassert>
-#include <sstream>
-
-#include "DiagnosticsBase.h"
-#include "DirectiveParser.h"
-#include "Macro.h"
-#include "MacroExpander.h"
-#include "Token.h"
-#include "Tokenizer.h"
+#include "common/debug.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/preprocessor/DirectiveParser.h"
+#include "compiler/preprocessor/Macro.h"
+#include "compiler/preprocessor/MacroExpander.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/preprocessor/Tokenizer.h"
namespace pp
{
struct PreprocessorImpl
{
- Diagnostics* diagnostics;
+ Diagnostics *diagnostics;
MacroSet macroSet;
Tokenizer tokenizer;
DirectiveParser directiveParser;
MacroExpander macroExpander;
- PreprocessorImpl(Diagnostics* diag,
- DirectiveHandler* directiveHandler) :
- diagnostics(diag),
- tokenizer(diag),
- directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
- macroExpander(&directiveParser, &macroSet, diag)
+ PreprocessorImpl(Diagnostics *diag, DirectiveHandler *directiveHandler)
+ : diagnostics(diag),
+ tokenizer(diag),
+ directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
+ macroExpander(&directiveParser, &macroSet, diag)
{
}
};
-Preprocessor::Preprocessor(Diagnostics* diagnostics,
- DirectiveHandler* directiveHandler)
+Preprocessor::Preprocessor(Diagnostics *diagnostics,
+ DirectiveHandler *directiveHandler)
{
mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
}
@@ -49,44 +46,26 @@ Preprocessor::~Preprocessor()
}
bool Preprocessor::init(size_t count,
- const char* const string[],
+ const char * const string[],
const int length[])
{
- static const int kGLSLVersion = 100;
+ static const int kDefaultGLSLVersion = 100;
// Add standard pre-defined macros.
predefineMacro("__LINE__", 0);
predefineMacro("__FILE__", 0);
- predefineMacro("__VERSION__", kGLSLVersion);
+ predefineMacro("__VERSION__", kDefaultGLSLVersion);
predefineMacro("GL_ES", 1);
return mImpl->tokenizer.init(count, string, length);
}
-void Preprocessor::predefineMacro(const char* name, int value)
-{
- std::ostringstream stream;
- stream << value;
-
- Token token;
- token.type = Token::CONST_INT;
- token.text = stream.str();
-
- Macro macro;
- macro.predefined = true;
- macro.type = Macro::kTypeObj;
- macro.name = name;
- macro.replacements.push_back(token);
-
- mImpl->macroSet[name] = macro;
-}
-
-void Preprocessor::setMaxTokenLength(size_t maxLength)
+void Preprocessor::predefineMacro(const char *name, int value)
{
- mImpl->tokenizer.setMaxTokenLength(maxLength);
+ PredefineMacro(&mImpl->macroSet, name, value);
}
-void Preprocessor::lex(Token* token)
+void Preprocessor::lex(Token *token)
{
bool validToken = false;
while (!validToken)
@@ -98,14 +77,14 @@ void Preprocessor::lex(Token* token)
// Convert preprocessing tokens to compiler tokens or report
// diagnostics.
case Token::PP_HASH:
- assert(false);
- break;
+ UNREACHABLE();
+ break;
case Token::PP_NUMBER:
- mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
+ mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER,
token->location, token->text);
break;
case Token::PP_OTHER:
- mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
+ mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER,
token->location, token->text);
break;
default:
@@ -115,5 +94,9 @@ void Preprocessor::lex(Token* token)
}
}
-} // namespace pp
+void Preprocessor::setMaxTokenSize(size_t maxTokenSize)
+{
+ mImpl->tokenizer.setMaxTokenSize(maxTokenSize);
+}
+} // namespace pp
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.h
index 9a90d79a1..cd699786f 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Preprocessor.h
@@ -7,9 +7,9 @@
#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_
#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
-#include <stddef.h>
+#include <cstddef>
-#include "pp_utils.h"
+#include "common/angleutils.h"
namespace pp
{
@@ -19,10 +19,10 @@ class DirectiveHandler;
struct PreprocessorImpl;
struct Token;
-class Preprocessor
+class Preprocessor : angle::NonCopyable
{
public:
- Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler);
+ Preprocessor(Diagnostics *diagnostics, DirectiveHandler *directiveHandler);
~Preprocessor();
// count: specifies the number of elements in the string and length arrays.
@@ -34,24 +34,19 @@ class Preprocessor
// Each element in the length array may contain the length of the
// corresponding string or a value less than 0 to indicate that the string
// is null terminated.
- bool init(size_t count, const char* const string[], const int length[]);
+ bool init(size_t count, const char * const string[], const int length[]);
// Adds a pre-defined macro.
- void predefineMacro(const char* name, int value);
- // Sets maximum allowed token length.
- // If token length exceeds this limit,
- // the token text will be truncated to the given maximum length, and
- // TOKEN_TOO_LONG diagnostic will be generated.
- // The maximum length defaults to 256.
- void setMaxTokenLength(size_t maxLength);
+ void predefineMacro(const char *name, int value);
- void lex(Token* token);
+ void lex(Token *token);
- private:
- PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
+ // Set maximum preprocessor token size
+ void setMaxTokenSize(size_t maxTokenSize);
- PreprocessorImpl* mImpl;
+ private:
+ PreprocessorImpl *mImpl;
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/SourceLocation.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/SourceLocation.h
index 6982613ac..af8a8d5d1 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/SourceLocation.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/SourceLocation.h
@@ -4,18 +4,26 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
-#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+#ifndef COMPILER_PREPROCESSOR_SOURCELOCATION_H_
+#define COMPILER_PREPROCESSOR_SOURCELOCATION_H_
namespace pp
{
struct SourceLocation
{
- SourceLocation() : file(0), line(0) { }
- SourceLocation(int f, int l) : file(f), line(l) { }
+ SourceLocation()
+ : file(0),
+ line(0)
+ {
+ }
+ SourceLocation(int f, int l)
+ : file(f),
+ line(l)
+ {
+ }
- bool equals(const SourceLocation& other) const
+ bool equals(const SourceLocation &other) const
{
return (file == other.file) && (line == other.line);
}
@@ -24,15 +32,16 @@ struct SourceLocation
int line;
};
-inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs)
+inline bool operator==(const SourceLocation &lhs, const SourceLocation &rhs)
{
return lhs.equals(rhs);
}
-inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs)
+inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs)
{
return !lhs.equals(rhs);
}
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+
+#endif // COMPILER_PREPROCESSOR_SOURCELOCATION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.cpp
index 67f50aa32..41610a402 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.cpp
@@ -4,11 +4,10 @@
// found in the LICENSE file.
//
-#include "Token.h"
+#include "compiler/preprocessor/Token.h"
-#include <cassert>
-
-#include "numeric_lex.h"
+#include "common/debug.h"
+#include "compiler/preprocessor/numeric_lex.h"
namespace pp
{
@@ -21,7 +20,7 @@ void Token::reset()
text.clear();
}
-bool Token::equals(const Token& other) const
+bool Token::equals(const Token &other) const
{
return (type == other.type) &&
(flags == other.flags) &&
@@ -53,25 +52,25 @@ void Token::setExpansionDisabled(bool disable)
flags &= ~EXPANSION_DISABLED;
}
-bool Token::iValue(int* value) const
+bool Token::iValue(int *value) const
{
- assert(type == CONST_INT);
+ ASSERT(type == CONST_INT);
return numeric_lex_int(text, value);
}
-bool Token::uValue(unsigned int* value) const
+bool Token::uValue(unsigned int *value) const
{
- assert(type == CONST_INT);
+ ASSERT(type == CONST_INT);
return numeric_lex_int(text, value);
}
-bool Token::fValue(float* value) const
+bool Token::fValue(float *value) const
{
- assert(type == CONST_FLOAT);
+ ASSERT(type == CONST_FLOAT);
return numeric_lex_float(text, value);
}
-std::ostream& operator<<(std::ostream& out, const Token& token)
+std::ostream &operator<<(std::ostream &out, const Token &token)
{
if (token.hasLeadingSpace())
out << " ";
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.h
index 8b553aecb..716503b32 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Token.h
@@ -10,7 +10,7 @@
#include <ostream>
#include <string>
-#include "SourceLocation.h"
+#include "compiler/preprocessor/SourceLocation.h"
namespace pp
{
@@ -62,27 +62,40 @@ struct Token
EXPANSION_DISABLED = 1 << 2
};
- Token() : type(0), flags(0) { }
+ Token()
+ : type(0),
+ flags(0)
+ {
+ }
void reset();
- bool equals(const Token& other) const;
+ bool equals(const Token &other) const;
// Returns true if this is the first token on line.
// It disregards any leading whitespace.
- bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; }
+ bool atStartOfLine() const
+ {
+ return (flags & AT_START_OF_LINE) != 0;
+ }
void setAtStartOfLine(bool start);
- bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; }
+ bool hasLeadingSpace() const
+ {
+ return (flags & HAS_LEADING_SPACE) != 0;
+ }
void setHasLeadingSpace(bool space);
- bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; }
+ bool expansionDisabled() const
+ {
+ return (flags & EXPANSION_DISABLED) != 0;
+ }
void setExpansionDisabled(bool disable);
// Converts text into numeric value for CONST_INT and CONST_FLOAT token.
// Returns false if the parsed value cannot fit into an int or float.
- bool iValue(int* value) const;
- bool uValue(unsigned int* value) const;
- bool fValue(float* value) const;
+ bool iValue(int *value) const;
+ bool uValue(unsigned int *value) const;
+ bool fValue(float *value) const;
int type;
unsigned int flags;
@@ -90,17 +103,18 @@ struct Token
std::string text;
};
-inline bool operator==(const Token& lhs, const Token& rhs)
+inline bool operator==(const Token &lhs, const Token &rhs)
{
return lhs.equals(rhs);
}
-inline bool operator!=(const Token& lhs, const Token& rhs)
+inline bool operator!=(const Token &lhs, const Token &rhs)
{
return !lhs.equals(rhs);
}
-extern std::ostream& operator<<(std::ostream& out, const Token& token);
+std::ostream &operator<<(std::ostream &out, const Token &token);
} // namepsace pp
+
#endif // COMPILER_PREPROCESSOR_TOKEN_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.cpp
index 363a37b36..fee20c674 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.cpp
@@ -1,6 +1,6 @@
#line 16 "./Tokenizer.l"
//
-// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
+// 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.
//
@@ -9,20 +9,96 @@
-#line 13 "./Tokenizer.cpp"
-
#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 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 1
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
@@ -56,7 +132,6 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
-typedef uint64_t flex_uint64_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
@@ -64,7 +139,6 @@ typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
/* Limits of integral types. */
#ifndef INT8_MIN
@@ -95,32 +169,31 @@ typedef unsigned int flex_uint32_t;
#define UINT32_MAX (4294967295U)
#endif
+#endif /* ! C99 */
+
#endif /* ! FLEXINT_H */
-#ifdef __cplusplus
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-#else /* ! __cplusplus */
+/* TODO: this is always defined, so inline it */
+#define yyconst const
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
-#define YY_USE_CONST
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
+
+
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
/* Returned upon end-of-file. */
#define YY_NULL 0
+
+
/* Promotes a possibly negative, possibly signed char to an unsigned
* integer for use as an array index. If the signed char is negative,
* we want to instead treat it as an 8-bit unsigned char, hence the
@@ -128,12 +201,34 @@ typedef unsigned int flex_uint32_t;
*/
#define YY_SC_TO_UI(c) ((unsigned int) (unsigned 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
@@ -145,12 +240,29 @@ typedef void* yyscan_t;
#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.
@@ -158,23 +270,41 @@ typedef void* yyscan_t;
#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 pprestart(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;
@@ -185,12 +315,22 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
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
+
+
+
#define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+
+
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
@@ -205,26 +345,31 @@ typedef size_t yy_size_t;
} \
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.
*/
- yy_size_t yy_buf_size;
+ int yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
- yy_size_t yy_n_chars;
+ 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
@@ -248,6 +393,7 @@ struct yy_buffer_state
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.
*/
@@ -272,6 +418,10 @@ struct yy_buffer_state
};
#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".
@@ -282,11 +432,18 @@ struct yy_buffer_state
? 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 pprestart (FILE *input_file ,yyscan_t yyscanner );
void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
YY_BUFFER_STATE pp_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
@@ -295,22 +452,30 @@ void pp_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
void pppush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
void pppop_buffer_state (yyscan_t yyscanner );
+
static void ppensure_buffer_stack (yyscan_t yyscanner );
static void pp_load_buffer_state (yyscan_t yyscanner );
static void pp_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+
#define YY_FLUSH_BUFFER pp_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
YY_BUFFER_STATE pp_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
YY_BUFFER_STATE pp_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
void *ppalloc (yy_size_t ,yyscan_t yyscanner );
void *pprealloc (void *,yy_size_t ,yyscan_t yyscanner );
void ppfree (void * ,yyscan_t yyscanner );
+
#define yy_new_buffer pp_create_buffer
+
+
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
@@ -321,6 +486,8 @@ void ppfree (void * ,yyscan_t yyscanner );
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
+
+
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
@@ -331,34 +498,50 @@ void ppfree (void * ,yyscan_t 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 ppwrap(n) 1
+#define ppwrap(yyscanner) (/*CONSTCOND*/1)
#define YY_SKIP_YYWRAP
typedef unsigned char 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 yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error (yyconst 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 = (yy_size_t) (yy_cp - 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 38
#define YY_END_OF_BUFFER 39
/* This struct is not used in this scanner,
@@ -368,20 +551,22 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static yyconst flex_int16_t yy_accept[87] =
+static yyconst flex_int16_t yy_accept[98] =
{ 0,
0, 0, 0, 0, 39, 37, 34, 35, 35, 33,
7, 33, 33, 33, 33, 33, 33, 33, 33, 9,
9, 33, 33, 33, 8, 37, 33, 33, 3, 5,
5, 4, 34, 35, 19, 27, 20, 30, 25, 12,
23, 13, 24, 10, 2, 1, 26, 10, 9, 11,
- 11, 11, 11, 9, 14, 16, 18, 17, 15, 8,
- 36, 36, 31, 21, 32, 22, 3, 5, 6, 11,
- 10, 11, 1, 10, 11, 0, 10, 9, 28, 29,
- 0, 10, 10, 10, 10, 0
+ 11, 11, 9, 11, 9, 9, 14, 16, 18, 17,
+ 15, 8, 36, 36, 31, 21, 32, 22, 3, 5,
+ 6, 11, 10, 11, 10, 1, 10, 11, 10, 0,
+ 10, 9, 9, 9, 28, 29, 0, 10, 10, 10,
+ 10, 9, 10, 10, 9, 10, 0
+
} ;
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
2, 2, 4, 1, 1, 1, 1, 1, 1, 1,
@@ -389,14 +574,14 @@ static yyconst flex_int32_t yy_ec[256] =
1, 2, 5, 1, 6, 1, 7, 8, 1, 9,
9, 10, 11, 9, 12, 13, 14, 15, 16, 16,
16, 16, 16, 16, 16, 17, 17, 9, 9, 18,
- 19, 20, 9, 1, 21, 21, 21, 21, 22, 21,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 24, 23, 23,
- 9, 25, 9, 26, 23, 1, 21, 21, 21, 21,
-
- 22, 21, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 24,
- 23, 23, 9, 27, 9, 9, 1, 1, 1, 1,
+ 19, 20, 9, 1, 21, 21, 21, 21, 22, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 25, 24, 24, 26, 24, 24,
+ 9, 27, 9, 28, 24, 1, 21, 21, 21, 21,
+
+ 22, 23, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 25, 24, 24, 26,
+ 24, 24, 9, 29, 9, 9, 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,
@@ -413,89 +598,101 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;
-static yyconst flex_int32_t yy_meta[28] =
+static yyconst YY_CHAR yy_meta[30] =
{ 0,
1, 1, 2, 2, 1, 1, 1, 1, 1, 3,
1, 1, 4, 1, 5, 5, 5, 1, 1, 1,
- 5, 5, 5, 5, 1, 1, 1
+ 5, 5, 5, 5, 5, 5, 1, 1, 1
} ;
-static yyconst flex_int16_t yy_base[92] =
+static yyconst flex_uint16_t yy_base[103] =
{ 0,
- 0, 0, 25, 27, 162, 163, 159, 163, 152, 132,
- 163, 131, 24, 163, 116, 22, 26, 31, 30, 37,
- 40, 44, 115, 46, 0, 64, 50, 15, 0, 163,
- 124, 91, 88, 163, 163, 163, 163, 163, 163, 163,
- 163, 163, 163, 64, 163, 0, 163, 76, 54, 58,
- 79, 91, 91, 0, 56, 163, 163, 163, 32, 0,
- 163, 36, 163, 163, 163, 163, 0, 163, 163, 94,
- 0, 106, 0, 0, 113, 55, 72, 113, 163, 163,
- 116, 101, 108, 123, 126, 163, 143, 31, 148, 153,
- 155
-
+ 0, 0, 27, 29, 137, 194, 133, 194, 117, 100,
+ 194, 98, 26, 194, 94, 24, 28, 33, 32, 39,
+ 51, 39, 80, 50, 0, 68, 25, 54, 0, 194,
+ 88, 71, 80, 194, 194, 194, 194, 194, 194, 194,
+ 194, 194, 194, 71, 194, 0, 194, 85, 55, 64,
+ 99, 111, 53, 105, 0, 50, 55, 194, 194, 194,
+ 40, 0, 194, 38, 194, 194, 194, 194, 0, 194,
+ 194, 117, 0, 130, 0, 0, 0, 137, 0, 88,
+ 113, 0, 131, 0, 194, 194, 143, 139, 152, 150,
+ 0, 13, 153, 194, 0, 194, 194, 176, 31, 181,
+
+ 186, 188
} ;
-static yyconst flex_int16_t yy_def[92] =
+static yyconst flex_int16_t yy_def[103] =
{ 0,
- 86, 1, 87, 87, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 20, 86, 86, 86, 88, 86, 86, 86, 89, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 90, 86, 86, 20, 20,
- 48, 51, 91, 21, 86, 86, 86, 86, 86, 88,
- 86, 86, 86, 86, 86, 86, 89, 86, 86, 44,
- 44, 70, 90, 48, 51, 86, 52, 91, 86, 86,
- 86, 72, 75, 86, 86, 0, 86, 86, 86, 86,
- 86
-
+ 97, 1, 98, 98, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 20, 97, 97, 97, 99, 97, 97, 97, 100, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 101, 97, 97, 20, 20,
+ 50, 51, 51, 102, 21, 51, 97, 97, 97, 97,
+ 97, 99, 97, 97, 97, 97, 97, 97, 100, 97,
+ 97, 44, 44, 72, 72, 101, 48, 51, 51, 97,
+ 52, 51, 102, 51, 97, 97, 97, 74, 78, 97,
+ 51, 51, 97, 97, 51, 97, 0, 97, 97, 97,
+
+ 97, 97
} ;
-static yyconst flex_int16_t yy_nxt[191] =
+static yyconst flex_uint16_t yy_nxt[224] =
{ 0,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 21, 22, 23, 24,
- 25, 25, 25, 25, 26, 27, 28, 30, 31, 30,
- 31, 37, 40, 65, 32, 60, 32, 42, 61, 45,
- 41, 66, 38, 46, 43, 44, 44, 44, 47, 48,
- 80, 49, 49, 50, 54, 54, 54, 51, 52, 51,
- 53, 55, 56, 51, 58, 59, 61, 62, 63, 84,
- 84, 84, 50, 50, 79, 64, 70, 51, 71, 71,
- 71, 51, 86, 86, 70, 72, 70, 70, 51, 33,
- 74, 74, 74, 51, 51, 51, 51, 75, 51, 51,
-
- 51, 76, 76, 51, 69, 77, 77, 77, 70, 70,
- 70, 86, 86, 51, 51, 70, 81, 81, 86, 86,
- 82, 82, 82, 81, 81, 51, 68, 83, 83, 83,
- 85, 85, 85, 57, 39, 51, 51, 84, 84, 84,
- 85, 85, 85, 29, 29, 29, 29, 29, 67, 36,
- 35, 67, 67, 73, 34, 73, 73, 73, 78, 78,
- 33, 86, 5, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86
+ 25, 25, 25, 25, 25, 25, 26, 27, 28, 30,
+ 31, 30, 31, 37, 40, 62, 32, 95, 32, 42,
+ 63, 45, 41, 65, 38, 46, 43, 44, 44, 44,
+ 47, 48, 66, 49, 49, 50, 57, 58, 86, 51,
+ 52, 51, 51, 53, 54, 55, 55, 55, 60, 61,
+ 63, 64, 67, 85, 84, 56, 51, 82, 50, 50,
+ 51, 33, 68, 72, 71, 73, 73, 73, 51, 51,
+ 70, 72, 74, 75, 72, 72, 72, 51, 59, 77,
+
+ 77, 77, 90, 90, 90, 51, 78, 79, 51, 51,
+ 51, 51, 39, 51, 51, 51, 36, 51, 35, 34,
+ 51, 80, 80, 97, 97, 81, 81, 81, 51, 51,
+ 51, 72, 72, 72, 33, 91, 97, 97, 72, 72,
+ 87, 87, 97, 51, 88, 88, 88, 87, 87, 97,
+ 97, 89, 89, 89, 51, 92, 51, 93, 93, 93,
+ 97, 75, 97, 97, 90, 90, 90, 93, 93, 93,
+ 97, 97, 94, 97, 79, 96, 29, 29, 29, 29,
+ 29, 69, 97, 97, 69, 69, 76, 97, 76, 76,
+ 76, 83, 83, 5, 97, 97, 97, 97, 97, 97,
+
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97
} ;
-static yyconst flex_int16_t yy_chk[191] =
+static yyconst flex_int16_t yy_chk[224] =
{ 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, 3, 3, 4,
- 4, 13, 16, 28, 3, 88, 4, 17, 62, 19,
- 16, 28, 13, 19, 17, 18, 18, 18, 19, 20,
- 59, 20, 20, 20, 21, 21, 21, 20, 20, 20,
- 20, 22, 22, 21, 24, 24, 26, 26, 27, 76,
- 76, 76, 50, 50, 55, 27, 44, 49, 44, 44,
- 44, 50, 77, 77, 44, 44, 44, 44, 48, 33,
- 48, 48, 48, 51, 51, 51, 48, 48, 48, 48,
-
- 51, 52, 52, 53, 32, 52, 52, 52, 70, 70,
- 70, 82, 82, 53, 53, 70, 72, 72, 83, 83,
- 72, 72, 72, 75, 75, 78, 31, 75, 75, 75,
- 81, 81, 81, 23, 15, 78, 78, 84, 84, 84,
- 85, 85, 85, 87, 87, 87, 87, 87, 89, 12,
- 10, 89, 89, 90, 9, 90, 90, 90, 91, 91,
- 7, 5, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 86, 86, 86, 86
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+ 3, 4, 4, 13, 16, 99, 3, 92, 4, 17,
+ 64, 19, 16, 27, 13, 19, 17, 18, 18, 18,
+ 19, 20, 27, 20, 20, 20, 22, 22, 61, 20,
+ 20, 20, 20, 20, 20, 21, 21, 21, 24, 24,
+ 26, 26, 28, 57, 56, 21, 21, 53, 50, 50,
+ 49, 33, 28, 44, 32, 44, 44, 44, 50, 50,
+ 31, 44, 44, 44, 44, 44, 44, 48, 23, 48,
+
+ 48, 48, 80, 80, 80, 48, 48, 48, 48, 48,
+ 48, 51, 15, 51, 51, 51, 12, 54, 10, 9,
+ 51, 52, 52, 81, 81, 52, 52, 52, 54, 54,
+ 54, 72, 72, 72, 7, 81, 5, 0, 72, 72,
+ 74, 74, 0, 83, 74, 74, 74, 78, 78, 88,
+ 88, 78, 78, 78, 83, 83, 83, 87, 87, 87,
+ 0, 88, 89, 89, 90, 90, 90, 93, 93, 93,
+ 0, 0, 90, 0, 89, 93, 98, 98, 98, 98,
+ 98, 100, 0, 0, 100, 100, 101, 0, 101, 101,
+ 101, 102, 102, 97, 97, 97, 97, 97, 97, 97,
+
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97
} ;
/* The intent behind this definition is that it'll catch
@@ -507,7 +704,7 @@ static yyconst flex_int16_t yy_chk[191] =
#define YY_RESTORE_YY_MORE_OFFSET
/*
//
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// 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.
//
@@ -519,20 +716,27 @@ http://msdn.microsoft.com/en-us/library/2scxys89.aspx
IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
*/
-#include "Tokenizer.h"
+#if defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#endif
+
+#include "compiler/preprocessor/Tokenizer.h"
-#include "DiagnosticsBase.h"
-#include "Token.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/preprocessor/Token.h"
#if defined(__GNUC__)
// Triggered by the auto-generated yy_fatal_error function.
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4244)
#endif
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunknown-pragmas"
-#pragma clang diagnostic ignored "-Wdeprecated-register"
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
#endif
typedef std::string YYSTYPE;
@@ -566,13 +770,25 @@ typedef pp::SourceLocation YYLTYPE;
} while(0);
#define YY_INPUT(buf, result, maxSize) \
- result = yyextra->input.read(buf, maxSize);
+ result = yyextra->input.read(buf, maxSize, &yylineno);
+
+
+
+
#define INITIAL 0
#define COMMENT 1
+
+
+
+
+
#define YY_EXTRA_TYPE pp::Tokenizer::Context*
+
+
+
/* Holds the entire state of the reentrant scanner. */
struct yyguts_t
{
@@ -586,8 +802,8 @@ struct yyguts_t
size_t yy_buffer_stack_max; /**< capacity of stack. */
YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
char yy_hold_char;
- yy_size_t yy_n_chars;
- yy_size_t yyleng_r;
+ int yy_n_chars;
+ int yyleng_r;
char *yy_c_buf_p;
int yy_init;
int yy_start;
@@ -601,65 +817,132 @@ struct yyguts_t
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 pplex_init (yyscan_t* scanner);
int pplex_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 pplex_destroy (yyscan_t yyscanner );
+
+
int ppget_debug (yyscan_t yyscanner );
+
+
void ppset_debug (int debug_flag ,yyscan_t yyscanner );
+
+
YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner );
+
+
void ppset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+
FILE *ppget_in (yyscan_t yyscanner );
-void ppset_in (FILE * in_str ,yyscan_t yyscanner );
+
+
+void ppset_in (FILE * _in_str ,yyscan_t yyscanner );
+
+
FILE *ppget_out (yyscan_t yyscanner );
-void ppset_out (FILE * out_str ,yyscan_t yyscanner );
-yy_size_t ppget_leng (yyscan_t yyscanner );
+
+void ppset_out (FILE * _out_str ,yyscan_t yyscanner );
+
+
+
+ int ppget_leng (yyscan_t yyscanner );
+
+
char *ppget_text (yyscan_t yyscanner );
+
+
int ppget_lineno (yyscan_t yyscanner );
-void ppset_lineno (int line_number ,yyscan_t yyscanner );
+
+
+void ppset_lineno (int _line_number ,yyscan_t yyscanner );
+
+
+
+
+int ppget_column (yyscan_t yyscanner );
+
+
+
+
+
+void ppset_column (int _column_no ,yyscan_t yyscanner );
+
+
+
YYSTYPE * ppget_lval (yyscan_t yyscanner );
+
void ppset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+
YYLTYPE *ppget_lloc (yyscan_t yyscanner );
+
+
void ppset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+
+
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
@@ -672,6 +955,12 @@ extern int ppwrap (yyscan_t yyscanner );
#endif
#endif
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
#endif
@@ -680,19 +969,44 @@ static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#endif
+#if 0
+
+#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 fwrite( yytext, yyleng, 1, yyout )
+#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".
*/
@@ -701,7 +1015,7 @@ static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- yy_size_t n; \
+ size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@@ -714,7 +1028,7 @@ static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
else \
{ \
errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
@@ -729,6 +1043,8 @@ static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#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.
@@ -737,24 +1053,48 @@ static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#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 pplex \
(YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
@@ -762,6 +1102,7 @@ extern int pplex \
(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.
*/
@@ -769,29 +1110,39 @@ extern int pplex \
#define YY_USER_ACTION
#endif
+
+
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
-#define YY_BREAK 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
{
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- /* Line comment */
+
+
yylval = yylval_param;
+
+
yylloc = yylloc_param;
+
if ( !yyg->yy_init )
{
yyg->yy_init = 1;
@@ -800,6 +1151,8 @@ YY_DECL
YY_USER_INIT;
#endif
+
+
if ( ! yyg->yy_start )
yyg->yy_start = 1; /* first start state */
@@ -818,7 +1171,12 @@ YY_DECL
pp_load_buffer_state(yyscanner );
}
- while ( 1 ) /* loops until end-of-file is reached */
+ {
+
+
+ /* Line comment */
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
yy_cp = yyg->yy_c_buf_p;
@@ -834,7 +1192,7 @@ YY_DECL
yy_match:
do
{
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ 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;
@@ -843,13 +1201,13 @@ yy_match:
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 >= 87 )
+ if ( yy_current_state >= 98 )
yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
++yy_cp;
}
- while ( yy_current_state != 86 );
+ while ( yy_current_state != 97 );
yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
@@ -858,8 +1216,11 @@ yy_find_action:
YY_DO_BEFORE_ACTION;
+
+
do_action: /* This label is used only to access EOF actions. */
+
switch ( yy_act )
{ /* beginning of action switch */
case 0: /* must back up */
@@ -875,7 +1236,7 @@ YY_RULE_SETUP
YY_BREAK
/* Block comment */
/* Line breaks are just counted - not returned. */
-/* The comment is replaced by a single space. */
+/* The comment is replaced by a single space. */
case 2:
YY_RULE_SETUP
{ BEGIN(COMMENT); }
@@ -1139,7 +1500,7 @@ case YY_STATE_EOF(COMMENT):
if (YY_START == COMMENT)
{
- yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+ yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
pp::SourceLocation(yyfileno, yylineno),
"");
}
@@ -1279,8 +1640,14 @@ ECHO;
"fatal flex scanner internal error--no action found" );
} /* end of action switch */
} /* end of scanning one token */
+ } /* end of user's declarations */
} /* end of pplex */
+
+
+
+
+
/* yy_get_next_buffer - try to read in a new buffer
*
* Returns a code representing an action:
@@ -1291,9 +1658,9 @@ ECHO;
static int yy_get_next_buffer (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = yyg->yytext_ptr;
- register int number_to_move, i;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ yy_size_t 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] )
@@ -1322,7 +1689,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* 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;
+ number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
@@ -1335,21 +1702,21 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{
- yy_size_t num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ int num_to_read =
+ static_cast<int>(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;
+ 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 )
{
- yy_size_t new_size = b->yy_buf_size * 2;
+ int new_size = b->yy_buf_size * 2;
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
@@ -1362,7 +1729,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
}
else
/* Can't grow it, we don't own it. */
- b->yy_ch_buf = 0;
+ b->yy_ch_buf = NULL;
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR(
@@ -1370,8 +1737,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
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;
+ num_to_read = static_cast<int>(YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1);
}
@@ -1379,8 +1746,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
+ yy_size_t ret = 0;
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, num_to_read );
+ ret, num_to_read );
+ yyg->yy_n_chars = static_cast<int>(ret);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
}
@@ -1404,7 +1773,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
- if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ if ((int) (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. */
yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
@@ -1412,7 +1781,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
}
- yyg->yy_n_chars += number_to_move;
+ yyg->yy_n_chars += static_cast<int>(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;
@@ -1421,19 +1790,21 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
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)
{
- register yy_state_type yy_current_state;
- register char *yy_cp;
+ 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 )
{
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ 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;
@@ -1442,15 +1813,16 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
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 >= 87 )
+ if ( yy_current_state >= 98 )
yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
}
return yy_current_state;
}
+
/* yy_try_NUL_trans - try to make a transition on the NUL character
*
* synopsis
@@ -1458,11 +1830,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
{
- register int yy_is_jam;
+ int yy_is_jam;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
- register char *yy_cp = yyg->yy_c_buf_p;
+ char *yy_cp = yyg->yy_c_buf_p;
- register YY_CHAR yy_c = 1;
+ YY_CHAR yy_c = 1;
if ( yy_accept[yy_current_state] )
{
yyg->yy_last_accepting_state = yy_current_state;
@@ -1471,15 +1843,97 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
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 >= 87 )
+ if ( yy_current_state >= 98 )
yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 86);
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+ yy_is_jam = (yy_current_state == 97);
+ (void)yyg;
return yy_is_jam ? 0 : yy_current_state;
}
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#if 0
+#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 */
+ auto offset = 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. */
+ pprestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( ppwrap(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;
+
+
+ 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.
@@ -1499,6 +1953,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
pp_load_buffer_state(yyscanner );
}
+
/** Switch to a different input buffer.
* @param new_buffer The new input buffer.
* @param yyscanner The scanner object.
@@ -1535,6 +1990,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_did_buffer_switch_on_eof = 1;
}
+
static void pp_load_buffer_state (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -1574,6 +2030,7 @@ static void pp_load_buffer_state (yyscan_t yyscanner)
return b;
}
+
/** Destroy the buffer.
* @param b a buffer created with pp_create_buffer()
* @param yyscanner The scanner object.
@@ -1594,6 +2051,7 @@ static void pp_load_buffer_state (yyscan_t yyscanner)
ppfree((void *) b ,yyscanner );
}
+
/* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer,
* such as during a pprestart() or at EOF.
@@ -1618,8 +2076,11 @@ static void pp_load_buffer_state (yyscan_t yyscanner)
b->yy_bs_column = 0;
}
+
+
b->yy_is_interactive = 0;
+
errno = oerrno;
}
@@ -1684,6 +2145,7 @@ void pppush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t 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.
@@ -1705,6 +2167,7 @@ void pppop_buffer_state (yyscan_t yyscanner)
}
}
+
/* Allocates the stack if it does not exist.
* Guarantees space for at least one push.
*/
@@ -1719,13 +2182,14 @@ static void ppensure_buffer_stack (yyscan_t yyscanner)
* 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;
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
yyg->yy_buffer_stack = (struct yy_buffer_state**)ppalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
, yyscanner);
if ( ! yyg->yy_buffer_stack )
YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" );
+
memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
yyg->yy_buffer_stack_max = num_to_alloc;
@@ -1736,7 +2200,7 @@ static void ppensure_buffer_stack (yyscan_t yyscanner)
if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
/* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
+ 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**)pprealloc
@@ -1752,6 +2216,10 @@ static void ppensure_buffer_stack (yyscan_t yyscanner)
}
}
+
+
+
+
/** 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
@@ -1766,16 +2234,16 @@ YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
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 0;
+ return NULL;
b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" );
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_size = static_cast<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 = 0;
+ b->yy_input_file = NULL;
b->yy_n_chars = b->yy_buf_size;
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
@@ -1787,6 +2255,9 @@ YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
return b;
}
+
+
+
/** Setup the input buffer state to scan a string. The next call to pplex() will
* scan from a @e copy of @a str.
* @param yystr a NUL-terminated string to scan
@@ -1798,29 +2269,33 @@ YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
YY_BUFFER_STATE pp_scan_string (yyconst char * yystr , yyscan_t yyscanner)
{
- return pp_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+ return pp_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner);
}
+
+
+
/** Setup the input buffer state to scan the given bytes. The next call to pplex() will
* scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @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 pp_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
char *buf;
- yy_size_t n, i;
+ yy_size_t n;
+ yy_size_t i;
/* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
+ n = (yy_size_t) _yybytes_len + 2;
buf = (char *) ppalloc(n ,yyscanner );
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" );
- for ( i = 0; i < _yybytes_len; ++i )
+ for ( i = 0; i < static_cast<yy_size_t>(_yybytes_len); ++i )
buf[i] = yybytes[i];
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
@@ -1837,13 +2312,25 @@ YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
return b;
}
+
+
+
+
+
+
+
+
+
+
#ifndef YY_EXIT_FAILURE
#define YY_EXIT_FAILURE 2
#endif
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
{
- (void) fprintf( stderr, "%s\n", msg );
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ (void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
@@ -1864,8 +2351,11 @@ static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
} \
while ( 0 )
+
+
/* Accessor methods (get/set functions) to struct members. */
+
/** Get the user-defined data for this scanner.
* @param yyscanner The scanner object.
*/
@@ -1875,6 +2365,8 @@ YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner)
return yyextra;
}
+
+
/** Get the current line number.
* @param yyscanner The scanner object.
*/
@@ -1882,12 +2374,16 @@ int ppget_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.
*/
@@ -1895,12 +2391,16 @@ int ppget_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.
*/
@@ -1910,6 +2410,8 @@ FILE *ppget_in (yyscan_t yyscanner)
return yyin;
}
+
+
/** Get the output stream.
* @param yyscanner The scanner object.
*/
@@ -1919,15 +2421,18 @@ FILE *ppget_out (yyscan_t yyscanner)
return yyout;
}
+
+
/** Get the length of the current token.
* @param yyscanner The scanner object.
*/
-yy_size_t ppget_leng (yyscan_t yyscanner)
+int ppget_leng (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
return yyleng;
}
+
/** Get the current token.
* @param yyscanner The scanner object.
*/
@@ -1938,6 +2443,8 @@ char *ppget_text (yyscan_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.
@@ -1948,92 +2455,123 @@ void ppset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
yyextra = user_defined ;
}
+
+
/** Set the current line number.
- * @param line_number
+ * @param _line_number line number
* @param yyscanner The scanner object.
*/
-void ppset_lineno (int line_number , yyscan_t yyscanner)
+void ppset_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( "ppset_lineno called with no buffer" , yyscanner);
+ YY_FATAL_ERROR( "ppset_lineno called with no buffer" );
- yylineno = line_number;
+ yylineno = _line_number;
}
+
+
+
/** Set the current column.
- * @param line_number
+ * @param _column_no column number
* @param yyscanner The scanner object.
*/
-void ppset_column (int column_no , yyscan_t yyscanner)
+void ppset_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( "ppset_column called with no buffer" , yyscanner);
+ YY_FATAL_ERROR( "ppset_column called with no buffer" );
- yycolumn = column_no;
+ yycolumn = _column_no;
}
+
+
+
+
/** Set the input stream. This does not discard the current
* input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
* @param yyscanner The scanner object.
* @see pp_switch_to_buffer
*/
-void ppset_in (FILE * in_str , yyscan_t yyscanner)
+void ppset_in (FILE * _in_str , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyin = in_str ;
+ yyin = _in_str ;
}
-void ppset_out (FILE * out_str , yyscan_t yyscanner)
+
+
+void ppset_out (FILE * _out_str , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyout = out_str ;
+ yyout = _out_str ;
}
+
+
+
int ppget_debug (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
return yy_flex_debug;
}
-void ppset_debug (int bdebug , yyscan_t yyscanner)
+
+
+void ppset_debug (int _bdebug , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yy_flex_debug = bdebug ;
+ yy_flex_debug = _bdebug ;
}
+
/* Accessor methods for yylval and yylloc */
+
YYSTYPE * ppget_lval (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
return yylval;
}
+
+
void ppset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
yylval = yylval_param;
}
+
+
+
YYLTYPE *ppget_lloc (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
return yylloc;
}
+
+
void ppset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
yylloc = yylloc_param;
}
+
+
+
+
/* User-visible API */
/* pplex_init is special because it creates the scanner itself, so it is
@@ -2062,6 +2600,7 @@ int pplex_init(yyscan_t* ptr_yy_globals)
return yy_init_globals ( *ptr_yy_globals );
}
+
/* pplex_init_extra has the same functionality as pplex_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
@@ -2098,6 +2637,7 @@ int pplex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* 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;
@@ -2105,24 +2645,31 @@ static int yy_init_globals (yyscan_t yyscanner)
* This function is called from pplex_destroy(), so don't allocate here.
*/
- yyg->yy_buffer_stack = 0;
+
+ yyg->yy_buffer_stack = NULL;
yyg->yy_buffer_stack_top = 0;
yyg->yy_buffer_stack_max = 0;
- yyg->yy_c_buf_p = (char *) 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 = (FILE *) 0;
- yyout = (FILE *) 0;
+ yyin = NULL;
+ yyout = NULL;
#endif
/* For future reference: Set errno on error, since we are called by
@@ -2131,6 +2678,7 @@ static int yy_init_globals (yyscan_t yyscanner)
return 0;
}
+
/* pplex_destroy is for both reentrant and non-reentrant scanners. */
int pplex_destroy (yyscan_t yyscanner)
{
@@ -2147,10 +2695,14 @@ int pplex_destroy (yyscan_t yyscanner)
ppfree(yyg->yy_buffer_stack ,yyscanner);
yyg->yy_buffer_stack = NULL;
+
/* Destroy the start condition stack. */
ppfree(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
* pplex() is called, initialization will occur. */
yy_init_globals( yyscanner);
@@ -2161,23 +2713,32 @@ int pplex_destroy (yyscan_t yyscanner)
return 0;
}
+
+
/*
* Internal utility routines.
*/
+
+
#ifndef yytext_ptr
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
{
- register int i;
+ 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 (yyconst char * s , yyscan_t yyscanner)
{
- register int n;
+ int n;
for ( n = 0; s[n]; ++n )
;
@@ -2185,13 +2746,22 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
}
#endif
+
+
void *ppalloc (yy_size_t size , yyscan_t yyscanner)
{
- return (void *) malloc( size );
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
}
+
+
void *pprealloc (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
@@ -2199,25 +2769,32 @@ void *pprealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
- return (void *) realloc( (char *) ptr, size );
+ return realloc(ptr, size);
}
+
+
void ppfree (void * ptr , yyscan_t yyscanner)
{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
free( (char *) ptr ); /* see pprealloc() for (char *) cast */
}
+
#define YYTABLES_NAME "yytables"
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
+
+
+
+
+
+
+
namespace pp {
-Tokenizer::Tokenizer(Diagnostics* diagnostics)
- : mHandle(0),
- mMaxTokenLength(256)
+Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256)
{
mContext.diagnostics = diagnostics;
}
@@ -2227,9 +2804,10 @@ Tokenizer::~Tokenizer()
destroyScanner();
}
-bool Tokenizer::init(size_t count, const char* const string[], const int length[])
+bool Tokenizer::init(size_t count, const char * const string[], const int length[])
{
- if ((count > 0) && (string == 0)) return false;
+ if ((count > 0) && (string == 0))
+ return false;
mContext.input = Input(count, string, length);
return initScanner();
@@ -2247,14 +2825,19 @@ void Tokenizer::setLineNumber(int line)
ppset_lineno(line,mHandle);
}
-void Tokenizer::lex(Token* token)
+void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
+{
+ mMaxTokenSize = maxTokenSize;
+}
+
+void Tokenizer::lex(Token *token)
{
token->type = pplex(&token->text,&token->location,mHandle);
- if (token->text.size() > mMaxTokenLength)
+ if (token->text.size() > mMaxTokenSize)
{
- mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+ mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
token->location, token->text);
- token->text.erase(mMaxTokenLength);
+ token->text.erase(mMaxTokenSize);
}
token->flags = 0;
@@ -2268,7 +2851,7 @@ void Tokenizer::lex(Token* token)
bool Tokenizer::initScanner()
{
- if ((mHandle == NULL) && pplex_init_extra(&mContext,&mHandle))
+ if ((mHandle == nullptr) && pplex_init_extra(&mContext, &mHandle))
return false;
pprestart(0,mHandle);
@@ -2277,12 +2860,13 @@ bool Tokenizer::initScanner()
void Tokenizer::destroyScanner()
{
- if (mHandle == NULL)
+ if (mHandle == nullptr)
return;
pplex_destroy(mHandle);
- mHandle = NULL;
+ mHandle = nullptr;
}
} // namespace pp
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.h
index 9d131f865..6dfb19c66 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.h
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-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.
//
@@ -7,9 +7,9 @@
#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_
#define COMPILER_PREPROCESSOR_TOKENIZER_H_
-#include "Input.h"
-#include "Lexer.h"
-#include "pp_utils.h"
+#include "common/angleutils.h"
+#include "compiler/preprocessor/Input.h"
+#include "compiler/preprocessor/Lexer.h"
namespace pp
{
@@ -21,7 +21,7 @@ class Tokenizer : public Lexer
public:
struct Context
{
- Diagnostics* diagnostics;
+ Diagnostics *diagnostics;
Input input;
// The location where yytext points to. Token location should track
@@ -33,27 +33,26 @@ class Tokenizer : public Lexer
bool lineStart;
};
- Tokenizer(Diagnostics* diagnostics);
+ Tokenizer(Diagnostics *diagnostics);
~Tokenizer();
- bool init(size_t count, const char* const string[], const int length[]);
+ bool init(size_t count, const char * const string[], const int length[]);
- void setMaxTokenLength(size_t maxLength) { mMaxTokenLength = maxLength; }
void setFileNumber(int file);
void setLineNumber(int line);
+ void setMaxTokenSize(size_t maxTokenSize);
- virtual void lex(Token* token);
+ void lex(Token *token) override;
private:
- PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
bool initScanner();
void destroyScanner();
- void* mHandle; // Scanner handle.
+ void *mHandle; // Scanner handle.
Context mContext; // Scanner extra.
- size_t mMaxTokenLength;
+ size_t mMaxTokenSize; // Maximum token size
};
} // namespace pp
-#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_
+#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.l b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.l
new file mode 100644
index 000000000..62eb4caa6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/Tokenizer.l
@@ -0,0 +1,357 @@
+/*
+//
+// 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 contains the Lex specification for GLSL ES preprocessor.
+Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
+http://msdn.microsoft.com/en-us/library/2scxys89.aspx
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
+*/
+
+%top{
+//
+// 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.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+}
+
+%{
+#if defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#endif
+
+#include "compiler/preprocessor/Tokenizer.h"
+
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/preprocessor/Token.h"
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated yy_fatal_error function.
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4244)
+#endif
+
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
+#endif
+
+typedef std::string YYSTYPE;
+typedef pp::SourceLocation YYLTYPE;
+
+// Use the unused yycolumn variable to track file (string) number.
+#define yyfileno yycolumn
+
+#define YY_USER_INIT \
+ do { \
+ yyfileno = 0; \
+ yylineno = 1; \
+ yyextra->leadingSpace = false; \
+ yyextra->lineStart = true; \
+ } while(0);
+
+#define YY_USER_ACTION \
+ do \
+ { \
+ pp::Input* input = &yyextra->input; \
+ pp::Input::Location* scanLoc = &yyextra->scanLoc; \
+ while ((scanLoc->sIndex < input->count()) && \
+ (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
+ { \
+ scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
+ ++yyfileno; yylineno = 1; \
+ } \
+ yylloc->file = yyfileno; \
+ yylloc->line = yylineno; \
+ scanLoc->cIndex += yyleng; \
+ } while(0);
+
+#define YY_INPUT(buf, result, maxSize) \
+ result = yyextra->input.read(buf, maxSize, &yylineno);
+
+%}
+
+%option noyywrap nounput never-interactive
+%option reentrant bison-bridge bison-locations
+%option prefix="pp"
+%option extra-type="pp::Tokenizer::Context*"
+%x COMMENT
+
+NEWLINE \n|\r|\r\n
+IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
+PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?]
+
+DECIMAL_CONSTANT [1-9][0-9]*[uU]?
+OCTAL_CONSTANT 0[0-7]*[uU]?
+HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+[uU]?
+
+DIGIT [0-9]
+EXPONENT_PART [eE][+-]?{DIGIT}+
+FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
+
+%%
+
+ /* Line comment */
+"//"[^\r\n]*
+
+ /* Block comment */
+ /* Line breaks are just counted - not returned. */
+ /* The comment is replaced by a single space. */
+"/*" { BEGIN(COMMENT); }
+<COMMENT>[^*\r\n]+
+<COMMENT>"*"
+<COMMENT>{NEWLINE} { ++yylineno; }
+<COMMENT>"*/" {
+ yyextra->leadingSpace = true;
+ BEGIN(INITIAL);
+}
+
+# {
+ // # is only valid at start of line for preprocessor directives.
+ yylval->assign(1, yytext[0]);
+ return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
+}
+
+{IDENTIFIER} {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::IDENTIFIER;
+}
+
+({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_INT;
+}
+
+({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_FLOAT;
+}
+
+ /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
+ /* Rule to catch all invalid integers and floats. */
+({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::PP_NUMBER;
+}
+
+"++" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_INC;
+}
+"--" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DEC;
+}
+"<<" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT;
+}
+">>" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT;
+}
+"<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LE;
+}
+">=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_GE;
+}
+"==" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_EQ;
+}
+"!=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_NE;
+}
+"&&" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND;
+}
+"^^" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR;
+}
+"||" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR;
+}
+"+=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_ADD_ASSIGN;
+}
+"-=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_SUB_ASSIGN;
+}
+"*=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MUL_ASSIGN;
+}
+"/=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DIV_ASSIGN;
+}
+"%=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MOD_ASSIGN;
+}
+"<<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT_ASSIGN;
+}
+">>=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT_ASSIGN;
+}
+"&=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND_ASSIGN;
+}
+"^=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR_ASSIGN;
+}
+"|=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR_ASSIGN;
+}
+
+{PUNCTUATOR} {
+ yylval->assign(1, yytext[0]);
+ return yytext[0];
+}
+
+[ \t\v\f]+ { yyextra->leadingSpace = true; }
+
+{NEWLINE} {
+ ++yylineno;
+ yylval->assign(1, '\n');
+ return '\n';
+}
+
+\\{NEWLINE} { ++yylineno; }
+
+. {
+ yylval->assign(1, yytext[0]);
+ return pp::Token::PP_OTHER;
+}
+
+<*><<EOF>> {
+ // YY_USER_ACTION is not invoked for handling EOF.
+ // Set the location for EOF token manually.
+ pp::Input* input = &yyextra->input;
+ pp::Input::Location* scanLoc = &yyextra->scanLoc;
+ yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
+ if (scanLoc->sIndex != sIndexMax)
+ {
+ // We can only reach here if there are empty strings at the
+ // end of the input.
+ scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
+ // FIXME: this is not 64-bit clean.
+ yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
+ }
+ yylloc->file = yyfileno;
+ yylloc->line = yylineno;
+ yylval->clear();
+
+ if (YY_START == COMMENT)
+ {
+ yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
+ pp::SourceLocation(yyfileno, yylineno),
+ "");
+ }
+ yyterminate();
+}
+
+%%
+
+namespace pp {
+
+Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256)
+{
+ mContext.diagnostics = diagnostics;
+}
+
+Tokenizer::~Tokenizer()
+{
+ destroyScanner();
+}
+
+bool Tokenizer::init(size_t count, const char * const string[], const int length[])
+{
+ if ((count > 0) && (string == 0))
+ return false;
+
+ mContext.input = Input(count, string, length);
+ return initScanner();
+}
+
+void Tokenizer::setFileNumber(int file)
+{
+ // We use column number as file number.
+ // See macro yyfileno.
+ yyset_column(file, mHandle);
+}
+
+void Tokenizer::setLineNumber(int line)
+{
+ yyset_lineno(line, mHandle);
+}
+
+void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
+{
+ mMaxTokenSize = maxTokenSize;
+}
+
+void Tokenizer::lex(Token *token)
+{
+ token->type = yylex(&token->text, &token->location, mHandle);
+ if (token->text.size() > mMaxTokenSize)
+ {
+ mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
+ token->location, token->text);
+ token->text.erase(mMaxTokenSize);
+ }
+
+ token->flags = 0;
+
+ token->setAtStartOfLine(mContext.lineStart);
+ mContext.lineStart = token->type == '\n';
+
+ token->setHasLeadingSpace(mContext.leadingSpace);
+ mContext.leadingSpace = false;
+}
+
+bool Tokenizer::initScanner()
+{
+ if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
+ return false;
+
+ yyrestart(0, mHandle);
+ return true;
+}
+
+void Tokenizer::destroyScanner()
+{
+ if (mHandle == nullptr)
+ return;
+
+ yylex_destroy(mHandle);
+ mHandle = nullptr;
+}
+
+} // namespace pp
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/generate_parser.sh b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/generate_parser.sh
new file mode 100755
index 000000000..032858722
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/generate_parser.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# 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.
+
+# Generates various components of GLSL ES preprocessor.
+
+run_flex()
+{
+input_file=$script_dir/$1
+output_source=$script_dir/$2
+flex --noline --nounistd --outfile=$output_source $input_file
+}
+
+run_bison()
+{
+input_file=$script_dir/$1
+output_source=$script_dir/$2
+bison --no-lines --skeleton=yacc.c --output=$output_source $input_file
+}
+
+script_dir=$(dirname $0)
+
+# Generate preprocessor
+run_flex Tokenizer.l Tokenizer.cpp
+run_bison ExpressionParser.y ExpressionParser.cpp
+patch --silent --forward < 64bit-tokenizer-safety.patch
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/length_limits.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/length_limits.h
deleted file mode 100644
index 4f1f71319..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/length_limits.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// 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.
-//
-
-//
-// length_limits.h
-//
-
-#if !defined(__LENGTH_LIMITS_H)
-#define __LENGTH_LIMITS_H 1
-
-// These constants are factored out from the rest of the headers to
-// make it easier to reference them from the compiler sources.
-
-// These lengths do not include the NULL terminator.
-#define MAX_SYMBOL_NAME_LEN 256
-#define MAX_STRING_LEN 511
-
-#endif // !(defined(__LENGTH_LIMITS_H)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/numeric_lex.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/numeric_lex.h
index b04125d23..b32e42253 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/numeric_lex.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/numeric_lex.h
@@ -6,14 +6,14 @@
// numeric_lex.h: Functions to extract numeric values from string.
-#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
-#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+#ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_
+#define COMPILER_PREPROCESSOR_NUMERICLEX_H_
#include <sstream>
namespace pp {
-inline std::ios::fmtflags numeric_base_int(const std::string& str)
+inline std::ios::fmtflags numeric_base_int(const std::string &str)
{
if ((str.size() >= 2) &&
(str[0] == '0') &&
@@ -21,7 +21,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string& str)
{
return std::ios::hex;
}
- else if ((str.size() >= 1) && (str[0] == '0'))
+ if ((str.size() >= 1) && (str[0] == '0'))
{
return std::ios::oct;
}
@@ -34,7 +34,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string& str)
// in which case false is returned.
template<typename IntType>
-bool numeric_lex_int(const std::string& str, IntType* value)
+bool numeric_lex_int(const std::string &str, IntType *value)
{
std::istringstream stream(str);
// This should not be necessary, but MSVS has a buggy implementation.
@@ -46,8 +46,17 @@ bool numeric_lex_int(const std::string& str, IntType* value)
}
template<typename FloatType>
-bool numeric_lex_float(const std::string& str, FloatType* value)
+bool numeric_lex_float(const std::string &str, FloatType *value)
{
+// On 64-bit Intel Android, istringstream is broken. Until this is fixed in
+// a newer NDK, don't use it. Android doesn't have locale support, so this
+// doesn't have to force the C locale.
+// TODO(thakis): Remove this once this bug has been fixed in the NDK and
+// that NDK has been rolled into chromium.
+#if defined(ANGLE_PLATFORM_ANDROID) && __x86_64__
+ *value = strtod(str.c_str(), nullptr);
+ return errno != ERANGE;
+#else
std::istringstream stream(str);
// Force "C" locale so that decimal character is always '.', and
// not dependent on the current locale.
@@ -55,7 +64,9 @@ bool numeric_lex_float(const std::string& str, FloatType* value)
stream >> (*value);
return !stream.fail();
+#endif
}
} // namespace pp.
-#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+
+#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/pp_utils.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/pp_utils.h
deleted file mode 100644
index 17164ea8b..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/pp_utils.h
+++ /dev/null
@@ -1,18 +0,0 @@
-//
-// 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.
-//
-
-// pp_utils.h: Common preprocessor utilities
-
-#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_
-#define COMPILER_PREPROCESSOR_PPUTILS_H_
-
-// A macro to disallow the copy constructor and operator= functions
-// This must be used in the private: declarations for a class.
-#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-#endif // COMPILER_PREPROCESSOR_PPUTILS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.cpp b/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.cpp
deleted file mode 100644
index b9d2bab17..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/InfoSink.h"
-#include "compiler/ParseContext.h"
-#include "compiler/depgraph/DependencyGraphOutput.h"
-#include "compiler/timing/RestrictFragmentShaderTiming.h"
-
-RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
- : mSink(sink)
- , mNumErrors(0)
-{
- // Sampling ops found only in fragment shaders.
- mSamplingOps.insert("texture2D(s21;vf2;f1;");
- mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
- mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
- mSamplingOps.insert("textureCube(sC1;vf3;f1;");
- // Sampling ops found in both vertex and fragment shaders.
- mSamplingOps.insert("texture2D(s21;vf2;");
- mSamplingOps.insert("texture2DProj(s21;vf3;");
- mSamplingOps.insert("texture2DProj(s21;vf4;");
- mSamplingOps.insert("textureCube(sC1;vf3;");
- // Sampling ops provided by OES_EGL_image_external.
- mSamplingOps.insert("texture2D(1;vf2;");
- mSamplingOps.insert("texture2DProj(1;vf3;");
- mSamplingOps.insert("texture2DProj(1;vf4;");
- // Sampling ops provided by ARB_texture_rectangle.
- mSamplingOps.insert("texture2DRect(1;vf2;");
- mSamplingOps.insert("texture2DRectProj(1;vf3;");
- mSamplingOps.insert("texture2DRectProj(1;vf4;");
-}
-
-// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
-// can vary based on the value of the input arguments. If so, we should restrict those as well.
-void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
-{
- mNumErrors = 0;
-
- // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
- // so we generate errors for them.
- validateUserDefinedFunctionCallUsage(graph);
-
- // Starting from each sampler, traverse the dependency graph and generate an error each time we
- // hit a node where sampler dependent values are not allowed.
- for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
- iter != graph.endSamplerSymbols();
- ++iter)
- {
- TGraphSymbol* samplerSymbol = *iter;
- clearVisited();
- samplerSymbol->traverse(this);
- }
-}
-
-void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
-{
- for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
- iter != graph.endUserDefinedFunctionCalls();
- ++iter)
- {
- TGraphFunctionCall* functionCall = *iter;
- beginError(functionCall->getIntermFunctionCall());
- mSink << "A call to a user defined function is not permitted.\n";
- }
-}
-
-void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
-{
- ++mNumErrors;
- mSink.prefix(EPrefixError);
- mSink.location(node->getLine());
-}
-
-bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
-{
- return !intermFunctionCall->isUserDefined() &&
- mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
-}
-
-void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
-{
- // Texture cache access time might leak sensitive information.
- // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
- // sampling operation.
- if (isSamplingOp(parameter->getIntermFunctionCall())) {
- switch (parameter->getArgumentNumber()) {
- case 1:
- // Second argument (coord)
- beginError(parameter->getIntermFunctionCall());
- mSink << "An expression dependent on a sampler is not permitted to be the"
- << " coordinate argument of a sampling operation.\n";
- break;
- case 2:
- // Third argument (bias)
- beginError(parameter->getIntermFunctionCall());
- mSink << "An expression dependent on a sampler is not permitted to be the"
- << " bias argument of a sampling operation.\n";
- break;
- default:
- // First argument (sampler)
- break;
- }
- }
-}
-
-void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
-{
- beginError(selection->getIntermSelection());
- mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
-}
-
-void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
-{
- beginError(loop->getIntermLoop());
- mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
-}
-
-void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
-{
- beginError(logicalOp->getIntermLogicalOp());
- mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
- << logicalOp->getOpString()
- << " operator.\n";
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.h b/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.h
deleted file mode 100644
index 899165ca2..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictFragmentShaderTiming.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// 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_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
-#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/intermediate.h"
-#include "compiler/depgraph/DependencyGraph.h"
-
-class TInfoSinkBase;
-
-class RestrictFragmentShaderTiming : TDependencyGraphTraverser {
-public:
- RestrictFragmentShaderTiming(TInfoSinkBase& sink);
- void enforceRestrictions(const TDependencyGraph& graph);
- int numErrors() const { return mNumErrors; }
-
- virtual void visitArgument(TGraphArgument* parameter);
- virtual void visitSelection(TGraphSelection* selection);
- virtual void visitLoop(TGraphLoop* loop);
- virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
-
-private:
- void beginError(const TIntermNode* node);
- void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph);
- bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const;
-
- TInfoSinkBase& mSink;
- int mNumErrors;
-
- typedef std::set<TString> StringSet;
- StringSet mSamplingOps;
-};
-
-#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.cpp b/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.cpp
deleted file mode 100644
index 355eb62d6..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// 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.
-//
-
-#include "compiler/timing/RestrictVertexShaderTiming.h"
-
-void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node)
-{
- if (IsSampler(node->getBasicType())) {
- ++mNumErrors;
- mSink.message(EPrefixError,
- node->getLine(),
- "Samplers are not permitted in vertex shaders");
- }
-}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.h b/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.h
deleted file mode 100644
index 19a05fa68..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/timing/RestrictVertexShaderTiming.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// 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_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
-#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
-
-#include "GLSLANG/ShaderLang.h"
-
-#include "compiler/intermediate.h"
-#include "compiler/InfoSink.h"
-
-class TInfoSinkBase;
-
-class RestrictVertexShaderTiming : public TIntermTraverser {
-public:
- RestrictVertexShaderTiming(TInfoSinkBase& sink)
- : TIntermTraverser(true, false, false)
- , mSink(sink)
- , mNumErrors(0) {}
-
- void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
- int numErrors() { return mNumErrors; }
-
- virtual void visitSymbol(TIntermSymbol*);
-private:
- TInfoSinkBase& mSink;
- int mNumErrors;
-};
-
-#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/64bit-lexer-safety.patch b/Source/ThirdParty/ANGLE/src/compiler/translator/64bit-lexer-safety.patch
new file mode 100644
index 000000000..db3b2fab5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/64bit-lexer-safety.patch
@@ -0,0 +1,40 @@
+--- a/src/compiler/glslang_lex.cpp
++++ b/src/compiler/glslang_lex.cpp
+@@ -68,6 +68,7 @@ typedef int16_t flex_int16_t;
+ typedef uint16_t flex_uint16_t;
+ typedef int32_t flex_int32_t;
+ typedef uint32_t flex_uint32_t;
++typedef uint64_t flex_uint64_t;
+ #else
+ typedef signed char flex_int8_t;
+ typedef short int flex_int16_t;
+@@ -191,6 +192,11 @@ typedef void* yyscan_t;
+ 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
+@@ -204,7 +210,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+- int yyl;\
++ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+@@ -378,7 +379,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+ */
+ #define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+- yyleng = (size_t) (yy_cp - yy_bp); \
++ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.cpp
new file mode 100644
index 000000000..cbeaff5ae
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -0,0 +1,452 @@
+//
+// 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"
+
+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());
+ }
+
+ 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:
+ onGradient();
+ default:
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit)
+ {
+ if (node->getOp() == EOpFunctionCall)
+ {
+ if (node->isUserDefined())
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(mIndex);
+
+ if ((*mMetadataList)[calleeIndex].mUsesGradient) {
+ onGradient();
+ }
+ }
+ else
+ {
+ TString name =
+ TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
+
+ if (name == "texture2D" ||
+ name == "texture2DProj" ||
+ name == "textureCube")
+ {
+ 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;
+};
+
+// 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() == EOpFunctionCall)
+ {
+ if (node->isUserDefined())
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(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 EOpFunctionCall:
+ if (visit == PreVisit && node->isUserDefined() && mNestedDiscont > 0)
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(mIndex);
+
+ (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ int mNestedDiscont;
+};
+
+}
+
+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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.h
new file mode 100644
index 000000000..4795bc387
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ASTMetadataHLSL.h
@@ -0,0 +1,58 @@
+//
+// 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>
+
+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);
+
+#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.cpp
new file mode 100644
index 000000000..0177fea96
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.cpp
@@ -0,0 +1,59 @@
+//
+// 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/AddAndTrueToLoopCondition.h"
+
+#include "compiler/translator/IntermNode.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.
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, TType(EbtBool));
+
+ // 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/Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.h b/Source/ThirdParty/ANGLE/src/compiler/translator/AddAndTrueToLoopCondition.h
new file mode 100644
index 000000000..34debe0ed
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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_ADDANDTRUETOLOOPCONDITION_H_
+#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void AddAndTrueToLoopCondition(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.cpp
new file mode 100644
index 000000000..5767aea2b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.cpp
@@ -0,0 +1,76 @@
+//
+// 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/AddDefaultReturnStatements.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class AddDefaultReturnStatementsTraverser : private TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root)
+ {
+ AddDefaultReturnStatementsTraverser separateInit;
+ root->traverse(&separateInit);
+ separateInit.updateTree();
+ }
+
+ private:
+ AddDefaultReturnStatementsTraverser() : TIntermTraverser(true, false, false) {}
+
+ static bool IsFunctionWithoutReturnStatement(TIntermFunctionDefinition *node, TType *returnType)
+ {
+ *returnType = node->getType();
+ if (node->getType().getBasicType() == EbtVoid)
+ {
+ return false;
+ }
+
+ TIntermBlock *bodyNode = node->getBody();
+ TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode();
+ if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *node) override
+ {
+ TType returnType;
+ if (IsFunctionWithoutReturnStatement(node, &returnType))
+ {
+ TIntermBranch *branch =
+ new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
+
+ TIntermBlock *bodyNode = node->getBody();
+ bodyNode->getSequence()->push_back(branch);
+
+ return false;
+ }
+
+ return true;
+ }
+};
+} // anonymous namespace
+
+void AddDefaultReturnStatements(TIntermNode *node)
+{
+ AddDefaultReturnStatementsTraverser::Apply(node);
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.h b/Source/ThirdParty/ANGLE/src/compiler/translator/AddDefaultReturnStatements.h
new file mode 100644
index 000000000..d765a7ae4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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_ADDDEFAULTRETURNSTATEMENTS_H_
+#define COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void AddDefaultReturnStatements(TIntermNode *node);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
new file mode 100644
index 000000000..f2891cfca
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -0,0 +1,212 @@
+//
+// 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/ArrayReturnValueToOutParameter.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to)
+{
+ const TIntermSequence *fromSequence = from->getSequence();
+ for (size_t ii = 0; ii < fromSequence->size(); ++ii)
+ {
+ to->getSequence()->push_back(fromSequence->at(ii));
+ }
+}
+
+TIntermSymbol *CreateReturnValueSymbol(const TType &type)
+{
+ TIntermSymbol *node = new TIntermSymbol(0, "angle_return", type);
+ node->setInternal(true);
+ return node;
+}
+
+TIntermSymbol *CreateReturnValueOutSymbol(const TType &type)
+{
+ TType outType(type);
+ outType.setQualifier(EvqOut);
+ return CreateReturnValueSymbol(outType);
+}
+
+TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermTyped *returnValueTarget)
+{
+ TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
+ replacementCall->setType(TType(EbtVoid));
+ replacementCall->setUserDefined();
+ *replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
+ replacementCall->setLine(originalCall->getLine());
+ TIntermSequence *replacementParameters = replacementCall->getSequence();
+ TIntermSequence *originalParameters = originalCall->getSequence();
+ for (auto &param : *originalParameters)
+ {
+ replacementParameters->push_back(param);
+ }
+ replacementParameters->push_back(returnValueTarget);
+ return replacementCall;
+}
+
+class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root, unsigned int *temporaryIndex);
+ private:
+ ArrayReturnValueToOutParameterTraverser();
+
+ 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;
+
+ bool mInFunctionWithArrayReturnValue;
+};
+
+void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam;
+ arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex);
+ root->traverse(&arrayReturnValueToOutParam);
+ arrayReturnValueToOutParam.updateTree();
+}
+
+ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser()
+ : TIntermTraverser(true, false, true),
+ mInFunctionWithArrayReturnValue(false)
+{
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition(
+ Visit visit,
+ TIntermFunctionDefinition *node)
+{
+ if (node->isArray() && visit == PreVisit)
+ {
+ // Replace the parameters child node of the function definition with another node
+ // that has the out parameter added.
+ // Also set the function to return void.
+
+ TIntermAggregate *params = node->getFunctionParameters();
+ ASSERT(params != nullptr && params->getOp() == EOpParameters);
+
+ TIntermAggregate *replacementParams = new TIntermAggregate;
+ replacementParams->setOp(EOpParameters);
+ CopyAggregateChildren(params, replacementParams);
+ replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
+ replacementParams->setLine(params->getLine());
+
+ queueReplacementWithParent(node, params, replacementParams, OriginalNode::IS_DROPPED);
+
+ node->setType(TType(EbtVoid));
+
+ mInFunctionWithArrayReturnValue = true;
+ }
+ if (visit == PostVisit)
+ {
+ // This isn't conditional on node->isArray() since the type has already been changed on
+ // PreVisit.
+ mInFunctionWithArrayReturnValue = false;
+ }
+ return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit == PreVisit)
+ {
+ if (node->isArray())
+ {
+ if (node->getOp() == EOpPrototype)
+ {
+ // Replace the whole prototype node with another node that has the out parameter added.
+ TIntermAggregate *replacement = new TIntermAggregate;
+ replacement->setOp(EOpPrototype);
+ CopyAggregateChildren(node, replacement);
+ replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
+ replacement->setUserDefined();
+ *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
+ replacement->setLine(node->getLine());
+ replacement->setType(TType(EbtVoid));
+
+ queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
+ }
+ else if (node->getOp() == EOpFunctionCall)
+ {
+ // 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)
+ {
+ nextTemporaryIndex();
+ TIntermSequence replacements;
+ replacements.push_back(createTempDeclaration(node->getType()));
+ TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
+ replacements.push_back(CreateReplacementCall(node, returnSymbol));
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mInFunctionWithArrayReturnValue && 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);
+ TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
+ 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();
+ if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
+ {
+ TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
+ queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED);
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.h
new file mode 100644
index 000000000..983e203e6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ArrayReturnValueToOutParameter.h
@@ -0,0 +1,16 @@
+//
+// 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_ARRAYRETURNVALUETOOUTPARAMETER_H_
+#define COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
+
+class TIntermNode;
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BaseTypes.h b/Source/ThirdParty/ANGLE/src/compiler/translator/BaseTypes.h
new file mode 100644
index 000000000..a3d9a6083
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BaseTypes.h
@@ -0,0 +1,531 @@
+//
+// 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 "common/debug.h"
+#include "GLSLANG/ShaderLang.h"
+
+//
+// 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,
+ EbtGVec4, // non type: represents vec4, ivec4, and uvec4
+ EbtGenType, // non type: represents float, vec2, vec3, and vec4
+ EbtGenIType, // non type: represents int, ivec2, ivec3, and ivec4
+ EbtGenUType, // non type: represents uint, uvec2, uvec3, and uvec4
+ EbtGenBType, // non type: represents bool, bvec2, bvec3, and bvec4
+ EbtVec, // non type: represents vec2, vec3, and vec4
+ EbtIVec, // non type: represents ivec2, ivec3, and ivec4
+ EbtUVec, // non type: represents uvec2, uvec3, and uvec4
+ EbtBVec, // non type: represents bvec2, bvec3, and bvec4
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D,
+ EbtSampler3D,
+ EbtSamplerCube,
+ EbtSampler2DArray,
+ EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
+ EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
+ EbtISampler2D,
+ EbtISampler3D,
+ EbtISamplerCube,
+ EbtISampler2DArray,
+ EbtUSampler2D,
+ EbtUSampler3D,
+ EbtUSamplerCube,
+ EbtUSampler2DArray,
+ EbtSampler2DShadow,
+ EbtSamplerCubeShadow,
+ EbtSampler2DArrayShadow,
+ EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
+ EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D
+ EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D
+ EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube
+ EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and usampler2DArray
+ EbtStruct,
+ EbtInterfaceBlock,
+ EbtAddress, // should be deprecated??
+
+ // end of list
+ EbtLast
+};
+
+const char* getBasicString(TBasicType t);
+
+inline bool IsSampler(TBasicType type)
+{
+ return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
+}
+
+inline bool IsIntegerSampler(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ return true;
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSampler2D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ return true;
+ 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 EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSampler2DArray:
+ 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 EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtISampler2D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ 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 EbtSampler2DArrayShadow:
+ return true;
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCube:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ 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 EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ return false;
+ default:
+ assert(!IsSampler(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 || IsSampler(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
+
+ 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,
+
+ // 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
+
+ // 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
+ EvqComputeIn,
+ EvqNumWorkGroups,
+ EvqWorkGroupSize,
+ EvqWorkGroupID,
+ EvqLocalInvocationID,
+ EvqGlobalInvocationID,
+ EvqLocalInvocationIndex,
+
+ // end of list
+ EvqLast
+};
+
+inline bool IsQualifierUnspecified(TQualifier qualifier)
+{
+ return (qualifier == EvqTemporary || qualifier == EvqGlobal);
+}
+
+enum TLayoutMatrixPacking
+{
+ EmpUnspecified,
+ EmpRowMajor,
+ EmpColumnMajor
+};
+
+enum TLayoutBlockStorage
+{
+ EbsUnspecified,
+ EbsShared,
+ EbsPacked,
+ EbsStd140
+};
+
+struct TLayoutQualifier
+{
+ int location;
+ unsigned int locationsSpecified;
+ TLayoutMatrixPacking matrixPacking;
+ TLayoutBlockStorage blockStorage;
+
+ // Compute shader layout qualifiers.
+ sh::WorkGroupSize localSize;
+
+ static TLayoutQualifier create()
+ {
+ TLayoutQualifier layoutQualifier;
+
+ layoutQualifier.location = -1;
+ layoutQualifier.locationsSpecified = 0;
+ layoutQualifier.matrixPacking = EmpUnspecified;
+ layoutQualifier.blockStorage = EbsUnspecified;
+
+ layoutQualifier.localSize.fill(-1);
+
+ return layoutQualifier;
+ }
+
+ bool isEmpty() const
+ {
+ return location == -1 && matrixPacking == EmpUnspecified &&
+ blockStorage == EbsUnspecified && !localSize.isAnyValueSet();
+ }
+
+ bool isCombinationValid() const
+ {
+ bool workSizeSpecified = localSize.isAnyValueSet();
+ bool otherLayoutQualifiersSpecified =
+ (location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified);
+
+ // we can have either the work group size specified, or the other layout qualifiers
+ return !(workSizeSpecified && otherLayoutQualifiersSpecified);
+ }
+
+ bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const
+ {
+ return localSize.isWorkGroupSizeMatching(localSizeIn);
+ }
+};
+
+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 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 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 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 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 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";
+ 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";
+ default: UNREACHABLE(); return "unknown block storage";
+ }
+}
+
+#endif // COMPILER_TRANSLATOR_BASETYPES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
new file mode 100644
index 000000000..aada0fac7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
@@ -0,0 +1,106 @@
+//
+// 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/IntermNode.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
+{
+
+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, TIntermTyped::CreateZero(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
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root)
+{
+ AliasingBreaker breaker;
+ root->traverse(&breaker);
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.h b/Source/ThirdParty/ANGLE/src/compiler/translator/BreakVariableAliasingInInnerLoops.h
new file mode 100644
index 000000000..b1d906f91
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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_BREAKVARIABLEALIASINGININNERLOOPS_H_
+#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.cpp
new file mode 100644
index 000000000..483fb4467
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,244 @@
+//
+// 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 "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/Cache.h"
+
+class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
+{
+ public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
+ : TIntermTraverser(true, false, false),
+ mEmulator(emulator)
+ {
+ }
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ if (visit == PreVisit)
+ {
+ bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit)
+ {
+ // Here we handle all the built-in functions instead of the ones we
+ // currently identified as problematic.
+ switch (node->getOp())
+ {
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpMod:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpOuterProduct:
+ case EOpMul:
+ break;
+ default:
+ return true;
+ }
+ const TIntermSequence &sequence = *(node->getSequence());
+ bool needToEmulate = false;
+ // Right now we only handle built-in functions with two or three parameters.
+ if (sequence.size() == 2)
+ {
+ TIntermTyped *param1 = sequence[0]->getAsTyped();
+ TIntermTyped *param2 = sequence[1]->getAsTyped();
+ if (!param1 || !param2)
+ return true;
+ needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), param1->getType(), param2->getType());
+ }
+ else if (sequence.size() == 3)
+ {
+ TIntermTyped *param1 = sequence[0]->getAsTyped();
+ TIntermTyped *param2 = sequence[1]->getAsTyped();
+ TIntermTyped *param3 = sequence[2]->getAsTyped();
+ if (!param1 || !param2 || !param3)
+ return true;
+ needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), param1->getType(), param2->getType(), param3->getType());
+ }
+ else
+ {
+ return true;
+ }
+
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ private:
+ BuiltInFunctionEmulator &mEmulator;
+};
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator()
+{}
+
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition);
+}
+
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition);
+}
+
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
+ const TType *param3, const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition);
+}
+
+bool BuiltInFunctionEmulator::IsOutputEmpty() const
+{
+ return (mFunctions.size() == 0);
+}
+
+void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
+{
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
+ out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
+ }
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param)
+{
+ return SetFunctionCalled(FunctionId(op, &param));
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param1, const TType &param2)
+{
+ return SetFunctionCalled(FunctionId(op, &param1, &param2));
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
+ const TType &param1, const TType &param2, const TType &param3)
+{
+ return SetFunctionCalled(FunctionId(op, &param1, &param2, &param3));
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
+{
+ if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
+ {
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
+ if (mFunctions[i] == functionId)
+ return true;
+ }
+ // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
+ // remain valid and constant.
+ mFunctions.push_back(functionId.getCopy());
+ return true;
+ }
+ return false;
+}
+
+void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
+{
+ ASSERT(root);
+
+ if (mEmulatedFunctions.empty())
+ return;
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::Cleanup()
+{
+ mFunctions.clear();
+}
+
+//static
+TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
+ const TString &name)
+{
+ ASSERT(name[name.length() - 1] == '(');
+ return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
+}
+
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
+ : mOp(op),
+ mParam1(param),
+ mParam2(TCache::getType(EbtVoid)),
+ mParam3(TCache::getType(EbtVoid))
+{
+}
+
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
+ : mOp(op),
+ mParam1(param1),
+ mParam2(param2),
+ mParam3(TCache::getType(EbtVoid))
+{
+}
+
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
+ const TType *param1, const TType *param2, const TType *param3)
+ : mOp(op),
+ mParam1(param1),
+ mParam2(param2),
+ mParam3(param3)
+{
+}
+
+bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const
+{
+ return (mOp == other.mOp &&
+ *mParam1 == *other.mParam1 &&
+ *mParam2 == *other.mParam2 &&
+ *mParam3 == *other.mParam3);
+}
+
+bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulator::FunctionId &other) const
+{
+ if (mOp != other.mOp)
+ return mOp < other.mOp;
+ if (*mParam1 != *other.mParam1)
+ return *mParam1 < *other.mParam1;
+ if (*mParam2 != *other.mParam2)
+ return *mParam2 < *other.mParam2;
+ if (*mParam3 != *other.mParam3)
+ return *mParam3 < *other.mParam3;
+ return false; // all fields are equal
+}
+
+BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
+{
+ return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.h b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.h
new file mode 100644
index 000000000..6976edfd5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -0,0 +1,85 @@
+//
+// 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"
+#include "compiler/translator/IntermNode.h"
+
+//
+// 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(" becomes "webgl_name_emu(".
+ static TString GetEmulatedFunctionName(const TString &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(TOperator op, const TType *param, const char *emulatedFunctionDefinition);
+ void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
+ const char *emulatedFunctionDefinition);
+ void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, const TType *param3,
+ const char *emulatedFunctionDefinition);
+
+ 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(TOperator op, const TType &param);
+ bool SetFunctionCalled(TOperator op, const TType &param1, const TType &param2);
+ bool SetFunctionCalled(TOperator op, const TType &param1, const TType &param2, const TType &param3);
+
+ class FunctionId {
+ public:
+ FunctionId(TOperator op, const TType *param);
+ FunctionId(TOperator op, const TType *param1, const TType *param2);
+ FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3);
+
+ bool operator==(const FunctionId &other) const;
+ bool operator<(const FunctionId &other) const;
+
+ FunctionId getCopy() const;
+ private:
+ TOperator mOp;
+
+ // The memory that these TType objects use is freed by PoolAllocator. The BuiltInFunctionEmulator's lifetime
+ // can extend until after the memory pool is freed, but that's not an issue since this class never destructs
+ // these objects.
+ const TType *mParam1;
+ const TType *mParam2;
+ const TType *mParam3;
+ };
+
+ bool SetFunctionCalled(const FunctionId &functionId);
+
+ // Map from function id to emulated function definition
+ std::map<FunctionId, std::string> mEmulatedFunctions;
+
+ // Called function ids
+ std::vector<FunctionId> mFunctions;
+};
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
new file mode 100644
index 000000000..0c8e2d9cf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -0,0 +1,250 @@
+//
+// 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 "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/Cache.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/VersionGLSL.h"
+
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType)
+{
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ const TType *int1 = TCache::getType(EbtInt);
+ emu->addEmulatedFunction(EOpAbs, int1, "int webgl_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;
+
+ const TType *float1 = TCache::getType(EbtFloat);
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *float3 = TCache::getType(EbtFloat, 3);
+ const TType *float4 = TCache::getType(EbtFloat, 4);
+
+ // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
+ emu->addEmulatedFunction(
+ EOpIsNan, float1,
+ "bool webgl_isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
+ emu->addEmulatedFunction(
+ EOpIsNan, float2,
+ "bvec2 webgl_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(
+ EOpIsNan, float3,
+ "bvec3 webgl_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(
+ EOpIsNan, float4,
+ "bvec4 webgl_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");
+}
+
+// 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)
+ {
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *uint1 = TCache::getType(EbtUInt);
+
+ // clang-format off
+ emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
+ "uint webgl_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(EOpUnpackUnorm2x16, uint1,
+ "vec2 webgl_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)
+ {
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *uint1 = TCache::getType(EbtUInt);
+
+ // clang-format off
+ emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
+ "uint webgl_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(EOpUnpackSnorm2x16, uint1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float webgl_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 webgl_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(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+ " #endif\n"
+ "}\n");
+ // Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
+ // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
+ emu->addEmulatedFunction(EOpPackHalf2x16, float2,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " uint webgl_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 webgl_packHalf2x16_emu(vec2 v)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return packHalf2x16(v);\n"
+ " #else\n"
+ " uint x = webgl_f32tof16(v.x);\n"
+ " uint y = webgl_f32tof16(v.y);\n"
+ " return (y << 16) | x;\n"
+ " #endif\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float webgl_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 webgl_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(webgl_f16tof32(x), webgl_f16tof32(y));\n"
+ " #endif\n"
+ "}\n");
+ // clang-format on
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
new file mode 100644
index 000000000..2bc5f2c88
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -0,0 +1,32 @@
+//
+// 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"
+
+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 function is emulating built-in functions missing from GLSL 1.30 and higher.
+//
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
+ int targetGLSLVersion);
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
new file mode 100644
index 000000000..988f1e2bf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -0,0 +1,494 @@
+//
+// 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 "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/VersionGLSL.h"
+
+void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion)
+{
+ if (targetGLSLVersion < GLSL_VERSION_130)
+ return;
+
+ TType *float1 = new TType(EbtFloat);
+ TType *float2 = new TType(EbtFloat, 2);
+ TType *float3 = new TType(EbtFloat, 3);
+ TType *float4 = new TType(EbtFloat, 4);
+
+ emu->addEmulatedFunction(EOpIsNan, float1,
+ "bool webgl_isnan_emu(float x)\n"
+ "{\n"
+ " return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n"
+ "}\n"
+ "\n");
+
+ emu->addEmulatedFunction(EOpIsNan, float2,
+ "bool2 webgl_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(EOpIsNan, float3,
+ "bool3 webgl_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(EOpIsNan, float4,
+ "bool4 webgl_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)
+{
+ TType *float1 = new TType(EbtFloat);
+ TType *float2 = new TType(EbtFloat, 2);
+ TType *float3 = new TType(EbtFloat, 3);
+ TType *float4 = new TType(EbtFloat, 4);
+
+ emu->addEmulatedFunction(EOpMod, float1, float1,
+ "float webgl_mod_emu(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float2, float2,
+ "float2 webgl_mod_emu(float2 x, float2 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float2, float1,
+ "float2 webgl_mod_emu(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float3, float3,
+ "float3 webgl_mod_emu(float3 x, float3 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float3, float1,
+ "float3 webgl_mod_emu(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float4, float4,
+ "float4 webgl_mod_emu(float4 x, float4 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+ emu->addEmulatedFunction(EOpMod, float4, float1,
+ "float4 webgl_mod_emu(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n");
+
+ emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1,
+ "float webgl_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"
+ "\n");
+ emu->addEmulatedFunction(EOpFaceForward, float2, float2, float2,
+ "float2 webgl_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"
+ "\n");
+ emu->addEmulatedFunction(EOpFaceForward, float3, float3, float3,
+ "float3 webgl_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"
+ "\n");
+ emu->addEmulatedFunction(EOpFaceForward, float4, float4, float4,
+ "float4 webgl_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"
+ "\n");
+
+ emu->addEmulatedFunction(EOpAtan, float1, float1,
+ "float webgl_atan_emu(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
+ " return atan2(y, x);\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAtan, float2, float2,
+ "float2 webgl_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");
+ emu->addEmulatedFunction(EOpAtan, float3, float3,
+ "float3 webgl_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");
+ emu->addEmulatedFunction(EOpAtan, float4, float4,
+ "float4 webgl_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], x[2]), atan2(y[3], x[3]));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpAsinh, float1,
+ "float webgl_asinh_emu(in float x) {\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAsinh, float2,
+ "float2 webgl_asinh_emu(in float2 x) {\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAsinh, float3,
+ "float3 webgl_asinh_emu(in float3 x) {\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAsinh, float4,
+ "float4 webgl_asinh_emu(in float4 x) {\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpAcosh, float1,
+ "float webgl_acosh_emu(in float x) {\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAcosh, float2,
+ "float2 webgl_acosh_emu(in float2 x) {\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAcosh, float3,
+ "float3 webgl_acosh_emu(in float3 x) {\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAcosh, float4,
+ "float4 webgl_acosh_emu(in float4 x) {\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpAtanh, float1,
+ "float webgl_atanh_emu(in float x) {\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAtanh, float2,
+ "float2 webgl_atanh_emu(in float2 x) {\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAtanh, float3,
+ "float3 webgl_atanh_emu(in float3 x) {\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpAtanh, float4,
+ "float4 webgl_atanh_emu(in float4 x) {\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpRoundEven, float1,
+ "float webgl_roundEven_emu(in float x) {\n"
+ " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpRoundEven, float2,
+ "float2 webgl_roundEven_emu(in float2 x) {\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");
+ emu->addEmulatedFunction(EOpRoundEven, float3,
+ "float3 webgl_roundEven_emu(in float3 x) {\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");
+ emu->addEmulatedFunction(EOpRoundEven, float4,
+ "float4 webgl_roundEven_emu(in float4 x) {\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");
+
+ emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
+ "int webgl_toSnorm(in float x) {\n"
+ " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
+ "}\n"
+ "\n"
+ "uint webgl_packSnorm2x16_emu(in float2 v) {\n"
+ " int x = webgl_toSnorm(v.x);\n"
+ " int y = webgl_toSnorm(v.y);\n"
+ " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
+ "uint webgl_toUnorm(in float x) {\n"
+ " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
+ "}\n"
+ "\n"
+ "uint webgl_packUnorm2x16_emu(in float2 v) {\n"
+ " uint x = webgl_toUnorm(v.x);\n"
+ " uint y = webgl_toUnorm(v.y);\n"
+ " return (y << 16) | x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpPackHalf2x16, float2,
+ "uint webgl_packHalf2x16_emu(in float2 v) {\n"
+ " uint x = f32tof16(v.x);\n"
+ " uint y = f32tof16(v.y);\n"
+ " return (y << 16) | x;\n"
+ "}\n");
+
+ TType *uint1 = new TType(EbtUInt);
+
+ emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
+ "float webgl_fromSnorm(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"
+ "\n"
+ "float2 webgl_unpackSnorm2x16_emu(in uint u) {\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u;\n"
+ " return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
+ "float webgl_fromUnorm(in uint x) {\n"
+ " return float(x) / 65535.0;\n"
+ "}\n"
+ "\n"
+ "float2 webgl_unpackUnorm2x16_emu(in uint u) {\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xffffu;\n"
+ " return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
+ "float2 webgl_unpackHalf2x16_emu(in uint u) {\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xffffu;\n"
+ " return float2(f16tof32(x), f16tof32(y));\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.
+ emu->addEmulatedFunction(EOpOuterProduct, float2, float2,
+ "float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n"
+ " return mul(float2x1(r), float1x2(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float3, float3,
+ "float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n"
+ " return mul(float3x1(r), float1x3(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float4, float4,
+ "float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n"
+ " return mul(float4x1(r), float1x4(c));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpOuterProduct, float3, float2,
+ "float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n"
+ " return mul(float2x1(r), float1x3(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float2, float3,
+ "float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n"
+ " return mul(float3x1(r), float1x2(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float4, float2,
+ "float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n"
+ " return mul(float2x1(r), float1x4(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float2, float4,
+ "float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n"
+ " return mul(float4x1(r), float1x2(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float4, float3,
+ "float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n"
+ " return mul(float3x1(r), float1x4(c));\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpOuterProduct, float3, float4,
+ "float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n"
+ " return mul(float4x1(r), float1x3(c));\n"
+ "}\n");
+
+ TType *mat2 = new TType(EbtFloat, 2, 2);
+ TType *mat3 = new TType(EbtFloat, 3, 3);
+ TType *mat4 = new TType(EbtFloat, 4, 4);
+
+ // 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.
+
+ emu->addEmulatedFunction(EOpInverse, mat2,
+ "float2x2 webgl_inverse_emu(in float2x2 m) {\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.
+
+ emu->addEmulatedFunction(EOpInverse, mat3,
+ "float3x3 webgl_inverse_emu(in float3x3 m) {\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");
+
+ emu->addEmulatedFunction(EOpInverse, mat4,
+ "float4x4 webgl_inverse_emu(in float4x4 m) {\n"
+ " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3]"
+ " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * 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] * m[1][2] * m[2][3]"
+ " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * 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] * m[1][1] * m[2][3]"
+ " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * 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] * m[1][1] * m[2][2]"
+ " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * 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] * m[0][2] * m[2][3]"
+ " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * 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] * m[0][2] * m[2][3]"
+ " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * 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] * m[0][1] * m[2][3]"
+ " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * 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] * m[0][1] * m[2][2]"
+ " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * 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] * m[0][2] * m[1][3]"
+ " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * 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] * m[0][2] * m[1][3]"
+ " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * 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] * m[0][1] * m[1][3]"
+ " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * 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] * m[0][1] * m[1][2]"
+ " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * 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] * m[0][2] * m[1][3]"
+ " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * 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] * m[0][2] * m[1][3]"
+ " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * 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] * m[0][1] * m[1][3]"
+ " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * 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] * m[0][1] * m[1][2]"
+ " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * m[0][2];\n"
+ " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,"
+ " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n"
+ " return cof / determinant(transpose(m));\n"
+ "}\n");
+
+ TType *bool1 = new TType(EbtBool);
+ TType *bool2 = new TType(EbtBool, 2);
+ TType *bool3 = new TType(EbtBool, 3);
+ TType *bool4 = new TType(EbtBool, 4);
+
+ // 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.
+ emu->addEmulatedFunction(EOpMix, float1, float1, bool1,
+ "float webgl_mix_emu(float x, float y, bool a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float2, float2, bool2,
+ "float2 webgl_mix_emu(float2 x, float2 y, bool2 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float3, float3, bool3,
+ "float3 webgl_mix_emu(float3 x, float3 y, bool3 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float4, float4, bool4,
+ "float4 webgl_mix_emu(float4 x, float4 y, bool4 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
new file mode 100644
index 000000000..f47449dfb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/BuiltInFunctionEmulatorHLSL.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.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+class BuiltInFunctionEmulator;
+
+void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu);
+
+//
+// This works around isnan() bug on some Intel drivers.
+//
+void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion);
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.cpp
new file mode 100644
index 000000000..57a43700c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.cpp
@@ -0,0 +1,100 @@
+//
+// 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.
+//
+
+// Cache.cpp: Implements a cache for various commonly created objects.
+
+#include <limits>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "compiler/translator/Cache.h"
+
+namespace
+{
+
+class TScopedAllocator : angle::NonCopyable
+{
+ public:
+ TScopedAllocator(TPoolAllocator *allocator)
+ : mPreviousAllocator(GetGlobalPoolAllocator())
+ {
+ SetGlobalPoolAllocator(allocator);
+ }
+ ~TScopedAllocator()
+ {
+ SetGlobalPoolAllocator(mPreviousAllocator);
+ }
+
+ private:
+ TPoolAllocator *mPreviousAllocator;
+};
+
+} // namespace
+
+TCache::TypeKey::TypeKey(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize)
+{
+ static_assert(sizeof(components) <= sizeof(value),
+ "TypeKey::value is too small");
+
+ const size_t MaxEnumValue = std::numeric_limits<EnumComponentType>::max();
+ UNUSED_ASSERTION_VARIABLE(MaxEnumValue);
+
+ // TODO: change to static_assert() once we deprecate MSVC 2013 support
+ ASSERT(MaxEnumValue >= EbtLast &&
+ MaxEnumValue >= EbpLast &&
+ MaxEnumValue >= EvqLast &&
+ "TypeKey::EnumComponentType is too small");
+
+ value = 0;
+ components.basicType = static_cast<EnumComponentType>(basicType);
+ components.precision = static_cast<EnumComponentType>(precision);
+ components.qualifier = static_cast<EnumComponentType>(qualifier);
+ components.primarySize = primarySize;
+ components.secondarySize = secondarySize;
+}
+
+TCache *TCache::sCache = nullptr;
+
+void TCache::initialize()
+{
+ if (sCache == nullptr)
+ {
+ sCache = new TCache();
+ }
+}
+
+void TCache::destroy()
+{
+ SafeDelete(sCache);
+}
+
+const TType *TCache::getType(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize)
+{
+ TypeKey key(basicType, precision, qualifier,
+ primarySize, secondarySize);
+ auto it = sCache->mTypes.find(key);
+ if (it != sCache->mTypes.end())
+ {
+ return it->second;
+ }
+
+ TScopedAllocator scopedAllocator(&sCache->mAllocator);
+
+ TType *type = new TType(basicType, precision, qualifier,
+ primarySize, secondarySize);
+ type->realize();
+ sCache->mTypes.insert(std::make_pair(key, type));
+
+ return type;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.h
new file mode 100644
index 000000000..1d2abb77e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Cache.h
@@ -0,0 +1,90 @@
+//
+// 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.
+//
+
+// Cache.h: Implements a cache for various commonly created objects.
+
+#ifndef COMPILER_TRANSLATOR_CACHE_H_
+#define COMPILER_TRANSLATOR_CACHE_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <map>
+
+#include "compiler/translator/Types.h"
+#include "compiler/translator/PoolAlloc.h"
+
+class TCache
+{
+ public:
+
+ static void initialize();
+ static void destroy();
+
+ static const TType *getType(TBasicType basicType,
+ TPrecision precision)
+ {
+ return getType(basicType, precision, EvqTemporary,
+ 1, 1);
+ }
+ static const TType *getType(TBasicType basicType,
+ unsigned char primarySize = 1,
+ unsigned char secondarySize = 1)
+ {
+ return getType(basicType, EbpUndefined, EvqGlobal,
+ primarySize, secondarySize);
+ }
+ static const TType *getType(TBasicType basicType,
+ TQualifier qualifier,
+ unsigned char primarySize = 1,
+ unsigned char secondarySize = 1)
+ {
+ return getType(basicType, EbpUndefined, qualifier,
+ primarySize, secondarySize);
+ }
+ static const TType *getType(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize);
+
+ private:
+ TCache()
+ {
+ }
+
+ union TypeKey
+ {
+ TypeKey(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize);
+
+ typedef uint8_t EnumComponentType;
+ struct
+ {
+ EnumComponentType basicType;
+ EnumComponentType precision;
+ EnumComponentType qualifier;
+ unsigned char primarySize;
+ unsigned char secondarySize;
+ } components;
+ uint64_t value;
+
+ bool operator < (const TypeKey &other) const
+ {
+ return value < other.value;
+ }
+ };
+ typedef std::map<TypeKey, const TType*> TypeMap;
+
+ TypeMap mTypes;
+ TPoolAllocator mAllocator;
+
+ static TCache *sCache;
+};
+
+#endif // COMPILER_TRANSLATOR_CACHE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.cpp
new file mode 100644
index 000000000..9810fa935
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.cpp
@@ -0,0 +1,343 @@
+//
+// 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/InfoSink.h"
+
+// 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(TInfoSinkBase *info)
+ : TIntermTraverser(true, false, true),
+ mCreationInfo(info),
+ mCurrentFunction(nullptr),
+ mCurrentIndex(0)
+ {
+ }
+
+ InitResult assignIndices()
+ {
+ int skipped = 0;
+ for (auto &it : mFunctions)
+ {
+ // Skip unimplemented functions
+ if (it.second.node)
+ {
+ InitResult result = assignIndicesInternal(&it.second);
+ if (result != INITDAG_SUCCESS)
+ {
+ *mCreationInfo << "\n";
+ 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.node)
+ {
+ continue;
+ }
+ ASSERT(data.index < records->size());
+ Record &record = (*records)[data.index];
+
+ record.name = data.name.data();
+ record.node = data.node;
+
+ record.callees.reserve(data.callees.size());
+ for (auto &callee : data.callees)
+ {
+ record.callees.push_back(static_cast<int>(callee->index));
+ }
+
+ (*idToIndex)[data.node->getFunctionSymbolInfo()->getId()] =
+ static_cast<int>(data.index);
+ }
+ }
+
+ private:
+
+ struct CreatorFunctionData
+ {
+ CreatorFunctionData()
+ : node(nullptr),
+ index(0),
+ indexAssigned(false),
+ visiting(false)
+ {
+ }
+
+ std::set<CreatorFunctionData*> callees;
+ TIntermFunctionDefinition *node;
+ TString name;
+ size_t index;
+ bool indexAssigned;
+ bool visiting;
+ };
+
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
+ {
+ // Create the record if need be and remember the node.
+ if (visit == PreVisit)
+ {
+ auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
+
+ if (it == mFunctions.end())
+ {
+ mCurrentFunction = &mFunctions[node->getFunctionSymbolInfo()->getName()];
+ }
+ else
+ {
+ mCurrentFunction = &it->second;
+ }
+
+ mCurrentFunction->node = node;
+ mCurrentFunction->name = node->getFunctionSymbolInfo()->getName();
+ }
+ else if (visit == PostVisit)
+ {
+ mCurrentFunction = nullptr;
+ }
+ return true;
+ }
+
+ // Aggregates the AST node for each function as well as the name of the functions called by it
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ // Function declaration, create an empty record.
+ auto &record = mFunctions[node->getFunctionSymbolInfo()->getName()];
+ record.name = node->getFunctionSymbolInfo()->getName();
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ // Function call, add the callees
+ if (visit == PreVisit)
+ {
+ // Do not handle calls to builtin functions
+ if (node->isUserDefined())
+ {
+ auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
+ ASSERT(it != mFunctions.end());
+
+ // We might be in a top-level function call to set a global variable
+ if (mCurrentFunction)
+ {
+ mCurrentFunction->callees.insert(&it->second);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ 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;
+
+ 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->node)
+ {
+ *mCreationInfo << "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)
+ {
+ *mCreationInfo << "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)
+ {
+ *mCreationInfo << " -> ";
+ }
+ *mCreationInfo << function->name << ")";
+ first = false;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ TInfoSinkBase *mCreationInfo;
+
+ std::map<TString, 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 TFunctionSymbolInfo *functionInfo) const
+{
+ auto it = mFunctionIdToIndex.find(functionInfo->getId());
+
+ 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];
+}
+
+const CallDAG::Record &CallDAG::getRecord(const TIntermAggregate *function) const
+{
+ size_t index = findIndex(function->getFunctionSymbolInfo());
+ 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, TInfoSinkBase *info)
+{
+ ASSERT(info);
+
+ CallDAGCreator creator(info);
+
+ // 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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.h b/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.h
new file mode 100644
index 000000000..9bcda070c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/CallDAG.h
@@ -0,0 +1,75 @@
+//
+// 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"
+#include "compiler/translator/VariableInfo.h"
+
+
+// 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 function.
+// Records are accessed by index but a mangled function name can be converted
+// to the index of the corresponding record. The records mostly contain the
+// AST node of the function 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
+ {
+ std::string name;
+ TIntermFunctionDefinition *node;
+ 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 info, if present.
+ InitResult init(TIntermNode *root, TInfoSinkBase *info);
+
+ // Returns InvalidIndex if the function wasn't found
+ size_t findIndex(const TFunctionSymbolInfo *functionInfo) const;
+
+ const Record &getRecordFromIndex(size_t index) const;
+ const Record &getRecord(const TIntermAggregate *function) const;
+ size_t size() const;
+ void clear();
+
+ const static size_t InvalidIndex;
+ private:
+ std::vector<Record> mRecords;
+ std::map<int, int> mFunctionIdToIndex;
+
+ class CallDAGCreator;
+};
+
+#endif // COMPILER_TRANSLATOR_CALLDAG_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp
new file mode 100644
index 000000000..f099bccf1
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.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.
+//
+
+#ifdef ANGLE_ENABLE_ESSL
+#include "compiler/translator/TranslatorESSL.h"
+#endif
+
+#ifdef ANGLE_ENABLE_GLSL
+#include "compiler/translator/TranslatorGLSL.h"
+#endif
+
+#ifdef ANGLE_ENABLE_HLSL
+#include "compiler/translator/TranslatorHLSL.h"
+#endif // ANGLE_ENABLE_HLSL
+
+//
+// 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)
+{
+ switch (output) {
+ case SH_ESSL_OUTPUT:
+#ifdef ANGLE_ENABLE_ESSL
+ return new TranslatorESSL(type, spec);
+#else
+ // This compiler is not supported in this
+ // configuration. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+#endif // ANGLE_ENABLE_ESSL
+ 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:
+#ifdef ANGLE_ENABLE_GLSL
+ return new TranslatorGLSL(type, spec, output);
+#else
+ // This compiler is not supported in this
+ // configuration. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+#endif // ANGLE_ENABLE_GLSL
+ case SH_HLSL_3_0_OUTPUT:
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_HLSL_4_0_FL9_3_OUTPUT:
+#ifdef ANGLE_ENABLE_HLSL
+ return new TranslatorHLSL(type, spec, output);
+#else
+ // This compiler is not supported in this
+ // configuration. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+#endif // ANGLE_ENABLE_HLSL
+ default:
+ // Unknown format. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Common.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Common.h
index 46f9440ff..60223232a 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/Common.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Common.h
@@ -4,15 +4,19 @@
// found in the LICENSE file.
//
-#ifndef _COMMON_INCLUDED_
-#define _COMMON_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_COMMON_H_
+#define COMPILER_TRANSLATOR_COMMON_H_
#include <map>
#include <sstream>
#include <string>
#include <vector>
+#include <limits>
+#include <stdio.h>
-#include "compiler/PoolAlloc.h"
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "compiler/translator/PoolAlloc.h"
struct TSourceLoc {
int first_file;
@@ -56,22 +60,36 @@ inline TString* NewPoolTString(const char* s)
//
// Pool allocator versions of vectors, lists, and maps
//
-template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
-public:
- 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 T>
+class TVector : public std::vector<T, pool_allocator<T>>
+{
+ public:
+ 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 CMP = std::less<K> >
-class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
-public:
- typedef pool_allocator<std::pair<const K, D> > tAllocator;
+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:
+ 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) {}
};
-#endif // _COMMON_INCLUDED_
+// 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;
+}
+
+#endif // COMPILER_TRANSLATOR_COMMON_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp
new file mode 100644
index 000000000..eb5dd585c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp
@@ -0,0 +1,979 @@
+//
+// 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/AddAndTrueToLoopCondition.h"
+#include "compiler/translator/Cache.h"
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/DeferGlobalInitializers.h"
+#include "compiler/translator/EmulateGLFragColorBroadcast.h"
+#include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/ForLoopUnroll.h"
+#include "compiler/translator/Initialize.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/PruneEmptyDeclarations.h"
+#include "compiler/translator/RegenerateStructNames.h"
+#include "compiler/translator/RemovePow.h"
+#include "compiler/translator/RewriteDoWhile.h"
+#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
+#include "compiler/translator/UnfoldShortCircuitAST.h"
+#include "compiler/translator/UseInterfaceBlockFields.h"
+#include "compiler/translator/ValidateLimitations.h"
+#include "compiler/translator/ValidateMaxParameters.h"
+#include "compiler/translator/ValidateOutputs.h"
+#include "compiler/translator/VariablePacker.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+namespace
+{
+
+#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+void DumpFuzzerCase(char const *const *shaderStrings,
+ size_t numStrings,
+ uint32_t type,
+ uint32_t spec,
+ uint32_t output,
+ uint64_t options)
+{
+ static int fileIndex = 0;
+
+ std::ostringstream o;
+ o << "corpus/" << fileIndex++ << ".sample";
+ std::string s = o.str();
+
+ // Must match the input format of the fuzzer
+ FILE *f = fopen(s.c_str(), "w");
+ fwrite(&type, sizeof(type), 1, f);
+ fwrite(&spec, sizeof(spec), 1, f);
+ fwrite(&output, sizeof(output), 1, f);
+ fwrite(&options, sizeof(options), 1, f);
+
+ char zero[128 - 20] = {0};
+ fwrite(&zero, 128 - 20, 1, f);
+
+ for (size_t i = 0; i < numStrings; i++)
+ {
+ fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f);
+ }
+ fwrite(&zero, 1, 1, f);
+
+ fclose(f);
+}
+#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+} // anonymous namespace
+
+bool IsWebGLBasedSpec(ShShaderSpec spec)
+{
+ return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
+}
+
+bool IsGLSL130OrNewer(ShShaderOutput output)
+{
+ return (output == SH_GLSL_130_OUTPUT ||
+ output == SH_GLSL_140_OUTPUT ||
+ output == SH_GLSL_150_CORE_OUTPUT ||
+ output == SH_GLSL_330_CORE_OUTPUT ||
+ output == SH_GLSL_400_CORE_OUTPUT ||
+ output == SH_GLSL_410_CORE_OUTPUT ||
+ output == SH_GLSL_420_CORE_OUTPUT ||
+ output == SH_GLSL_430_CORE_OUTPUT ||
+ output == SH_GLSL_440_CORE_OUTPUT ||
+ output == SH_GLSL_450_CORE_OUTPUT);
+}
+
+size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
+{
+ // WebGL defines a max token legnth 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;
+ }
+}
+
+namespace {
+
+class TScopedPoolAllocator
+{
+ public:
+ TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
+ {
+ mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator()
+ {
+ SetGlobalPoolAllocator(NULL);
+ mAllocator->pop();
+ }
+
+ private:
+ TPoolAllocator* mAllocator;
+};
+
+class TScopedSymbolTableLevel
+{
+ public:
+ TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
+ {
+ ASSERT(mTable->atBuiltInLevel());
+ mTable->push();
+ }
+ ~TScopedSymbolTableLevel()
+ {
+ while (!mTable->atBuiltInLevel())
+ 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;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+} // namespace
+
+TShHandleBase::TShHandleBase()
+{
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase()
+{
+ SetGlobalPoolAllocator(NULL);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : variablesCollected(false),
+ shaderType(type),
+ shaderSpec(spec),
+ outputType(output),
+ maxUniformVectors(0),
+ maxExpressionComplexity(0),
+ maxCallStackDepth(0),
+ maxFunctionParameters(0),
+ fragmentPrecisionHigh(false),
+ clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
+ builtInFunctionEmulator(),
+ mSourcePath(NULL),
+ mComputeShaderLocalSizeDeclared(false),
+ mTemporaryIndex(0)
+{
+ mComputeShaderLocalSize.fill(1);
+}
+
+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(shaderSpec) && shaderVersion == 100) ||
+ (compileOptions & SH_VALIDATE_LOOP_INDEXING);
+}
+
+bool TCompiler::Init(const ShBuiltInResources& resources)
+{
+ shaderVersion = 100;
+ maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
+ resources.MaxVertexUniformVectors :
+ resources.MaxFragmentUniformVectors;
+ maxExpressionComplexity = resources.MaxExpressionComplexity;
+ maxCallStackDepth = resources.MaxCallStackDepth;
+ maxFunctionParameters = resources.MaxFunctionParameters;
+
+ SetGlobalPoolAllocator(&allocator);
+
+ // Generate built-in symbol table.
+ if (!InitBuiltInSymbolTable(resources))
+ return false;
+ InitExtensionBehavior(resources, extensionBehavior);
+ fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
+
+ arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
+ clampingStrategy = resources.ArrayIndexClampingStrategy;
+
+ hashFunction = resources.HashFunction;
+
+ 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(extensionBehavior);
+
+ // 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(symbolTable, extensionBehavior, shaderType, shaderSpec,
+ compileOptions, true, infoSink, getResources());
+
+ parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
+ SetGlobalParseContext(&parseContext);
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
+
+ // Parse shader.
+ bool success =
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
+ (parseContext.getTreeRoot() != nullptr);
+
+ shaderVersion = parseContext.getShaderVersion();
+ if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "unsupported shader version";
+ success = false;
+ }
+
+ TIntermBlock *root = nullptr;
+
+ if (success)
+ {
+ mPragma = parseContext.pragma();
+ symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
+
+ mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
+ mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
+
+ root = parseContext.getTreeRoot();
+
+ // Highp might have been auto-enabled based on shader version
+ fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
+
+ // Disallow expressions deemed too complex.
+ if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
+ success = limitExpressionComplexity(root);
+
+ // Create the function DAG and check there is no recursion
+ if (success)
+ success = initCallDag(root);
+
+ if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH))
+ success = checkCallDepth();
+
+ // Checks which functions are used and if "main" exists
+ if (success)
+ {
+ functionMetadata.clear();
+ functionMetadata.resize(mCallDag.size());
+ success = tagUsedFunctions();
+ }
+
+ if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
+ success = pruneUnusedFunctions(root);
+
+ // Prune empty declarations to work around driver bugs and to keep declaration output simple.
+ if (success)
+ PruneEmptyDeclarations(root);
+
+ if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
+ success = validateOutputs(root);
+
+ if (success && shouldRunLoopAndIndexingValidation(compileOptions))
+ success = validateLimitations(root);
+
+ // Fail compilation if precision emulation not supported.
+ if (success && getResources().WEBGL_debug_shader_precision &&
+ getPragma().debugShaderPrecision)
+ {
+ if (!EmulatePrecision::SupportedInLanguage(outputType))
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Precision emulation not supported for this output type.";
+ success = false;
+ }
+ }
+
+ // Unroll for-loop markup needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
+ {
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex,
+ shouldRunLoopAndIndexingValidation(compileOptions));
+ root->traverse(&marker);
+ }
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
+ {
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex,
+ shouldRunLoopAndIndexingValidation(compileOptions));
+ root->traverse(&marker);
+ if (marker.samplerArrayIndexIsFloatLoopIndex())
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "sampler array index is float loop index";
+ success = false;
+ }
+ }
+
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ if (success)
+ {
+ // TODO(jmadill): Remove global pool allocator.
+ GetGlobalPoolAllocator()->lock();
+ initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
+ GetGlobalPoolAllocator()->unlock();
+ builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+ }
+
+ // Clamping uniform array bounds needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
+ arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+
+ // gl_Position is always written in compatibility output mode
+ if (success && shaderType == GL_VERTEX_SHADER &&
+ ((compileOptions & SH_INIT_GL_POSITION) ||
+ (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
+ initializeGLPosition(root);
+
+ // This pass might emit short circuits so keep it before the short circuit unfolding
+ if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
+ RewriteDoWhile(root, getTemporaryIndex());
+
+ if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION))
+ sh::AddAndTrueToLoopCondition(root);
+
+ if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
+ {
+ UnfoldShortCircuitAST unfoldShortCircuit;
+ root->traverse(&unfoldShortCircuit);
+ unfoldShortCircuit.updateTree();
+ }
+
+ if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT))
+ {
+ RemovePow(root);
+ }
+
+ if (success && shouldCollectVariables(compileOptions))
+ {
+ collectVariables(root);
+ if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
+ {
+ useAllMembersInUnusedStandardAndSharedBlocks(root);
+ }
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
+ {
+ success = enforcePackingRestrictions();
+ if (!success)
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "too many uniforms";
+ }
+ }
+ if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES))
+ {
+ initializeOutputVariables(root);
+ }
+ }
+
+ if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
+ {
+ ScalarizeVecAndMatConstructorArgs scalarizer(
+ shaderType, fragmentPrecisionHigh);
+ root->traverse(&scalarizer);
+ }
+
+ if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
+ {
+ RegenerateStructNames gen(symbolTable, shaderVersion);
+ root->traverse(&gen);
+ }
+
+ if (success && shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 &&
+ compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 &&
+ IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers"))
+ {
+ EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables);
+ }
+
+ if (success)
+ {
+ DeferGlobalInitializers(root);
+ }
+ }
+
+ SetGlobalParseContext(NULL);
+ if (success)
+ return root;
+
+ return NULL;
+}
+
+bool TCompiler::compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptionsIn)
+{
+#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+ DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn);
+#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+
+ if (numStrings == 0)
+ return true;
+
+ ShCompileOptions compileOptions = compileOptionsIn;
+
+ // Apply key workarounds.
+ if (shouldFlattenPragmaStdglInvariantAll())
+ {
+ // This should be harmless to do in all cases, but for the moment, do it only conditionally.
+ compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
+ }
+
+ ShCompileOptions unrollFlags =
+ SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
+ if ((compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) != 0 &&
+ (compileOptions & unrollFlags) != 0)
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info
+ << "Unsupported compile flag combination: unroll & ADD_TRUE_TO_LOOP_CONDITION";
+ return false;
+ }
+
+ TScopedPoolAllocator scopedAlloc(&allocator);
+ TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
+
+ if (root)
+ {
+ if (compileOptions & SH_INTERMEDIATE_TREE)
+ TIntermediate::outputTree(root, infoSink.info);
+
+ if (compileOptions & SH_OBJECT_CODE)
+ translate(root, compileOptions);
+
+ // 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)
+{
+ compileResources = resources;
+ setResourceString();
+
+ assert(symbolTable.isEmpty());
+ symbolTable.push(); // COMMON_BUILTINS
+ symbolTable.push(); // ESSL1_BUILTINS
+ symbolTable.push(); // ESSL3_BUILTINS
+ symbolTable.push(); // ESSL3_1_BUILTINS
+
+ TPublicType integer;
+ integer.setBasicType(EbtInt);
+ integer.initializeSizeForScalarTypes();
+ integer.array = false;
+
+ TPublicType floatingPoint;
+ floatingPoint.setBasicType(EbtFloat);
+ floatingPoint.initializeSizeForScalarTypes();
+ floatingPoint.array = false;
+
+ switch(shaderType)
+ {
+ case GL_FRAGMENT_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpMedium);
+ break;
+ case GL_VERTEX_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpHigh);
+ symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
+ break;
+ case GL_COMPUTE_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpHigh);
+ symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
+ break;
+ default:
+ assert(false && "Language not supported");
+ }
+ // 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);
+ // It isn't specified whether Sampler2DRect has default precision.
+ initSamplerDefaultPrecision(EbtSampler2DRect);
+
+ InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
+
+ IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
+
+ return true;
+}
+
+void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
+{
+ ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
+ TPublicType sampler;
+ sampler.initializeSizeForScalarTypes();
+ sampler.setBasicType(samplerType);
+ sampler.array = false;
+ symbolTable.setDefaultPrecision(sampler, EbpLow);
+}
+
+void TCompiler::setResourceString()
+{
+ std::ostringstream strstream;
+
+ // clang-format off
+ strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
+ << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
+ << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
+ << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
+ << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
+ << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
+ << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
+ << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
+ << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
+ << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
+ << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3
+ << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external
+ << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
+ << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
+ << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
+ << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
+ << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
+ << ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
+ << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
+ << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
+ << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
+ << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
+ << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
+ << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
+ << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
+ << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
+ << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
+ << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+ << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
+ << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
+ << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
+ << ":MaxImageUnits:" << compileResources.MaxImageUnits
+ << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
+ << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
+ << ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms
+ << ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms
+ << ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources
+ << ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0]
+ << ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1]
+ << ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2]
+ << ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0]
+ << ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1]
+ << ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2]
+ << ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents
+ << ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits
+ << ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters
+ << ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers
+ << ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters
+ << ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters
+ << ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters
+ << ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings
+ << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
+ << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
+ << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
+ << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize;
+ // clang-format on
+
+ builtInResourcesString = strstream.str();
+}
+
+void TCompiler::clearResults()
+{
+ arrayBoundsClamper.Cleanup();
+ infoSink.info.erase();
+ infoSink.obj.erase();
+ infoSink.debug.erase();
+
+ attributes.clear();
+ outputVariables.clear();
+ uniforms.clear();
+ expandedUniforms.clear();
+ varyings.clear();
+ interfaceBlocks.clear();
+ variablesCollected = false;
+
+ builtInFunctionEmulator.Cleanup();
+
+ nameMap.clear();
+
+ mSourcePath = NULL;
+ mTemporaryIndex = 0;
+}
+
+bool TCompiler::initCallDag(TIntermNode *root)
+{
+ mCallDag.clear();
+
+ switch (mCallDag.init(root, &infoSink.info))
+ {
+ case CallDAG::INITDAG_SUCCESS:
+ return true;
+ case CallDAG::INITDAG_RECURSION:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function recursion detected";
+ return false;
+ case CallDAG::INITDAG_UNDEFINED:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Unimplemented function detected";
+ return false;
+ }
+
+ UNREACHABLE();
+ return true;
+}
+
+bool TCompiler::checkCallDepth()
+{
+ std::vector<int> depths(mCallDag.size());
+
+ for (size_t i = 0; i < mCallDag.size(); i++)
+ {
+ int depth = 0;
+ auto &record = mCallDag.getRecordFromIndex(i);
+
+ for (auto &calleeIndex : record.callees)
+ {
+ depth = std::max(depth, depths[calleeIndex] + 1);
+ }
+
+ depths[i] = depth;
+
+ if (depth >= maxCallStackDepth)
+ {
+ // Trace back the function chain to have a meaningful info log.
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
+ << ") with the following call chain: " << record.name;
+
+ int currentFunction = static_cast<int>(i);
+ int currentDepth = depth;
+
+ while (currentFunction != -1)
+ {
+ infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
+
+ int nextFunction = -1;
+ for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
+ {
+ if (depths[calleeIndex] == currentDepth - 1)
+ {
+ currentDepth--;
+ nextFunction = calleeIndex;
+ }
+ }
+
+ currentFunction = nextFunction;
+ }
+
+ 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).name == "main(")
+ {
+ internalTagUsedFunction(i);
+ return true;
+ }
+ }
+
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Missing main()\n";
+ return false;
+}
+
+void TCompiler::internalTagUsedFunction(size_t index)
+{
+ if (functionMetadata[index].used)
+ {
+ return;
+ }
+
+ functionMetadata[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 TIntermAggregate *asAggregate = node->getAsAggregate();
+ const TIntermFunctionDefinition *asFunction = node->getAsFunctionDefinition();
+
+ const TFunctionSymbolInfo *functionInfo = nullptr;
+
+ if (asFunction)
+ {
+ functionInfo = asFunction->getFunctionSymbolInfo();
+ }
+ else if (asAggregate)
+ {
+ if (asAggregate->getOp() == EOpPrototype)
+ {
+ functionInfo = asAggregate->getFunctionSymbolInfo();
+ }
+ }
+ if (functionInfo == nullptr)
+ {
+ return false;
+ }
+
+ size_t callDagIndex = mCallDag->findIndex(functionInfo);
+ if (callDagIndex == CallDAG::InvalidIndex)
+ {
+ // This happens only for unimplemented prototypes which are thus unused
+ ASSERT(asAggregate && asAggregate->getOp() == EOpPrototype);
+ return true;
+ }
+
+ ASSERT(callDagIndex < mMetadatas->size());
+ return !(*mMetadatas)[callDagIndex].used;
+ }
+
+ private:
+ const CallDAG *mCallDag;
+ const std::vector<FunctionMetadata> *mMetadatas;
+};
+
+bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
+{
+ UnusedPredicate isUnused(&mCallDag, &functionMetadata);
+ TIntermSequence *sequence = root->getSequence();
+
+ if (!sequence->empty())
+ {
+ sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
+ }
+
+ return true;
+}
+
+bool TCompiler::validateOutputs(TIntermNode* root)
+{
+ ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
+ root->traverse(&validateOutputs);
+ return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
+}
+
+bool TCompiler::validateLimitations(TIntermNode* root)
+{
+ ValidateLimitations validate(shaderType, &infoSink.info);
+ root->traverse(&validate);
+ return validate.numErrors() == 0;
+}
+
+bool TCompiler::limitExpressionComplexity(TIntermNode* root)
+{
+ TMaxDepthTraverser traverser(maxExpressionComplexity+1);
+ root->traverse(&traverser);
+
+ if (traverser.getMaxDepth() > maxExpressionComplexity)
+ {
+ infoSink.info << "Expression too complex.";
+ return false;
+ }
+
+ if (!ValidateMaxParameters::validate(root, maxFunctionParameters))
+ {
+ infoSink.info << "Function has too many parameters.";
+ return false;
+ }
+
+ return true;
+}
+
+void TCompiler::collectVariables(TIntermNode* root)
+{
+ if (!variablesCollected)
+ {
+ sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings,
+ &interfaceBlocks, hashFunction, symbolTable, extensionBehavior);
+ root->traverse(&collect);
+
+ // This is for enforcePackingRestriction().
+ sh::ExpandUniforms(uniforms, &expandedUniforms);
+ variablesCollected = true;
+ }
+}
+
+bool TCompiler::enforcePackingRestrictions()
+{
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
+}
+
+void TCompiler::initializeGLPosition(TIntermNode* root)
+{
+ InitVariableList list;
+ sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
+ var.name = "gl_Position";
+ list.push_back(var);
+ InitializeVariables(root, list);
+}
+
+void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
+{
+ sh::InterfaceBlockList list;
+
+ for (auto block : interfaceBlocks)
+ {
+ if (!block.staticUse &&
+ (block.layout == sh::BLOCKLAYOUT_STANDARD || block.layout == sh::BLOCKLAYOUT_SHARED))
+ {
+ list.push_back(block);
+ }
+ }
+
+ sh::UseInterfaceBlockFields(root, list);
+}
+
+void TCompiler::initializeOutputVariables(TIntermNode *root)
+{
+ InitVariableList list;
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ for (auto var : varyings)
+ {
+ list.push_back(var);
+ }
+ }
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ for (auto var : outputVariables)
+ {
+ list.push_back(var);
+ }
+ }
+ InitializeVariables(root, list);
+}
+
+const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+{
+ return extensionBehavior;
+}
+
+const char *TCompiler::getSourcePath() const
+{
+ return mSourcePath;
+}
+
+const ShBuiltInResources& TCompiler::getResources() const
+{
+ return compileResources;
+}
+
+const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
+{
+ return arrayBoundsClamper;
+}
+
+ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
+{
+ return clampingStrategy;
+}
+
+const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+{
+ return builtInFunctionEmulator;
+}
+
+void TCompiler::writePragma(ShCompileOptions compileOptions)
+{
+ if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
+ {
+ TInfoSinkBase &sink = infoSink.obj;
+ if (mPragma.stdgl.invariantAll)
+ sink << "#pragma STDGL invariant(all)\n";
+ }
+}
+
+bool TCompiler::isVaryingDefined(const char *varyingName)
+{
+ ASSERT(variablesCollected);
+ for (size_t ii = 0; ii < varyings.size(); ++ii)
+ {
+ if (varyings[ii].name == varyingName)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h
new file mode 100644
index 000000000..823832bcb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h
@@ -0,0 +1,260 @@
+//
+// 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 "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/CallDAG.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/VariableInfo.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+class TCompiler;
+#ifdef ANGLE_ENABLE_HLSL
+class TranslatorHLSL;
+#endif // ANGLE_ENABLE_HLSL
+
+//
+// Helper function to identify specs that are based on the WebGL spec.
+//
+bool IsWebGLBasedSpec(ShShaderSpec spec);
+
+//
+// Helper function to check if the shader type is GLSL.
+//
+bool IsGLSL130OrNewer(ShShaderOutput output);
+
+//
+// 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.
+ TPoolAllocator 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 shaderVersion; }
+ TInfoSink& getInfoSink() { return infoSink; }
+
+ bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
+ const sh::WorkGroupSize &getComputeShaderLocalSize() { return mComputeShaderLocalSize; }
+
+ // Clears the results from the previous compilation.
+ void clearResults();
+
+ const std::vector<sh::Attribute> &getAttributes() const { return attributes; }
+ const std::vector<sh::OutputVariable> &getOutputVariables() const { return outputVariables; }
+ const std::vector<sh::Uniform> &getUniforms() const { return uniforms; }
+ const std::vector<sh::Varying> &getVaryings() const { return varyings; }
+ const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return interfaceBlocks; }
+
+ ShHashFunction64 getHashFunction() const { return hashFunction; }
+ NameMap& getNameMap() { return nameMap; }
+ TSymbolTable& getSymbolTable() { return symbolTable; }
+ ShShaderSpec getShaderSpec() const { return shaderSpec; }
+ ShShaderOutput getOutputType() const { return outputType; }
+ const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
+
+ bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
+
+ // Get the resources set by InitBuiltInSymbolTable
+ const ShBuiltInResources& getResources() const;
+
+ protected:
+ sh::GLenum getShaderType() const { return shaderType; }
+ // 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();
+ // Returns true if a program has no conflicting or missing fragment outputs
+ bool validateOutputs(TIntermNode* root);
+ // Returns true if the given shader does not exceed the minimum
+ // functionality mandated in GLSL 1.0 spec Appendix A.
+ bool validateLimitations(TIntermNode* root);
+ // Collect info for all attribs, uniforms, varyings.
+ void collectVariables(TIntermNode* root);
+ // Add emulated functions to the built-in function emulator.
+ virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions){};
+ // Translate to object code.
+ virtual void translate(TIntermNode *root, ShCompileOptions compileOptions) = 0;
+ // Returns true if, after applying the packing rules in the GLSL 1.017 spec
+ // Appendix A, section 7, the shader does not use too many uniforms.
+ bool enforcePackingRestrictions();
+ // 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(TIntermNode *root);
+ // Insert statements to initialize output variables in the beginning of main().
+ // This is to avoid undefined behaviors.
+ void initializeOutputVariables(TIntermNode *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(TIntermNode* root);
+ // Return true if the maximum expression complexity is below the limit.
+ bool limitExpressionComplexity(TIntermNode* root);
+ // 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);
+ unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
+ // Relies on collectVariables having been called.
+ bool isVaryingDefined(const char *varyingName);
+
+ const ArrayBoundsClamper& getArrayBoundsClamper() const;
+ ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
+ const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+
+ virtual bool shouldCollectVariables(ShCompileOptions compileOptions)
+ {
+ return (compileOptions & SH_VARIABLES) != 0;
+ }
+
+ virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
+
+ std::vector<sh::Attribute> attributes;
+ std::vector<sh::OutputVariable> outputVariables;
+ std::vector<sh::Uniform> uniforms;
+ std::vector<sh::ShaderVariable> expandedUniforms;
+ std::vector<sh::Varying> varyings;
+ std::vector<sh::InterfaceBlock> interfaceBlocks;
+ bool variablesCollected;
+
+ private:
+ // 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 initSamplerDefaultPrecision(TBasicType samplerType);
+
+ // Removes unused function declarations and prototypes from the AST
+ class UnusedPredicate;
+ bool pruneUnusedFunctions(TIntermBlock *root);
+
+ TIntermBlock *compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ const ShCompileOptions compileOptions);
+
+ sh::GLenum shaderType;
+ ShShaderSpec shaderSpec;
+ ShShaderOutput outputType;
+
+ struct FunctionMetadata
+ {
+ FunctionMetadata()
+ : used(false)
+ {
+ }
+ bool used;
+ };
+
+ CallDAG mCallDag;
+ std::vector<FunctionMetadata> functionMetadata;
+
+ int maxUniformVectors;
+ int maxExpressionComplexity;
+ int maxCallStackDepth;
+ int maxFunctionParameters;
+
+ ShBuiltInResources compileResources;
+ std::string builtInResourcesString;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable symbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior extensionBehavior;
+ bool fragmentPrecisionHigh;
+
+ ArrayBoundsClamper arrayBoundsClamper;
+ ShArrayIndexClampingStrategy clampingStrategy;
+ BuiltInFunctionEmulator builtInFunctionEmulator;
+
+ // Results of compilation.
+ int shaderVersion;
+ TInfoSink infoSink; // Output sink.
+ const char *mSourcePath; // Path of source file or NULL
+
+ // compute shader local group size
+ bool mComputeShaderLocalSizeDeclared;
+ sh::WorkGroupSize mComputeShaderLocalSize;
+
+ // name hashing.
+ ShHashFunction64 hashFunction;
+ NameMap nameMap;
+
+ TPragma mPragma;
+
+ unsigned int mTemporaryIndex;
+};
+
+//
+// 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*);
+
+#endif // COMPILER_TRANSLATOR_COMPILER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp
new file mode 100644
index 000000000..b4074bf77
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp
@@ -0,0 +1,622 @@
+//
+// 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 "base/numerics/safe_math.h"
+#include "common/mathutil.h"
+#include "compiler/translator/Diagnostics.h"
+
+namespace
+{
+
+template <typename T>
+T CheckedSum(base::CheckedNumeric<T> lhs,
+ base::CheckedNumeric<T> rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ ASSERT(lhs.IsValid() && rhs.IsValid());
+ auto result = lhs + rhs;
+ if (!result.IsValid())
+ {
+ diag->error(line, "Addition out of range", "*", "");
+ return 0;
+ }
+ return result.ValueOrDefault(0);
+}
+
+template <typename T>
+T CheckedDiff(base::CheckedNumeric<T> lhs,
+ base::CheckedNumeric<T> rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ ASSERT(lhs.IsValid() && rhs.IsValid());
+ auto result = lhs - rhs;
+ if (!result.IsValid())
+ {
+ diag->error(line, "Difference out of range", "*", "");
+ return 0;
+ }
+ return result.ValueOrDefault(0);
+}
+
+template <typename T>
+T CheckedMul(base::CheckedNumeric<T> lhs,
+ base::CheckedNumeric<T> rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ ASSERT(lhs.IsValid() && rhs.IsValid());
+ auto result = lhs * rhs;
+ if (!result.IsValid())
+ {
+ diag->error(line, "Multiplication out of range", "*", "");
+ return 0;
+ }
+ return result.ValueOrDefault(0);
+}
+
+} // anonymous namespace
+
+TConstantUnion::TConstantUnion()
+{
+ iConst = 0;
+ type = EbtVoid;
+}
+
+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:
+ 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
+{
+ return i == iConst;
+}
+
+bool TConstantUnion::operator==(const unsigned int u) const
+{
+ return u == uConst;
+}
+
+bool TConstantUnion::operator==(const float f) const
+{
+ return f == fConst;
+}
+
+bool TConstantUnion::operator==(const bool b) const
+{
+ return b == bConst;
+}
+
+bool TConstantUnion::operator==(const TConstantUnion &constant) const
+{
+ if (constant.type != type)
+ return false;
+
+ 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;
+ default:
+ return false;
+ }
+}
+
+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 TConstantUnion &constant) const
+{
+ return !operator==(constant);
+}
+
+bool TConstantUnion::operator>(const TConstantUnion &constant) const
+{
+ ASSERT(type == constant.type);
+ 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
+ }
+}
+
+bool TConstantUnion::operator<(const TConstantUnion &constant) const
+{
+ ASSERT(type == constant.type);
+ 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
+ }
+}
+
+// static
+TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ 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<float>(lhs.fConst, rhs.fConst, diag, line));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ 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<float>(lhs.fConst, rhs.fConst, diag, line));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ 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<float>(lhs.fConst, rhs.fConst, diag, line));
+ 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;
+}
+
+// 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 ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
+ (rhs.type == EbtUInt && rhs.uConst > 31u))
+ {
+ diag->error(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.
+ bool extendSignBit = false;
+ int lhsSafe = lhs.iConst;
+ 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(rhs.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 ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
+ (rhs.type == EbtUInt && rhs.uConst > 31u))
+ {
+ diag->error(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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h
new file mode 100644
index 000000000..eec0f0ff9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h
@@ -0,0 +1,86 @@
+//
+// 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/Common.h"
+#include "compiler/translator/BaseTypes.h"
+
+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; }
+
+ int getIConst() const { return iConst; }
+ unsigned int getUConst() const { return uConst; }
+ float getFConst() const { return fConst; }
+ bool getBConst() const { return bConst; }
+
+ 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 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 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
+ };
+
+ TBasicType type;
+};
+
+#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.cpp
new file mode 100644
index 000000000..067e6cea3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -0,0 +1,189 @@
+//
+// 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 function, and
+// adds a function call to that function 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.
+//
+
+#include "compiler/translator/DeferGlobalInitializers.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+void SetInternalFunctionName(TFunctionSymbolInfo *functionInfo, const char *name)
+{
+ TString nameStr(name);
+ nameStr = TFunction::mangleName(nameStr);
+ TName nameObj(nameStr);
+ nameObj.setInternal(true);
+ functionInfo->setNameObj(nameObj);
+}
+
+TIntermAggregate *CreateFunctionPrototypeNode(const char *name, const int functionId)
+{
+ TIntermAggregate *functionNode = new TIntermAggregate(EOpPrototype);
+
+ SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
+ TType returnType(EbtVoid);
+ functionNode->setType(returnType);
+ functionNode->getFunctionSymbolInfo()->setId(functionId);
+ return functionNode;
+}
+
+TIntermFunctionDefinition *CreateFunctionDefinitionNode(const char *name,
+ TIntermBlock *functionBody,
+ const int functionId)
+{
+ TType returnType(EbtVoid);
+ TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
+ TIntermFunctionDefinition *functionNode =
+ new TIntermFunctionDefinition(returnType, paramsNode, functionBody);
+
+ SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
+ functionNode->getFunctionSymbolInfo()->setId(functionId);
+ return functionNode;
+}
+
+TIntermAggregate *CreateFunctionCallNode(const char *name, const int functionId)
+{
+ TIntermAggregate *functionNode = new TIntermAggregate(EOpFunctionCall);
+
+ functionNode->setUserDefined();
+ SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
+ TType returnType(EbtVoid);
+ functionNode->setType(returnType);
+ functionNode->getFunctionSymbolInfo()->setId(functionId);
+ return functionNode;
+}
+
+class DeferGlobalInitializersTraverser : public TIntermTraverser
+{
+ public:
+ DeferGlobalInitializersTraverser();
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ void insertInitFunction(TIntermBlock *root);
+
+ private:
+ TIntermSequence mDeferredInitializers;
+};
+
+DeferGlobalInitializersTraverser::DeferGlobalInitializersTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ ASSERT(symbolNode);
+ TIntermTyped *expression = node->getRight();
+
+ if (mInGlobalScope && (expression->getQualifier() != EvqConst ||
+ (expression->getAsConstantUnion() == nullptr &&
+ !expression->isConstructorWithOnlyConstantUnionParameters())))
+ {
+ // 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 has not been constant folded,
+ // since otherwise there's a chance that HLSL output will generate extra statements
+ // from the initializer expression.
+ TIntermBinary *deferredInit =
+ new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
+ mDeferredInitializers.push_back(deferredInit);
+
+ // 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)
+ {
+ // All of the siblings in the same declaration need to have consistent qualifiers.
+ auto *siblings = getParentNode()->getAsAggregate()->getSequence();
+ for (TIntermNode *siblingNode : *siblings)
+ {
+ TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
+ if (siblingBinary)
+ {
+ ASSERT(siblingBinary->getOp() == EOpInitialize);
+ siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal);
+ }
+ siblingNode->getAsTyped()->getTypePointer()->setQualifier(EvqGlobal);
+ }
+ // This node is one of the siblings.
+ ASSERT(symbolNode->getQualifier() == EvqGlobal);
+ }
+ // Remove the initializer from the global scope and just declare the global instead.
+ queueReplacement(node, symbolNode, OriginalNode::IS_DROPPED);
+ }
+ }
+ return false;
+}
+
+void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
+{
+ if (mDeferredInitializers.empty())
+ {
+ return;
+ }
+ const int initFunctionId = TSymbolTable::nextUniqueId();
+
+ const char *functionName = "initializeDeferredGlobals";
+
+ // Add function prototype to the beginning of the shader
+ TIntermAggregate *functionPrototypeNode =
+ CreateFunctionPrototypeNode(functionName, initFunctionId);
+ root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
+
+ // Add function definition to the end of the shader
+ TIntermBlock *functionBodyNode = new TIntermBlock();
+ TIntermSequence *functionBody = functionBodyNode->getSequence();
+ for (const auto &deferredInit : mDeferredInitializers)
+ {
+ functionBody->push_back(deferredInit);
+ }
+ TIntermFunctionDefinition *functionDefinition =
+ CreateFunctionDefinitionNode(functionName, functionBodyNode, initFunctionId);
+ root->getSequence()->push_back(functionDefinition);
+
+ // Insert call into main function
+ for (TIntermNode *node : *root->getSequence())
+ {
+ TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
+ if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain())
+ {
+ TIntermAggregate *functionCallNode =
+ CreateFunctionCallNode(functionName, initFunctionId);
+
+ TIntermBlock *mainBody = nodeFunction->getBody();
+ ASSERT(mainBody != nullptr);
+ mainBody->getSequence()->insert(mainBody->getSequence()->begin(), functionCallNode);
+ }
+ }
+}
+
+} // namespace
+
+void DeferGlobalInitializers(TIntermBlock *root)
+{
+ DeferGlobalInitializersTraverser traverser;
+ root->traverse(&traverser);
+
+ // Replace the initializers of the global variables.
+ traverser.updateTree();
+
+ // Add the function with initialization and the call to that.
+ traverser.insertInitFunction(root);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.h b/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.h
new file mode 100644
index 000000000..85e55d9c6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/DeferGlobalInitializers.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.
+//
+// DeferGlobalInitializers is an AST traverser that moves global initializers into a function, and
+// adds a function call to that function 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
+#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
+
+class TIntermBlock;
+
+void DeferGlobalInitializers(TIntermBlock *root);
+
+#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Diagnostics.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.cpp
index 8a38c41a6..6ba4679c4 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/Diagnostics.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.cpp
@@ -1,14 +1,15 @@
//
-// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// 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/Diagnostics.h"
+#include "compiler/translator/Diagnostics.h"
-#include "compiler/debug.h"
-#include "compiler/InfoSink.h"
+#include "common/debug.h"
#include "compiler/preprocessor/SourceLocation.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/InfoSink.h"
TDiagnostics::TDiagnostics(TInfoSink& infoSink) :
mInfoSink(infoSink),
@@ -30,11 +31,11 @@ void TDiagnostics::writeInfo(Severity severity,
TPrefixType prefix = EPrefixNone;
switch (severity)
{
- case ERROR:
+ case PP_ERROR:
++mNumErrors;
prefix = EPrefixError;
break;
- case WARNING:
+ case PP_WARNING:
++mNumWarnings;
prefix = EPrefixWarning;
break;
@@ -50,9 +51,26 @@ void TDiagnostics::writeInfo(Severity severity,
sink << "'" << token << "' : " << reason << " " << extra << "\n";
}
-void TDiagnostics::writeDebug(const std::string& str)
+void TDiagnostics::error(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
{
- mInfoSink.debug << str;
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo);
+}
+
+void TDiagnostics::warning(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
+{
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo);
}
void TDiagnostics::print(ID id,
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Diagnostics.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.h
index cb71bb120..bb521da1a 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/Diagnostics.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Diagnostics.h
@@ -1,21 +1,23 @@
//
-// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// 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_DIAGNOSTICS_H_
-#define COMPILER_DIAGNOSTICS_H_
+#ifndef COMPILER_TRANSLATOR_DIAGNOSTICS_H_
+#define COMPILER_TRANSLATOR_DIAGNOSTICS_H_
+#include "common/angleutils.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
class TInfoSink;
+struct TSourceLoc;
-class TDiagnostics : public pp::Diagnostics
+class TDiagnostics : public pp::Diagnostics, angle::NonCopyable
{
public:
TDiagnostics(TInfoSink& infoSink);
- virtual ~TDiagnostics();
+ ~TDiagnostics() override;
TInfoSink& infoSink() { return mInfoSink; }
@@ -28,12 +30,14 @@ class TDiagnostics : public pp::Diagnostics
const std::string& token,
const std::string& extra);
- void writeDebug(const std::string& str);
+ void error(const TSourceLoc &loc, const char *reason, const char *token, const char *extraInfo);
+ void warning(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo);
protected:
- virtual void print(ID id,
- const pp::SourceLocation& loc,
- const std::string& text);
+ void print(ID id, const pp::SourceLocation &loc, const std::string &text) override;
private:
TInfoSink& mInfoSink;
@@ -41,4 +45,4 @@ class TDiagnostics : public pp::Diagnostics
int mNumWarnings;
};
-#endif // COMPILER_DIAGNOSTICS_H_
+#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.cpp
new file mode 100644
index 000000000..f8081ecd6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.cpp
@@ -0,0 +1,197 @@
+//
+// 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/Diagnostics.h"
+
+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 pp::SourceLocation& loc,
+ const std::string& msg)
+{
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", "");
+}
+
+void TDirectiveHandler::handlePragma(const 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.writeInfo(
+ pp::Diagnostics::PP_ERROR, loc,
+ "#pragma STDGL invariant(all) can not be used in fragment shader", name, value);
+ }
+ 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(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
+ return;
+ }
+
+ if (invalidValue)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "invalid pragma value", value,
+ "'on' or 'off' expected");
+ }
+ }
+}
+
+void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior)
+{
+ const char kExtAll[] = "all";
+
+ TBehavior behaviorVal = getBehavior(behavior);
+ if (behaviorVal == EBhUndefined)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "behavior", name, "invalid");
+ return;
+ }
+
+ if (name == kExtAll)
+ {
+ if (behaviorVal == EBhRequire)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "extension", name,
+ "cannot have 'require' behavior");
+ }
+ else if (behaviorVal == EBhEnable)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "extension", name,
+ "cannot have 'enable' behavior");
+ }
+ else
+ {
+ for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
+ iter != mExtensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ return;
+ }
+
+ TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
+ if (iter != mExtensionBehavior.end())
+ {
+ iter->second = behaviorVal;
+ return;
+ }
+
+ pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR;
+ switch (behaviorVal) {
+ case EBhRequire:
+ severity = pp::Diagnostics::PP_ERROR;
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ severity = pp::Diagnostics::PP_WARNING;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ mDiagnostics.writeInfo(severity, loc,
+ "extension", name, "is not supported");
+}
+
+void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
+ int version)
+{
+ if (version == 100 || version == 300 || version == 310)
+ {
+ mShaderVersion = version;
+ }
+ else
+ {
+ std::stringstream stream;
+ stream << version;
+ std::string str = stream.str();
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "version number", str, "not supported");
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.h b/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.h
new file mode 100644
index 000000000..00eb49114
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/DirectiveHandler.h
@@ -0,0 +1,53 @@
+//
+// 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 "common/angleutils.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/Pragma.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+#include "GLSLANG/ShaderLang.h"
+
+class TDiagnostics;
+
+class TDirectiveHandler : public 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 pp::SourceLocation &loc, const std::string &msg) override;
+
+ void handlePragma(const pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &value,
+ bool stdgl) override;
+
+ void handleExtension(const pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &behavior) override;
+
+ void handleVersion(const pp::SourceLocation &loc, int version) override;
+
+ private:
+ TPragma mPragma;
+ TExtensionBehavior& mExtensionBehavior;
+ TDiagnostics& mDiagnostics;
+ int& mShaderVersion;
+ sh::GLenum mShaderType;
+ bool mDebugShaderPrecisionSupported;
+};
+
+#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
new file mode 100644
index 000000000..e34e1dc1c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -0,0 +1,132 @@
+//
+// 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/EmulateGLFragColorBroadcast.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class GLFragColorBroadcastTraverser : public TIntermTraverser
+{
+ public:
+ GLFragColorBroadcastTraverser(int maxDrawBuffers)
+ : TIntermTraverser(true, false, false),
+ mMainSequence(nullptr),
+ mGLFragColorUsed(false),
+ mMaxDrawBuffers(maxDrawBuffers)
+ {
+ }
+
+ void broadcastGLFragColor();
+
+ bool isGLFragColorUsed() const { return mGLFragColorUsed; }
+
+ protected:
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+
+ TIntermBinary *constructGLFragDataNode(int index) const;
+ TIntermBinary *constructGLFragDataAssignNode(int index) const;
+
+ private:
+ TIntermSequence *mMainSequence;
+ bool mGLFragColorUsed;
+ int mMaxDrawBuffers;
+};
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
+{
+ TType gl_FragDataType = TType(EbtFloat, EbpMedium, EvqFragData, 4);
+ gl_FragDataType.setArraySize(mMaxDrawBuffers);
+
+ TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", gl_FragDataType);
+ TIntermTyped *indexNode = TIntermTyped::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->getSymbol() == "gl_FragColor")
+ {
+ queueReplacement(node, constructGLFragDataNode(0), OriginalNode::IS_DROPPED);
+ mGLFragColorUsed = true;
+ }
+}
+
+bool GLFragColorBroadcastTraverser::visitFunctionDefinition(Visit visit,
+ TIntermFunctionDefinition *node)
+{
+ ASSERT(visit == PreVisit);
+ if (node->getFunctionSymbolInfo()->isMain())
+ {
+ TIntermBlock *body = node->getBody();
+ ASSERT(body);
+ mMainSequence = body->getSequence();
+ }
+ return true;
+}
+
+void GLFragColorBroadcastTraverser::broadcastGLFragColor()
+{
+ ASSERT(mMaxDrawBuffers > 1);
+ if (!mGLFragColorUsed)
+ {
+ return;
+ }
+ ASSERT(mMainSequence);
+ // Now insert statements
+ // gl_FragData[1] = gl_FragData[0];
+ // ...
+ // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
+ for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
+ {
+ mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
+ }
+}
+
+} // namespace anonymous
+
+void EmulateGLFragColorBroadcast(TIntermNode *root,
+ int maxDrawBuffers,
+ std::vector<sh::OutputVariable> *outputVariables)
+{
+ ASSERT(maxDrawBuffers > 1);
+ GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
+ root->traverse(&traverser);
+ if (traverser.isGLFragColorUsed())
+ {
+ traverser.updateTree();
+ traverser.broadcastGLFragColor();
+ 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.arraySize = maxDrawBuffers;
+ }
+ }
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.h b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.h
new file mode 100644
index 000000000..627c4c67f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulateGLFragColorBroadcast.h
@@ -0,0 +1,29 @@
+//
+// 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_EMULATEGLFRAGCOLORBROADCAST_H_
+#define COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_
+
+#include <vector>
+
+namespace sh
+{
+struct OutputVariable;
+}
+
+class TIntermNode;
+
+// 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(TIntermNode *root,
+ int maxDrawBuffers,
+ std::vector<sh::OutputVariable> *outputVariables);
+
+#endif // COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.cpp
new file mode 100644
index 000000000..a8f6d642e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.cpp
@@ -0,0 +1,718 @@
+//
+// 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/EmulatePrecision.h"
+
+#include <memory>
+
+namespace
+{
+
+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_frm(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;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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);
+}
+
+TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
+{
+ TIntermAggregate *callNode = new TIntermAggregate();
+ callNode->setOp(EOpFunctionCall);
+ TName nameObj(TFunction::mangleName(name));
+ nameObj.setInternal(true);
+ callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
+ callNode->getSequence()->push_back(child);
+ return callNode;
+}
+
+TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild)
+{
+ TString roundFunctionName;
+ if (roundedChild->getPrecision() == EbpMedium)
+ roundFunctionName = "angle_frm";
+ else
+ roundFunctionName = "angle_frl";
+ TIntermAggregate *callNode = createInternalFunctionCallNode(roundFunctionName, roundedChild);
+ callNode->setType(roundedChild->getType());
+ return callNode;
+}
+
+TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr)
+{
+ std::stringstream strstr;
+ if (left->getPrecision() == EbpMedium)
+ strstr << "angle_compound_" << opNameStr << "_frm";
+ else
+ strstr << "angle_compound_" << opNameStr << "_frl";
+ TString functionName = strstr.str().c_str();
+ TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left);
+ callNode->getSequence()->push_back(right);
+ return callNode;
+}
+
+bool parentUsesResult(TIntermNode* parent, TIntermNode* 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;
+}
+
+} // namespace anonymous
+
+EmulatePrecision::EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion)
+ : TLValueTrackingTraverser(true, true, true, symbolTable, shaderVersion),
+ mDeclaringVariables(false)
+{}
+
+void EmulatePrecision::visitSymbol(TIntermSymbol *node)
+{
+ if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere())
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(node, 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))
+ {
+ break;
+ }
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(node, 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(node, 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(node, 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(node, 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(node, replacement, OriginalNode::IS_DROPPED);
+ break;
+ }
+ default:
+ // The rest of the binary operations should not need precision emulation.
+ break;
+ }
+ }
+ return visitChildren;
+}
+
+bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+ switch (node->getOp())
+ {
+ case EOpConstructStruct:
+ break;
+ case EOpPrototype:
+ visitChildren = false;
+ break;
+ case EOpParameters:
+ visitChildren = false;
+ break;
+ case EOpInvariantDeclaration:
+ visitChildren = false;
+ break;
+ case EOpDeclaration:
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ // Function call.
+ if (visit == PreVisit)
+ {
+ // User-defined function return values are not rounded, this relies on that
+ // calculations producing the value were rounded.
+ TIntermNode *parent = getParentNode();
+ if (canRoundFloat(node->getType()) && !isInFunctionMap(node) &&
+ parentUsesResult(parent, node))
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
+ }
+ }
+ break;
+ }
+ default:
+ TIntermNode *parent = getParentNode();
+ if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node))
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
+ }
+ break;
+ }
+ return visitChildren;
+}
+
+bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative:
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ break;
+ default:
+ if (canRoundFloat(node->getType()) && visit == PreVisit)
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(node, 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 ||
+ IsGLSL130OrNewer(outputLanguage));
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.h b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.h
new file mode 100644
index 000000000..f23e40be7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/EmulatePrecision.h
@@ -0,0 +1,66 @@
+//
+// 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_EMULATE_PRECISION_H_
+#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
+
+#include "common/angleutils.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "GLSLANG/ShaderLang.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.
+
+class EmulatePrecision : public TLValueTrackingTraverser
+{
+ public:
+ EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion);
+
+ 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;
+
+ 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;
+ }
+ };
+
+ typedef std::set<TypePair, TypePairComparator> EmulationSet;
+ EmulationSet mEmulateCompoundAdd;
+ EmulationSet mEmulateCompoundSub;
+ EmulationSet mEmulateCompoundMul;
+ EmulationSet mEmulateCompoundDiv;
+
+ bool mDeclaringVariables;
+};
+
+#endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.cpp
new file mode 100644
index 000000000..9409c010f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.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 the integer pow expressions HLSL bug workaround.
+// See header for more info.
+
+#include "compiler/translator/ExpandIntegerPowExpressions.h"
+
+#include <cmath>
+#include <cstdlib>
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root, unsigned int *tempIndex);
+
+ private:
+ Traverser();
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ void nextIteration();
+
+ bool mFound = false;
+};
+
+// static
+void Traverser::Apply(TIntermNode *root, unsigned int *tempIndex)
+{
+ Traverser traverser;
+ traverser.useTemporaryIndex(tempIndex);
+ 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;
+ nextTemporaryIndex();
+}
+
+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 *constantNode = sequence->at(1)->getAsConstantUnion();
+
+ // Test 1: check for a single constant.
+ if (!constantNode || constantNode->getNominalSize() != 1)
+ {
+ return true;
+ }
+
+ const TConstantUnion *constant = constantNode->getUnionArrayPointer();
+
+ TConstantUnion asFloat;
+ asFloat.cast(EbtFloat, *constant);
+
+ float value = asFloat.getFConst();
+
+ // Test 2: value is in the problematic range.
+ if (value < -5.0f || value > 9.0f)
+ {
+ return true;
+ }
+
+ // Test 3: value is integer or pretty close to an integer.
+ float absval = std::abs(value);
+ float frac = absval - std::round(absval);
+ if (frac > 0.0001f)
+ {
+ return true;
+ }
+
+ // Test 4: skip -1, 0, and 1
+ int exponent = static_cast<int>(value);
+ int n = std::abs(exponent);
+ if (n < 2)
+ {
+ return true;
+ }
+
+ // Potential problem case detected, apply workaround.
+ nextTemporaryIndex();
+
+ TIntermTyped *lhs = sequence->at(0)->getAsTyped();
+ ASSERT(lhs);
+
+ TIntermAggregate *init = createTempInitDeclaration(lhs);
+ TIntermTyped *current = createTempSymbol(lhs->getType());
+
+ insertStatementInParentBlock(init);
+
+ // Create a chain of n-1 multiples.
+ for (int i = 1; i < n; ++i)
+ {
+ TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType()));
+ 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(node, current, OriginalNode::IS_DROPPED);
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void ExpandIntegerPowExpressions(TIntermNode *root, unsigned int *tempIndex)
+{
+ Traverser::Apply(root, tempIndex);
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.h
new file mode 100644
index 000000000..8bc8c9664
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ExpandIntegerPowExpressions.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 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_EXPANDINTEGERPOWEXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void ExpandIntegerPowExpressions(TIntermNode *root, unsigned int *tempIndex);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionBehavior.h
index 5c1595fb2..782c1c921 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionBehavior.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
-#define _EXTENSION_BEHAVIOR_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
+#define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
#include <map>
#include <string>
@@ -34,4 +34,10 @@ inline const char* getBehaviorString(TBehavior b)
// Mapping between extension name and behavior.
typedef std::map<std::string, TBehavior> TExtensionBehavior;
-#endif // _EXTENSION_TABLE_INCLUDED_
+inline bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, const char *extension)
+{
+ auto iter = extBehavior.find(extension);
+ return iter != extBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire);
+}
+
+#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.cpp
new file mode 100644
index 000000000..d7f45f7ee
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.cpp
@@ -0,0 +1,100 @@
+//
+// 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"
+
+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;
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.h
new file mode 100644
index 000000000..6bb84d612
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ExtensionGLSL.h
@@ -0,0 +1,39 @@
+//
+// 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/IntermNode.h"
+
+// 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;
+};
+
+#endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.cpp
new file mode 100644
index 000000000..a751b768b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.cpp
@@ -0,0 +1,77 @@
+//
+// 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.
+//
+
+#include "compiler/translator/FlagStd140Structs.h"
+
+namespace sh
+{
+
+bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getRight()->getBasicType() == EbtStruct)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexDirectStruct:
+ if (isInStd140InterfaceBlock(binaryNode->getLeft()))
+ {
+ mFlaggedNodes.push_back(binaryNode);
+ }
+ break;
+
+ default: break;
+ }
+ return false;
+ }
+
+ if (binaryNode->getOp() == EOpIndexDirectStruct)
+ {
+ return false;
+ }
+
+ return visit == PreVisit;
+}
+
+void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol)
+{
+ if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct)
+ {
+ mFlaggedNodes.push_back(symbol);
+ }
+}
+
+bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const
+{
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode)
+ {
+ return isInStd140InterfaceBlock(binaryNode->getLeft());
+ }
+
+ const TType &type = node->getType();
+
+ // determine if we are in the standard layout
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ return (interfaceBlock->blockStorage() == EbsStd140);
+ }
+
+ return false;
+}
+
+std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node)
+{
+ FlagStd140Structs flaggingTraversal;
+
+ node->traverse(&flaggingTraversal);
+
+ return flaggingTraversal.getFlaggedNodes();
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.h b/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.h
new file mode 100644
index 000000000..cfcd775af
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/FlagStd140Structs.h
@@ -0,0 +1,43 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
+#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+// This class finds references to nested structs of std140 blocks that access
+// the nested struct "by value", where the padding added in the translator
+// conflicts with the "natural" unpadded type.
+class FlagStd140Structs : public TIntermTraverser
+{
+ public:
+
+ FlagStd140Structs()
+ : TIntermTraverser(true, false, false)
+ {
+ }
+
+ const std::vector<TIntermTyped *> getFlaggedNodes() const { return mFlaggedNodes; }
+
+ protected:
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
+ void visitSymbol(TIntermSymbol *symbol) override;
+
+ private:
+ bool isInStd140InterfaceBlock(TIntermTyped *node) const;
+
+ std::vector<TIntermTyped *> mFlaggedNodes;
+};
+
+std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node);
+
+}
+
+#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.cpp
new file mode 100644
index 000000000..4cc1c26a1
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.cpp
@@ -0,0 +1,97 @@
+//
+// 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/ForLoopUnroll.h"
+
+#include "compiler/translator/ValidateLimitations.h"
+#include "angle_gl.h"
+
+bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
+{
+ if (mUnrollCondition != kSamplerArrayIndex)
+ return true;
+
+ // If a sampler array index is also the loop index,
+ // 1) if the index type is integer, mark the loop for unrolling;
+ // 2) if the index type if float, set a flag to later fail compile.
+ switch (node->getOp())
+ {
+ case EOpIndexIndirect:
+ if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode())
+ {
+ TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty())
+ {
+ mVisitSamplerArrayIndexNodeInsideLoop = true;
+ node->getRight()->traverse(this);
+ mVisitSamplerArrayIndexNodeInsideLoop = false;
+ // We have already visited all the children.
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
+{
+ bool canBeUnrolled = mHasRunLoopValidation;
+ if (!mHasRunLoopValidation)
+ {
+ canBeUnrolled = ValidateLimitations::IsLimitedForLoop(node);
+ }
+ if (mUnrollCondition == kIntegerIndex && canBeUnrolled)
+ {
+ // Check if loop index type is integer.
+ // This is called after ValidateLimitations pass, so the loop has the limited form specified
+ // in ESSL 1.00 appendix A.
+ TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence();
+ TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+ if (symbol->getBasicType() == EbtInt)
+ node->setUnrollFlag(true);
+ }
+
+ TIntermNode *body = node->getBody();
+ if (body != nullptr)
+ {
+ if (canBeUnrolled)
+ {
+ mLoopStack.push(node);
+ body->traverse(this);
+ mLoopStack.pop();
+ }
+ else
+ {
+ body->traverse(this);
+ }
+ }
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
+{
+ if (!mVisitSamplerArrayIndexNodeInsideLoop)
+ return;
+ TIntermLoop *loop = mLoopStack.findLoop(symbol);
+ if (loop)
+ {
+ switch (symbol->getBasicType())
+ {
+ case EbtFloat:
+ mSamplerArrayIndexIsFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ loop->setUnrollFlag(true);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.h
new file mode 100644
index 000000000..9c49ecad3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ForLoopUnroll.h
@@ -0,0 +1,53 @@
+//
+// 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_FORLOOPUNROLL_H_
+#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
+
+#include "compiler/translator/LoopInfo.h"
+
+// This class detects for-loops that needs to be unrolled.
+// Currently we support two unroll conditions:
+// 1) kForLoopWithIntegerIndex: unroll if the index type is integer.
+// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index
+// is also the loop integer index, and reject and fail a compile
+// where a sampler array index is also the loop float index.
+class ForLoopUnrollMarker : public TIntermTraverser
+{
+ public:
+ enum UnrollCondition
+ {
+ kIntegerIndex,
+ kSamplerArrayIndex
+ };
+
+ ForLoopUnrollMarker(UnrollCondition condition, bool hasRunLoopValidation)
+ : TIntermTraverser(true, false, false),
+ mUnrollCondition(condition),
+ mSamplerArrayIndexIsFloatLoopIndex(false),
+ mVisitSamplerArrayIndexNodeInsideLoop(false),
+ mHasRunLoopValidation(hasRunLoopValidation)
+ {
+ }
+
+ bool visitBinary(Visit, TIntermBinary *node) override;
+ bool visitLoop(Visit, TIntermLoop *node) override;
+ void visitSymbol(TIntermSymbol *node) override;
+
+ bool samplerArrayIndexIsFloatLoopIndex() const
+ {
+ return mSamplerArrayIndexIsFloatLoopIndex;
+ }
+
+ private:
+ UnrollCondition mUnrollCondition;
+ TLoopStack mLoopStack;
+ bool mSamplerArrayIndexIsFloatLoopIndex;
+ bool mVisitSamplerArrayIndexNodeInsideLoop;
+ bool mHasRunLoopValidation;
+};
+
+#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/HashNames.h b/Source/ThirdParty/ANGLE/src/compiler/translator/HashNames.h
index d2141e2d8..09c959f9d 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/HashNames.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/HashNames.h
@@ -4,16 +4,15 @@
// found in the LICENSE file.
//
-#ifndef COMPILER_HASH_NAMES_H_
-#define COMPILER_HASH_NAMES_H_
+#ifndef COMPILER_TRANSLATOR_HASHNAMES_H_
+#define COMPILER_TRANSLATOR_HASHNAMES_H_
#include <map>
-#include "compiler/intermediate.h"
-#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/IntermNode.h"
#define HASHED_NAME_PREFIX "webgl_"
typedef std::map<TPersistString, TPersistString> NameMap;
-#endif // COMPILER_HASH_NAMES_H_
+#endif // COMPILER_TRANSLATOR_HASHNAMES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.cpp
index d20a6c017..cd59658ff 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.cpp
@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
-#include "compiler/InfoSink.h"
+#include "compiler/translator/InfoSink.h"
void TInfoSinkBase::prefix(TPrefixType p) {
switch(p) {
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.h b/Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.h
index be0ddffe3..f47fafa8e 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InfoSink.h
@@ -4,12 +4,12 @@
// found in the LICENSE file.
//
-#ifndef _INFOSINK_INCLUDED_
-#define _INFOSINK_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_INFOSINK_H_
+#define COMPILER_TRANSLATOR_INFOSINK_H_
#include <math.h>
#include <stdlib.h>
-#include "compiler/Common.h"
+#include "compiler/translator/Common.h"
// Returns the fractional part of the given floating-point number.
inline float fractionalPart(float f) {
@@ -113,4 +113,4 @@ public:
TInfoSinkBase obj;
};
-#endif // _INFOSINK_INCLUDED_
+#endif // COMPILER_TRANSLATOR_INFOSINK_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.cpp
new file mode 100644
index 000000000..759834f85
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.cpp
@@ -0,0 +1,736 @@
+//
+// 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.
+//
+
+//
+// Create symbols that declare built-in definitions, add built-ins that
+// cannot be expressed in the files, and establish mappings between
+// built-in functions and operators.
+//
+
+#include "compiler/translator/Initialize.h"
+#include "compiler/translator/Cache.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "angle_gl.h"
+
+void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
+{
+ const TType *float1 = TCache::getType(EbtFloat);
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *float3 = TCache::getType(EbtFloat, 3);
+ const TType *float4 = TCache::getType(EbtFloat, 4);
+ const TType *int1 = TCache::getType(EbtInt);
+ const TType *int2 = TCache::getType(EbtInt, 2);
+ const TType *int3 = TCache::getType(EbtInt, 3);
+ const TType *uint1 = TCache::getType(EbtUInt);
+ const TType *bool1 = TCache::getType(EbtBool);
+ const TType *genType = TCache::getType(EbtGenType);
+ const TType *genIType = TCache::getType(EbtGenIType);
+ const TType *genUType = TCache::getType(EbtGenUType);
+ const TType *genBType = TCache::getType(EbtGenBType);
+
+ //
+ // Angle and Trigonometric Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRadians, genType, "radians", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDegrees, genType, "degrees", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSin, genType, "sin", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCos, genType, "cos", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpTan, genType, "tan", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAsin, genType, "asin", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAcos, genType, "acos", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSinh, genType, "sinh", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpCosh, genType, "cosh", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTanh, genType, "tanh", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAsinh, genType, "asinh", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAcosh, genType, "acosh", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAtanh, genType, "atanh", genType);
+
+ //
+ // Exponential Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpPow, genType, "pow", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp, genType, "exp", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog, genType, "log", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp2, genType, "exp2", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog2, genType, "log2", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSqrt, genType, "sqrt", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpInverseSqrt, genType, "inversesqrt", genType);
+
+ //
+ // Common Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAbs, genType, "abs", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAbs, genIType, "abs", genIType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSign, genType, "sign", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSign, genIType, "sign", genIType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFloor, genType, "floor", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTrunc, genType, "trunc", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRound, genType, "round", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRoundEven, genType, "roundEven", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCeil, genType, "ceil", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFract, genType, "fract", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, genIType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, genUType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, uint1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, genIType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, genUType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, uint1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, genType, genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, int1, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, genIType, genIType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, uint1, uint1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, genUType, genUType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMix, genType, "mix", genType, genType, genBType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", float1, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", genType, genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", float1, float1, genType);
+
+ const TType *outFloat1 = TCache::getType(EbtFloat, EvqOut);
+ const TType *outFloat2 = TCache::getType(EbtFloat, EvqOut, 2);
+ const TType *outFloat3 = TCache::getType(EbtFloat, EvqOut, 3);
+ const TType *outFloat4 = TCache::getType(EbtFloat, EvqOut, 4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float1, "modf", float1, outFloat1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float2, "modf", float2, outFloat2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float3, "modf", float3, outFloat3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float4, "modf", float4, outFloat4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsNan, genBType, "isnan", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsInf, genBType, "isinf", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToInt, genIType, "floatBitsToInt", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToUint, genUType, "floatBitsToUint", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, "intBitsToFloat", genIType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, "uintBitsToFloat", genUType);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, "packSnorm2x16", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, "packUnorm2x16", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, "packHalf2x16", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackSnorm2x16, float2, "unpackSnorm2x16", uint1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, "unpackUnorm2x16", uint1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, "unpackHalf2x16", uint1);
+
+ //
+ // Geometric Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLength, float1, "length", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDistance, float1, "distance", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDot, float1, "dot", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCross, float3, "cross", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpNormalize, genType, "normalize", genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFaceForward, genType, "faceforward", genType, genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpReflect, genType, "reflect", genType, genType);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRefract, genType, "refract", genType, genType, float1);
+
+ const TType *mat2 = TCache::getType(EbtFloat, 2, 2);
+ const TType *mat3 = TCache::getType(EbtFloat, 3, 3);
+ const TType *mat4 = TCache::getType(EbtFloat, 4, 4);
+ const TType *mat2x3 = TCache::getType(EbtFloat, 2, 3);
+ const TType *mat3x2 = TCache::getType(EbtFloat, 3, 2);
+ const TType *mat2x4 = TCache::getType(EbtFloat, 2, 4);
+ const TType *mat4x2 = TCache::getType(EbtFloat, 4, 2);
+ const TType *mat3x4 = TCache::getType(EbtFloat, 3, 4);
+ const TType *mat4x3 = TCache::getType(EbtFloat, 4, 3);
+
+ //
+ // Matrix Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat2, "matrixCompMult", mat2, mat2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat3, "matrixCompMult", mat3, mat3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat4, "matrixCompMult", mat4, mat4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x3, "matrixCompMult", mat2x3, mat2x3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x2, "matrixCompMult", mat3x2, mat3x2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x4, "matrixCompMult", mat2x4, mat2x4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x2, "matrixCompMult", mat4x2, mat4x2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x4, "matrixCompMult", mat3x4, mat3x4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x3, "matrixCompMult", mat4x3, mat4x3);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2, "outerProduct", float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3, "outerProduct", float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4, "outerProduct", float4, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x3, "outerProduct", float3, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x2, "outerProduct", float2, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x4, "outerProduct", float4, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x2, "outerProduct", float2, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x4, "outerProduct", float4, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x3, "outerProduct", float3, float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2, "transpose", mat2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3, "transpose", mat3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4, "transpose", mat4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x3, "transpose", mat3x2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x2, "transpose", mat2x3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x4, "transpose", mat4x2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x2, "transpose", mat2x4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x4, "transpose", mat4x3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x3, "transpose", mat3x4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat2, "inverse", mat2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat3, "inverse", mat3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat4, "inverse", mat4);
+
+ const TType *vec = TCache::getType(EbtVec);
+ const TType *ivec = TCache::getType(EbtIVec);
+ const TType *uvec = TCache::getType(EbtUVec);
+ const TType *bvec = TCache::getType(EbtBVec);
+
+ //
+ // Vector relational functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThan, bvec, "lessThan", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThan, bvec, "greaterThan", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorEqual, bvec, "equal", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", bvec, bvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", vec, vec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", ivec, ivec);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", uvec, uvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", bvec, bvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAny, bool1, "any", bvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAll, bool1, "all", bvec);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorLogicalNot, bvec, "not", bvec);
+
+ const TType *sampler2D = TCache::getType(EbtSampler2D);
+ const TType *samplerCube = TCache::getType(EbtSamplerCube);
+
+ //
+ // Texture Functions for GLSL ES 1.0
+ //
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3);
+
+ if (resources.OES_EGL_image_external || resources.NV_EGL_stream_consumer_external)
+ {
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float4);
+ }
+
+ if (resources.ARB_texture_rectangle)
+ {
+ const TType *sampler2DRect = TCache::getType(EbtSampler2DRect);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4);
+ }
+
+ if (resources.EXT_shader_texture_lod)
+ {
+ /* The *Grad* variants are new to both vertex and fragment shaders; the fragment
+ * shader specific pieces are added separately below.
+ */
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DGradEXT", sampler2D, float2, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeGradEXT", samplerCube, float3, float3, float3);
+ }
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, float1);
+
+ if (resources.OES_standard_derivatives)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType);
+ }
+
+ if (resources.EXT_shader_texture_lod)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DLodEXT", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeLodEXT", samplerCube, float3, float1);
+ }
+ }
+
+ if (type == GL_VERTEX_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1);
+ }
+
+ const TType *gvec4 = TCache::getType(EbtGVec4);
+
+ const TType *gsampler2D = TCache::getType(EbtGSampler2D);
+ const TType *gsamplerCube = TCache::getType(EbtGSamplerCube);
+ const TType *gsampler3D = TCache::getType(EbtGSampler3D);
+ const TType *gsampler2DArray = TCache::getType(EbtGSampler2DArray);
+
+ //
+ // Texture Functions for GLSL ES 3.0
+ //
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler3D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1);
+
+ if (resources.OES_EGL_image_external_essl3)
+ {
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES,
+ float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES,
+ float4);
+ }
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1);
+
+ if (resources.OES_EGL_image_external_essl3)
+ {
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2,
+ float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES,
+ float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES,
+ float4, float1);
+ }
+ }
+
+ const TType *sampler2DShadow = TCache::getType(EbtSampler2DShadow);
+ const TType *samplerCubeShadow = TCache::getType(EbtSamplerCubeShadow);
+ const TType *sampler2DArrayShadow = TCache::getType(EbtSampler2DArrayShadow);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DArrayShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, float1);
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2D, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler3D, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsamplerCube, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler2DArray, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2DShadow, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1);
+
+ if (resources.OES_EGL_image_external_essl3)
+ {
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerExternalOES, int1);
+ }
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, genType, "dFdx", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, genType, "dFdy", genType);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, genType, "fwidth", genType);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2);
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2);
+
+ if (type == GL_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, float1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler3D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, float1);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1);
+
+ if (resources.OES_EGL_image_external_essl3)
+ {
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texelFetch", samplerExternalOES, int2,
+ int1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, float2, float2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, float3, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, float4, float2, float2, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, float2, float2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2);
+
+ //
+ // Depth range in window coordinates
+ //
+ TFieldList *fields = NewPoolTFieldList();
+ TSourceLoc zeroSourceLoc = {0, 0, 0, 0};
+ auto highpFloat1 = new TType(EbtFloat, EbpHigh, EvqGlobal, 1);
+ TField *near = new TField(highpFloat1, NewPoolTString("near"), zeroSourceLoc);
+ TField *far = new TField(highpFloat1, NewPoolTString("far"), zeroSourceLoc);
+ TField *diff = new TField(highpFloat1, NewPoolTString("diff"), zeroSourceLoc);
+ fields->push_back(near);
+ fields->push_back(far);
+ fields->push_back(diff);
+ TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields);
+ TVariable *depthRangeParameters =
+ new TVariable(&depthRangeStruct->name(), TType(depthRangeStruct), true);
+ symbolTable.insert(COMMON_BUILTINS, depthRangeParameters);
+ TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct));
+ depthRange->setQualifier(EvqUniform);
+ // Ensure we evaluate the mangled name for depth range, so we allocate to the current scope.
+ depthRangeParameters->getType().getMangledName();
+ depthRange->getType().getMangledName();
+ symbolTable.insert(COMMON_BUILTINS, depthRange);
+
+ //
+ // Implementation dependent built-in constants.
+ //
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs,
+ EbpMedium);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors",
+ resources.MaxVertexUniformVectors, EbpMedium);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits",
+ resources.MaxVertexTextureImageUnits, EbpMedium);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits",
+ resources.MaxCombinedTextureImageUnits, EbpMedium);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits",
+ resources.MaxTextureImageUnits, EbpMedium);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors",
+ resources.MaxFragmentUniformVectors, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
+ EbpMedium);
+
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
+ EbpMedium);
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
+ "gl_MaxDualSourceDrawBuffersEXT",
+ resources.MaxDualSourceDrawBuffers);
+ }
+
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
+ resources.MaxVertexOutputVectors, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors",
+ resources.MaxFragmentInputVectors, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset",
+ resources.MinProgramTexelOffset, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset",
+ resources.MaxProgramTexelOffset, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxImageUnits", resources.MaxImageUnits,
+ EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexImageUniforms",
+ resources.MaxVertexImageUniforms, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentImageUniforms",
+ resources.MaxFragmentImageUniforms, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeImageUniforms",
+ resources.MaxComputeImageUniforms, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedImageUniforms",
+ resources.MaxCombinedImageUniforms, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedShaderOutputResources",
+ resources.MaxCombinedShaderOutputResources, EbpMedium);
+
+ symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupCount",
+ resources.MaxComputeWorkGroupCount, EbpHigh);
+ symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupSize",
+ resources.MaxComputeWorkGroupSize, EbpHigh);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeUniformComponents",
+ resources.MaxComputeUniformComponents, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeTextureImageUnits",
+ resources.MaxComputeTextureImageUnits, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounters",
+ resources.MaxComputeAtomicCounters, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounterBuffers",
+ resources.MaxComputeAtomicCounterBuffers, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounters",
+ resources.MaxVertexAtomicCounters, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounters",
+ resources.MaxFragmentAtomicCounters, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounters",
+ resources.MaxCombinedAtomicCounters, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBindings",
+ resources.MaxAtomicCounterBindings, EbpMedium);
+
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounterBuffers",
+ resources.MaxVertexAtomicCounterBuffers, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounterBuffers",
+ resources.MaxFragmentAtomicCounterBuffers, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounterBuffers",
+ resources.MaxCombinedAtomicCounterBuffers, EbpMedium);
+ symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBufferSize",
+ resources.MaxAtomicCounterBufferSize, EbpMedium);
+}
+
+void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
+ const ShBuiltInResources &resources,
+ TSymbolTable &symbolTable)
+{
+ //
+ // Insert some special built-in variables that are not in
+ // the built-in header files.
+ //
+ switch (type)
+ {
+ case GL_FRAGMENT_SHADER:
+ {
+ symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"),
+ TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
+ symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"),
+ TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
+ symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"),
+ TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
+
+ symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"),
+ TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
+
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
+ TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
+ TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
+ secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
+ }
+
+ if (resources.EXT_frag_depth)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_frag_depth",
+ new TVariable(
+ NewPoolTString("gl_FragDepthEXT"),
+ TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
+ EvqFragDepthEXT, 1)));
+ }
+
+ symbolTable.insert(ESSL3_BUILTINS,
+ new TVariable(NewPoolTString("gl_FragDepth"),
+ TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
+
+ if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
+ {
+ TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
+ lastFragData.setArraySize(resources.MaxDrawBuffers);
+
+ if (resources.EXT_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
+ }
+ else if (resources.NV_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragColor"),
+ TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
+ symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
+ }
+ }
+ else if (resources.ARM_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragColorARM"),
+ TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
+ }
+ }
+
+ break;
+
+ case GL_VERTEX_SHADER:
+ symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"),
+ TType(EbtFloat, EbpHigh, EvqPosition, 4)));
+ symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"),
+ TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
+ symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"),
+ TType(EbtInt, EbpHigh, EvqInstanceID, 1)));
+ symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_VertexID"),
+ TType(EbtInt, EbpHigh, EvqVertexID, 1)));
+ break;
+ case GL_COMPUTE_SHADER:
+ {
+ symbolTable.insert(ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_NumWorkGroups"),
+ TType(EbtUInt, EbpUndefined, EvqNumWorkGroups, 3)));
+ symbolTable.insert(ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_WorkGroupSize"),
+ TType(EbtUInt, EbpUndefined, EvqWorkGroupSize, 3)));
+ symbolTable.insert(ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_WorkGroupID"),
+ TType(EbtUInt, EbpUndefined, EvqWorkGroupID, 3)));
+ symbolTable.insert(ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_LocalInvocationID"),
+ TType(EbtUInt, EbpUndefined, EvqLocalInvocationID, 3)));
+ symbolTable.insert(ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_GlobalInvocationID"),
+ TType(EbtUInt, EbpUndefined, EvqGlobalInvocationID, 3)));
+ symbolTable.insert(
+ ESSL3_1_BUILTINS,
+ new TVariable(NewPoolTString("gl_LocalInvocationIndex"),
+ TType(EbtUInt, EbpUndefined, EvqLocalInvocationIndex, 1)));
+ }
+ break;
+
+ default:
+ assert(false && "Language not supported");
+ }
+}
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ extBehavior["GL_OES_standard_derivatives"] = EBhUndefined;
+ if (resources.OES_EGL_image_external)
+ extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
+ if (resources.OES_EGL_image_external_essl3)
+ extBehavior["GL_OES_EGL_image_external_essl3"] = EBhUndefined;
+ if (resources.NV_EGL_stream_consumer_external)
+ extBehavior["GL_NV_EGL_stream_consumer_external"] = EBhUndefined;
+ if (resources.ARB_texture_rectangle)
+ extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+ if (resources.EXT_blend_func_extended)
+ extBehavior["GL_EXT_blend_func_extended"] = EBhUndefined;
+ if (resources.EXT_draw_buffers)
+ extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
+ if (resources.EXT_frag_depth)
+ extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
+ if (resources.EXT_shader_texture_lod)
+ extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined;
+ if (resources.EXT_shader_framebuffer_fetch)
+ extBehavior["GL_EXT_shader_framebuffer_fetch"] = EBhUndefined;
+ if (resources.NV_shader_framebuffer_fetch)
+ extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined;
+ if (resources.ARM_shader_framebuffer_fetch)
+ extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined;
+}
+
+void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
+{
+ for (auto ext_iter = extBehavior.begin();
+ ext_iter != extBehavior.end();
+ ++ext_iter)
+ {
+ ext_iter->second = EBhUndefined;
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.h
new file mode 100644
index 000000000..c43ce3417
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Initialize.h
@@ -0,0 +1,29 @@
+//
+// 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"
+
+void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table);
+
+void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable);
+
+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);
+
+#endif // COMPILER_TRANSLATOR_INITIALIZE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.cpp
index 6c7f27fce..713965389 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.cpp
@@ -4,11 +4,14 @@
// found in the LICENSE file.
//
-#include "compiler/InitializeDll.h"
+#include "compiler/translator/Cache.h"
+#include "compiler/translator/InitializeDll.h"
+#include "compiler/translator/InitializeGlobals.h"
+#include "compiler/translator/InitializeParseContext.h"
-#include "compiler/InitializeGlobals.h"
-#include "compiler/InitializeParseContext.h"
-#include "compiler/osinclude.h"
+#include "common/platform.h"
+
+#include <assert.h>
bool InitProcess()
{
@@ -22,6 +25,8 @@ bool InitProcess()
return false;
}
+ TCache::initialize();
+
return true;
}
@@ -29,4 +34,5 @@ void DetachProcess()
{
FreeParseContextIndex();
FreePoolIndex();
+ TCache::destroy();
}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.h
index 43070cc3f..4c400760f 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeDll.h
@@ -3,11 +3,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-#ifndef __INITIALIZEDLL_H
-#define __INITIALIZEDLL_H
+#ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_
+#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_
bool InitProcess();
void DetachProcess();
-#endif // __INITIALIZEDLL_H
+#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeGlobals.h
index 071594142..8c65cb28d 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeGlobals.h
@@ -4,10 +4,10 @@
// found in the LICENSE file.
//
-#ifndef __INITIALIZE_GLOBALS_INCLUDED_
-#define __INITIALIZE_GLOBALS_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
+#define COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
bool InitializePoolIndex();
void FreePoolIndex();
-#endif // __INITIALIZE_GLOBALS_INCLUDED_
+#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.cpp
new file mode 100644
index 000000000..c35cedb34
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.cpp
@@ -0,0 +1,42 @@
+//
+// 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.
+//
+
+#include "compiler/translator/InitializeParseContext.h"
+
+#include "common/tls.h"
+
+#include <assert.h>
+
+TLSIndex GlobalParseContextIndex = TLS_INVALID_INDEX;
+
+bool InitializeParseContextIndex()
+{
+ assert(GlobalParseContextIndex == TLS_INVALID_INDEX);
+
+ GlobalParseContextIndex = CreateTLSIndex();
+ return GlobalParseContextIndex != TLS_INVALID_INDEX;
+}
+
+void FreeParseContextIndex()
+{
+ assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
+
+ DestroyTLSIndex(GlobalParseContextIndex);
+ GlobalParseContextIndex = TLS_INVALID_INDEX;
+}
+
+void SetGlobalParseContext(TParseContext* context)
+{
+ assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
+ SetTLSValue(GlobalParseContextIndex, context);
+}
+
+TParseContext* GetGlobalParseContext()
+{
+ assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
+ return static_cast<TParseContext*>(GetTLSValue(GlobalParseContextIndex));
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.h
index bffbab87d..70dac702e 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeParseContext.h
@@ -4,14 +4,14 @@
// found in the LICENSE file.
//
-#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_
-#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
+#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
bool InitializeParseContextIndex();
void FreeParseContextIndex();
-struct TParseContext;
+class TParseContext;
extern void SetGlobalParseContext(TParseContext* context);
extern TParseContext* GetGlobalParseContext();
-#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.cpp
new file mode 100644
index 000000000..2deff0c5e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.cpp
@@ -0,0 +1,105 @@
+//
+// 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/InitializeVariables.h"
+
+#include "angle_gl.h"
+#include "common/debug.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/util.h"
+
+namespace
+{
+
+class VariableInitializer : public TIntermTraverser
+{
+ public:
+ VariableInitializer(const InitVariableList &vars)
+ : TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
+ {
+ }
+
+ protected:
+ bool visitBinary(Visit, TIntermBinary *node) override { return false; }
+ bool visitUnary(Visit, TIntermUnary *node) override { return false; }
+ bool visitIfElse(Visit, TIntermIfElse *node) override { return false; }
+ bool visitLoop(Visit, TIntermLoop *node) override { return false; }
+ bool visitBranch(Visit, TIntermBranch *node) override { return false; }
+ bool visitAggregate(Visit, TIntermAggregate *node) override { return false; }
+
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+
+ private:
+ void insertInitCode(TIntermSequence *sequence);
+
+ const InitVariableList &mVariables;
+ bool mCodeInserted;
+};
+
+// VariableInitializer implementation.
+
+bool VariableInitializer::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ if (node->getFunctionSymbolInfo()->isMain())
+ {
+ TIntermBlock *body = node->getBody();
+ insertInitCode(body->getSequence());
+ mCodeInserted = true;
+ }
+ return false;
+}
+
+void VariableInitializer::insertInitCode(TIntermSequence *sequence)
+{
+ for (const auto &var : mVariables)
+ {
+ TString name = TString(var.name.c_str());
+ TType type = sh::GetShaderVariableType(var);
+
+ // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
+ // doesn't have array assignment.
+ if (var.isArray())
+ {
+ size_t pos = name.find_last_of('[');
+ if (pos != TString::npos)
+ {
+ name = name.substr(0, pos);
+ }
+ TType elementType = type;
+ elementType.clearArrayness();
+
+ for (unsigned int i = 0; i < var.arraySize; ++i)
+ {
+ TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
+ TIntermTyped::CreateIndexNode(i));
+
+ TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
+ TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
+
+ sequence->insert(sequence->begin(), assignment);
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
+ TIntermTyped *zero = TIntermTyped::CreateZero(type);
+
+ TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
+ sequence->insert(sequence->begin(), assign);
+ }
+ }
+}
+
+} // namespace anonymous
+
+void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
+{
+ VariableInitializer initializer(vars);
+ root->traverse(&initializer);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.h b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.h
new file mode 100644
index 000000000..dce1083f6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/InitializeVariables.h
@@ -0,0 +1,19 @@
+//
+// 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_INITIALIZEVARIABLES_H_
+#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+class TIntermNode;
+
+typedef std::vector<sh::ShaderVariable> InitVariableList;
+
+// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend.
+void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
+
+#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp
new file mode 100644
index 000000000..0acfe40e7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp
@@ -0,0 +1,2863 @@
+//
+// 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/HashNames.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+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,
+ TQualifier qualifier)
+{
+ if (constArray == nullptr)
+ {
+ return nullptr;
+ }
+ TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
+ folded->getTypePointer()->setQualifier(qualifier);
+ 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]);
+}
+
+} // namespace anonymous
+
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+void TIntermTyped::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) \
+ if (node == original) { \
+ node = static_cast<type *>(replacement); \
+ return true; \
+ }
+
+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;
+}
+
+bool TIntermBranch::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
+ return false;
+}
+
+bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
+ REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
+ return false;
+}
+
+bool TIntermBinary::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
+ return false;
+}
+
+bool TIntermUnary::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
+ REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
+ return false;
+}
+
+bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mParameters, TIntermAggregate, original, replacement);
+ REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
+ return false;
+}
+
+bool TIntermAggregate::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ return replaceChildNodeInternal(original, replacement);
+}
+
+bool TIntermBlock::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;
+}
+
+bool TIntermAggregate::areChildrenConstQualified()
+{
+ for (TIntermNode *&child : mSequence)
+ {
+ TIntermTyped *typed = child->getAsTyped();
+ if (typed && typed->getQualifier() != EvqConst)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void TIntermAggregate::setPrecisionFromChildren()
+{
+ mGotPrecisionFromChildren = true;
+ if (getBasicType() == EbtBool)
+ {
+ mType.setPrecision(EbpUndefined);
+ return;
+ }
+
+ TPrecision precision = EbpUndefined;
+ TIntermSequence::iterator childIter = mSequence.begin();
+ while (childIter != mSequence.end())
+ {
+ TIntermTyped *typed = (*childIter)->getAsTyped();
+ if (typed)
+ precision = GetHigherPrecision(typed->getPrecision(), precision);
+ ++childIter;
+ }
+ mType.setPrecision(precision);
+}
+
+void TIntermAggregate::setBuiltInFunctionPrecision()
+{
+ // All built-ins returning bool should be handled as ops, not functions.
+ ASSERT(getBasicType() != EbtBool);
+
+ TPrecision precision = EbpUndefined;
+ TIntermSequence::iterator childIter = mSequence.begin();
+ while (childIter != mSequence.end())
+ {
+ TIntermTyped *typed = (*childIter)->getAsTyped();
+ // ESSL spec section 8: texture functions get their precision from the sampler.
+ if (typed && IsSampler(typed->getBasicType()))
+ {
+ precision = typed->getPrecision();
+ break;
+ }
+ ++childIter;
+ }
+ // 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 (mFunctionInfo.getName().find("textureSize") == 0)
+ mType.setPrecision(EbpHigh);
+ else
+ mType.setPrecision(precision);
+}
+
+void TIntermBlock::appendStatement(TIntermNode *statement)
+{
+ if (statement != nullptr)
+ {
+ mStatements.push_back(statement);
+ }
+}
+
+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;
+}
+
+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;
+}
+
+bool TIntermSwitch::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
+ return false;
+}
+
+bool TIntermCase::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
+ return false;
+}
+
+TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
+{
+ // 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 besides handling fields in TIntermTyped.
+ mLine = node.mLine;
+}
+
+bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
+{
+ TIntermAggregate *constructor = getAsAggregate();
+ if (!constructor || !constructor->isConstructor())
+ {
+ return false;
+ }
+ for (TIntermNode *&node : *constructor->getSequence())
+ {
+ if (!node->getAsConstantUnion())
+ return false;
+ }
+ return true;
+}
+
+// static
+TIntermTyped *TIntermTyped::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;
+}
+
+// static
+TIntermTyped *TIntermTyped::CreateZero(const TType &type)
+{
+ TType constType(type);
+ constType.setQualifier(EvqConst);
+
+ if (!type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
+
+ 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:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
+ return node;
+ }
+
+ TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
+ constructor->setType(constType);
+
+ if (type.isArray())
+ {
+ TType elementType(type);
+ elementType.clearArrayness();
+
+ size_t arraySize = type.getArraySize();
+ for (size_t i = 0; i < arraySize; ++i)
+ {
+ constructor->getSequence()->push_back(CreateZero(elementType));
+ }
+ }
+ else
+ {
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ TStructure *structure = type.getStruct();
+ for (const auto &field : structure->fields())
+ {
+ constructor->getSequence()->push_back(CreateZero(*field->type()));
+ }
+ }
+
+ return constructor;
+}
+
+TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
+{
+ mUnionArrayPointer = node.mUnionArrayPointer;
+}
+
+void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
+{
+ setName(function.getMangledName());
+ setId(function.getUniqueId());
+}
+
+TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
+ : TIntermOperator(node),
+ mUserDefined(node.mUserDefined),
+ mUseEmulatedFunction(node.mUseEmulatedFunction),
+ mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
+ mFunctionInfo(node.mFunctionInfo)
+{
+ for (TIntermNode *child : node.mSequence)
+ {
+ TIntermTyped *typedChild = child->getAsTyped();
+ ASSERT(typedChild != nullptr);
+ TIntermTyped *childCopy = typedChild->deepCopy();
+ mSequence.push_back(childCopy);
+ }
+}
+
+TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
+{
+ TIntermTyped *operandCopy = node.mOperand->deepCopy();
+ ASSERT(operandCopy != nullptr);
+ mOperand = operandCopy;
+}
+
+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)
+{
+ TIntermTyped *operandCopy = node.mOperand->deepCopy();
+ ASSERT(operandCopy != nullptr);
+ mOperand = operandCopy;
+}
+
+TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(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;
+ }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+ switch (mOp)
+ {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ case EOpConstructUVec2:
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+ case EOpConstructUInt:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ case EOpConstructStruct:
+ 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()
+{
+ 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:
+ 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 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;
+ default:
+ setType(mOperand->getType());
+ mType.setQualifier(resultQualifier);
+ break;
+ }
+}
+
+TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
+ : TIntermTyped(TType(EbtFloat, EbpUndefined)),
+ mOperand(operand),
+ mSwizzleOffsets(swizzleOffsets)
+{
+ ASSERT(mSwizzleOffsets.size() <= 4);
+ promote();
+}
+
+TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
+ : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
+{
+ promote();
+}
+
+TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
+ : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
+{
+ promote();
+}
+
+TIntermTernary::TIntermTernary(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+ : TIntermTyped(trueExpression->getType()),
+ mCondition(cond),
+ mTrueExpression(trueExpression),
+ mFalseExpression(falseExpression)
+{
+ getTypePointer()->setQualifier(
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
+}
+
+// static
+TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+{
+ if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
+ falseExpression->getQualifier() == EvqConst)
+ {
+ return EvqConst;
+ }
+ return EvqTemporary;
+}
+
+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
+{
+ int offsetCount[4] = {0u, 0u, 0u, 0u};
+ for (const auto offset : mSwizzleOffsets)
+ {
+ offsetCount[offset]++;
+ if (offsetCount[offset] > 1)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+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.
+ 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.clearArrayness();
+ }
+ 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;
+ }
+}
+
+const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
+{
+ if (isArray())
+ {
+ ASSERT(index < static_cast<int>(getType().getArraySize()));
+ TType arrayElementType = getType();
+ arrayElementType.clearArrayness();
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ return &mUnionArrayPointer[arrayElementSize * index];
+ }
+ else if (isMatrix())
+ {
+ ASSERT(index < getType().getCols());
+ int size = getType().getRows();
+ return &mUnionArrayPointer[size * index];
+ }
+ else if (isVector())
+ {
+ ASSERT(index < getType().getNominalSize());
+ return &mUnionArrayPointer[index];
+ }
+ else
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+TIntermTyped *TIntermSwizzle::fold()
+{
+ TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+ if (operandConstant == nullptr)
+ {
+ return nullptr;
+ }
+
+ TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
+ for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
+ {
+ constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
+ }
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+}
+
+TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
+{
+ TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
+ TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
+ switch (mOp)
+ {
+ case EOpIndexDirect:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ int index = rightConstant->getIConst(0);
+
+ const TConstantUnion *constArray = leftConstant->foldIndexing(index);
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+ }
+ case EOpIndexDirectStruct:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ const TFieldList &fields = mLeft->getType().getStruct()->fields();
+ size_t index = static_cast<size_t>(rightConstant->getIConst(0));
+
+ size_t previousFieldsSize = 0;
+ for (size_t i = 0; i < index; ++i)
+ {
+ previousFieldsSize += fields[i]->type()->getObjectSize();
+ }
+
+ const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
+ return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
+ }
+ case EOpIndexIndirect:
+ case EOpIndexDirectInterfaceBlock:
+ // Can never be constant folded.
+ return nullptr;
+ default:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ TConstantUnion *constArray =
+ leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
+
+ // Nodes may be constant folded without being qualified as constant.
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+ }
+ }
+}
+
+TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
+{
+ TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+ if (operandConstant == nullptr)
+ {
+ return nullptr;
+ }
+
+ TConstantUnion *constArray = nullptr;
+ 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:
+ constArray = operandConstant->foldUnaryNonComponentWise(mOp);
+ break;
+ default:
+ constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
+ break;
+ }
+
+ // Nodes may be constant folded without being qualified as constant.
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+}
+
+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 nullptr;
+ }
+ }
+ TConstantUnion *constArray = nullptr;
+ if (isConstructor())
+ constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
+ else
+ constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
+
+ // Nodes may be constant folded without being qualified as constant.
+ TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
+ return CreateFoldedNode(constArray, this, resultQualifier);
+}
+
+//
+// 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.
+//
+TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
+ TIntermConstantUnion *rightNode,
+ TDiagnostics *diagnostics,
+ const TSourceLoc &line)
+{
+ const TConstantUnion *leftArray = getUnionArrayPointer();
+ const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
+
+ ASSERT(leftArray && rightArray);
+
+ size_t objectSize = getType().getObjectSize();
+
+ // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
+ if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
+ {
+ rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
+ }
+ else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
+ {
+ // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
+ leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
+ objectSize = rightNode->getType().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(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
+
+ const int leftCols = getCols();
+ const int leftRows = getRows();
+ const int rightCols = rightNode->getType().getCols();
+ const int rightRows = rightNode->getType().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++)
+ {
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ if (rightArray[i] == 0.0f)
+ {
+ diagnostics->warning(
+ getLine(), "Divide by zero error during constant folding", "/", "");
+ resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
+ }
+ else
+ {
+ ASSERT(op == EOpDiv);
+ resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
+ }
+ break;
+
+ case EbtInt:
+ if (rightArray[i] == 0)
+ {
+ diagnostics->warning(
+ getLine(), "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(getLine(),
+ "Negative modulus operator operand "
+ "encountered during constant folding",
+ "%", "");
+ resultArray[i].setIConst(0);
+ }
+ else
+ {
+ resultArray[i].setIConst(lhs % divisor);
+ }
+ }
+ }
+ break;
+
+ case EbtUInt:
+ if (rightArray[i] == 0)
+ {
+ diagnostics->warning(
+ getLine(), "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(rightNode->getBasicType() == EbtFloat);
+
+ const int matrixCols = getCols();
+ const int matrixRows = 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(getType().getBasicType() == EbtFloat);
+
+ const int matrixCols = rightNode->getType().getCols();
+ const int matrixRows = rightNode->getType().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(getType().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 = getUnionArrayPointer();
+ 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;
+ }
+
+ 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 = getUnionArrayPointer();
+ 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 EOpVectorLogicalNot:
+ 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 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::FoldAggregateConstructor(TIntermAggregate *aggregate)
+{
+ ASSERT(aggregate->getSequence()->size() > 0u);
+ size_t resultSize = aggregate->getType().getObjectSize();
+ TConstantUnion *resultArray = new TConstantUnion[resultSize];
+ TBasicType basicType = aggregate->getBasicType();
+
+ size_t resultIndex = 0u;
+
+ if (aggregate->getSequence()->size() == 1u)
+ {
+ TIntermNode *argument = aggregate->getSequence()->front();
+ TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
+ const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+ // Check the special case of constructing a matrix diagonal from a single scalar,
+ // or a vector from a single scalar.
+ if (argumentConstant->getType().getObjectSize() == 1u)
+ {
+ if (aggregate->isMatrix())
+ {
+ int resultCols = aggregate->getType().getCols();
+ int resultRows = aggregate->getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
+ {
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col == row)
+ {
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+ }
+ else
+ {
+ resultArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
+ }
+ }
+ }
+ else
+ {
+ while (resultIndex < resultSize)
+ {
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+ }
+ else if (aggregate->isMatrix() && argumentConstant->isMatrix())
+ {
+ // The special case of constructing a matrix from a matrix.
+ int argumentCols = argumentConstant->getType().getCols();
+ int argumentRows = argumentConstant->getType().getRows();
+ int resultCols = aggregate->getType().getCols();
+ int resultRows = aggregate->getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
+ {
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col < argumentCols && row < argumentRows)
+ {
+ resultArray[resultIndex].cast(basicType,
+ argumentUnionArray[col * argumentRows + row]);
+ }
+ else if (col == row)
+ {
+ resultArray[resultIndex].setFConst(1.0f);
+ }
+ else
+ {
+ resultArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+ }
+ }
+
+ for (TIntermNode *&argument : *aggregate->getSequence())
+ {
+ TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
+ size_t argumentSize = argumentConstant->getType().getObjectSize();
+ const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+ for (size_t i = 0u; i < argumentSize; ++i)
+ {
+ if (resultIndex >= resultSize)
+ break;
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+}
+
+// static
+TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
+{
+ TOperator op = aggregate->getOp();
+ TIntermSequence *sequence = aggregate->getSequence();
+ unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
+ std::vector<const TConstantUnion *> unionArrays(paramsCount);
+ std::vector<size_t> objectSizes(paramsCount);
+ size_t maxObjectSize = 0;
+ TBasicType basicType = EbtVoid;
+ TSourceLoc loc;
+ for (unsigned int i = 0; i < paramsCount; i++)
+ {
+ TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
+ ASSERT(paramConstant != nullptr); // Should be checked already.
+
+ if (i == 0)
+ {
+ basicType = paramConstant->getType().getBasicType();
+ loc = paramConstant->getLine();
+ }
+ unionArrays[i] = paramConstant->getUnionArrayPointer();
+ objectSizes[i] = paramConstant->getType().getObjectSize();
+ if (objectSizes[i] > maxObjectSize)
+ maxObjectSize = objectSizes[i];
+ }
+
+ if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
+ {
+ for (unsigned int i = 0; i < paramsCount; i++)
+ if (objectSizes[i] != maxObjectSize)
+ unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
+ }
+
+ TConstantUnion *resultArray = nullptr;
+ if (paramsCount == 2)
+ {
+ //
+ // Binary built-in
+ //
+ 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 EOpLessThan:
+ {
+ 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 EOpLessThanEqual:
+ {
+ 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 EOpGreaterThan:
+ {
+ 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 EOpGreaterThanEqual:
+ {
+ 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 EOpVectorEqual:
+ {
+ 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 EOpVectorNotEqual:
+ {
+ 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 EOpMul:
+ {
+ ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
+ (*sequence)[1]->getAsTyped()->isMatrix());
+ // Perform component-wise matrix multiplication.
+ resultArray = new TConstantUnion[maxObjectSize];
+ int size = (*sequence)[0]->getAsTyped()->getNominalSize();
+ angle::Matrix<float> result =
+ GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+
+ case EOpOuterProduct:
+ {
+ ASSERT(basicType == EbtFloat);
+ size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
+ size_t numCols = (*sequence)[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;
+ }
+
+ default:
+ UNREACHABLE();
+ // TODO: Add constant folding support for other built-in operations that take 2
+ // parameters and not handled above.
+ return nullptr;
+ }
+ }
+ else if (paramsCount == 3)
+ {
+ //
+ // Ternary built-in
+ //
+ switch (op)
+ {
+ 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 = (*sequence)[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 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;
+ }
+
+ default:
+ UNREACHABLE();
+ // TODO: Add constant folding support for other built-in operations that take 3
+ // parameters and not handled above.
+ return nullptr;
+ }
+ }
+ return resultArray;
+}
+
+// static
+TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
+{
+ if (hashFunction == NULL || name.empty())
+ return name;
+ khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
+ TStringStream stream;
+ stream << HASHED_NAME_PREFIX << std::hex << number;
+ TString hashedName = stream.str();
+ return hashedName;
+}
+
+void TIntermTraverser::updateTree()
+{
+ for (size_t ii = 0; ii < mInsertions.size(); ++ii)
+ {
+ const NodeInsertMultipleEntry &insertion = mInsertions[ii];
+ ASSERT(insertion.parent);
+ if (!insertion.insertionsAfter.empty())
+ {
+ bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+ insertion.insertionsAfter);
+ ASSERT(inserted);
+ UNUSED_ASSERTION_VARIABLE(inserted);
+ }
+ if (!insertion.insertionsBefore.empty())
+ {
+ bool inserted =
+ insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+ ASSERT(inserted);
+ UNUSED_ASSERTION_VARIABLE(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);
+ UNUSED_ASSERTION_VARIABLE(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);
+ UNUSED_ASSERTION_VARIABLE(replaced);
+ }
+
+ clearReplacementQueue();
+}
+
+void TIntermTraverser::clearReplacementQueue()
+{
+ mReplacements.clear();
+ mMultiReplacements.clear();
+ mInsertions.clear();
+}
+
+void TIntermTraverser::queueReplacement(TIntermNode *original,
+ TIntermNode *replacement,
+ OriginalNode originalStatus)
+{
+ queueReplacementWithParent(getParentNode(), original, 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));
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h
new file mode 100644
index 000000000..4c3703413
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h
@@ -0,0 +1,1175 @@
+//
+// 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/Operator.h"
+#include "compiler/translator/Types.h"
+
+class TDiagnostics;
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBlock;
+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 TIntermRaw;
+class TIntermBranch;
+
+class TSymbolTable;
+class TFunction;
+
+// Encapsulate an identifier string and track whether it is coming from the original shader code
+// (not internal) or from ANGLE (internal). Usually internal names shouldn't be decorated or hashed.
+class TName
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ explicit TName(const TString &name) : mName(name), mIsInternal(false) {}
+ TName() : mName(), mIsInternal(false) {}
+ TName(const TName &) = default;
+ TName &operator=(const TName &) = default;
+
+ const TString &getString() const { return mName; }
+ void setString(const TString &string) { mName = string; }
+ bool isInternal() const { return mIsInternal; }
+ void setInternal(bool isInternal) { mIsInternal = isInternal; }
+
+ private:
+ TString mName;
+ bool mIsInternal;
+};
+
+//
+// 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 *) = 0;
+ virtual TIntermTyped *getAsTyped() { return 0; }
+ virtual TIntermConstantUnion *getAsConstantUnion() { return 0; }
+ virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; }
+ virtual TIntermAggregate *getAsAggregate() { return 0; }
+ virtual TIntermBlock *getAsBlock() { return nullptr; }
+ virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
+ virtual TIntermBinary *getAsBinaryNode() { return 0; }
+ virtual TIntermUnary *getAsUnaryNode() { return 0; }
+ virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
+ virtual TIntermIfElse *getAsIfElseNode() { return nullptr; }
+ virtual TIntermSwitch *getAsSwitchNode() { return 0; }
+ virtual TIntermCase *getAsCaseNode() { return 0; }
+ virtual TIntermSymbol *getAsSymbolNode() { return 0; }
+ virtual TIntermLoop *getAsLoopNode() { return 0; }
+ virtual TIntermRaw *getAsRawNode() { return 0; }
+ virtual TIntermBranch *getAsBranchNode() { return 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(const TType &t) : mType(t) { }
+
+ virtual TIntermTyped *deepCopy() const = 0;
+
+ TIntermTyped *getAsTyped() override { return this; }
+
+ virtual bool hasSideEffects() const = 0;
+
+ void setType(const TType &t) { mType = t; }
+ void setTypePreservePrecision(const TType &t);
+ const TType &getType() const { return mType; }
+ TType *getTypePointer() { return &mType; }
+
+ TBasicType getBasicType() const { return mType.getBasicType(); }
+ TQualifier getQualifier() const { return mType.getQualifier(); }
+ TPrecision getPrecision() const { return mType.getPrecision(); }
+ int getCols() const { return mType.getCols(); }
+ int getRows() const { return mType.getRows(); }
+ int getNominalSize() const { return mType.getNominalSize(); }
+ int getSecondarySize() const { return mType.getSecondarySize(); }
+
+ bool isInterfaceBlock() const { return mType.isInterfaceBlock(); }
+ bool isMatrix() const { return mType.isMatrix(); }
+ bool isArray() const { return mType.isArray(); }
+ bool isVector() const { return mType.isVector(); }
+ bool isScalar() const { return mType.isScalar(); }
+ bool isScalarInt() const { return mType.isScalarInt(); }
+ const char *getBasicString() const { return mType.getBasicString(); }
+ TString getCompleteString() const { return mType.getCompleteString(); }
+
+ unsigned int getArraySize() const { return mType.getArraySize(); }
+
+ bool isConstructorWithOnlyConstantUnionParameters();
+
+ static TIntermTyped *CreateIndexNode(int index);
+ static TIntermTyped *CreateZero(const TType &type);
+
+ protected:
+ TType mType;
+
+ 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)
+ : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
+ {
+ }
+
+ TIntermLoop *getAsLoopNode() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ 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 setCondition(TIntermTyped *condition) { mCond = condition; }
+ void setExpression(TIntermTyped *expression) { mExpr = expression; }
+ void setBody(TIntermBlock *body) { mBody = body; }
+
+ void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
+ bool getUnrollFlag() const { return mUnrollFlag; }
+
+ protected:
+ TLoopType mType;
+ TIntermNode *mInit; // for-loop initialization
+ TIntermTyped *mCond; // loop exit condition
+ TIntermTyped *mExpr; // for-loop expression
+ TIntermBlock *mBody; // loop body
+
+ bool mUnrollFlag; // Whether the loop should be unrolled or not.
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode
+{
+ public:
+ TIntermBranch(TOperator op, TIntermTyped *e)
+ : mFlowOp(op),
+ mExpression(e) { }
+
+ void traverse(TIntermTraverser *it) override;
+ TIntermBranch *getAsBranchNode() override { return this; }
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TOperator getFlowOp() { return mFlowOp; }
+ TIntermTyped* getExpression() { return mExpression; }
+
+protected:
+ TOperator mFlowOp;
+ TIntermTyped *mExpression; // non-zero except for "return exp;" statements
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped
+{
+ public:
+ // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym.
+ // If sym comes from per process globalpoolallocator, then it causes increased memory usage
+ // per compile it is essential to use "symbol = sym" to assign to symbol
+ TIntermSymbol(int id, const TString &symbol, const TType &type)
+ : TIntermTyped(type), mId(id), mSymbol(symbol)
+ {
+ }
+
+ TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); }
+
+ bool hasSideEffects() const override { return false; }
+
+ int getId() const { return mId; }
+ const TString &getSymbol() const { return mSymbol.getString(); }
+ const TName &getName() const { return mSymbol; }
+
+ void setId(int newId) { mId = newId; }
+
+ void setInternal(bool internal) { mSymbol.setInternal(internal); }
+
+ void traverse(TIntermTraverser *it) override;
+ TIntermSymbol *getAsSymbolNode() override { return this; }
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ protected:
+ int mId;
+ TName mSymbol;
+
+ private:
+ TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private!
+};
+
+// A Raw node stores raw code, that the translator will insert verbatim
+// into the output stream. Useful for transformation operations that make
+// complex code that might not fit naturally into the GLSL model.
+class TIntermRaw : public TIntermTyped
+{
+ public:
+ TIntermRaw(const TType &type, const TString &rawText)
+ : TIntermTyped(type),
+ mRawText(rawText) { }
+ TIntermRaw(const TIntermRaw &) = delete;
+
+ TIntermTyped *deepCopy() const override
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+
+ bool hasSideEffects() const override { return false; }
+
+ TString getRawText() const { return mRawText; }
+
+ void traverse(TIntermTraverser *it) override;
+
+ TIntermRaw *getAsRawNode() override { return this; }
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ protected:
+ TString mRawText;
+};
+
+// 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 TIntermTyped
+{
+ public:
+ TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
+ : TIntermTyped(type), mUnionArrayPointer(unionPointer)
+ {
+ ASSERT(unionPointer);
+ }
+
+ TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
+
+ bool hasSideEffects() const override { return false; }
+
+ const TConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
+
+ 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;
+ }
+
+ void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
+ {
+ ASSERT(safeConstantUnion);
+ // Previous union pointer freed on pool deallocation.
+ mUnionArrayPointer = safeConstantUnion;
+ }
+
+ TIntermConstantUnion *getAsConstantUnion() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ TConstantUnion *foldBinary(TOperator op,
+ TIntermConstantUnion *rightNode,
+ TDiagnostics *diagnostics,
+ const TSourceLoc &line);
+ const TConstantUnion *foldIndexing(int index);
+ TConstantUnion *foldUnaryNonComponentWise(TOperator op);
+ TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
+
+ static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
+ static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics);
+
+ 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 TIntermTyped
+{
+ public:
+ TOperator getOp() const { return mOp; }
+
+ bool isAssignment() const;
+ bool isMultiplication() const;
+ bool isConstructor() const;
+
+ bool hasSideEffects() const override { return isAssignment(); }
+
+ protected:
+ TIntermOperator(TOperator op)
+ : TIntermTyped(TType(EbtFloat, EbpUndefined)),
+ mOp(op) {}
+ TIntermOperator(TOperator op, const TType &type)
+ : TIntermTyped(type),
+ mOp(op) {}
+
+ TIntermOperator(const TIntermOperator &) = default;
+
+ TOperator mOp;
+};
+
+// Node for vector swizzles.
+class TIntermSwizzle : public TIntermTyped
+{
+ 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; };
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override { return mOperand->hasSideEffects(); }
+
+ TIntermTyped *getOperand() { return mOperand; }
+ void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
+
+ bool hasDuplicateOffsets() const;
+
+ TIntermTyped *fold();
+
+ protected:
+ TIntermTyped *mOperand;
+ TVector<int> mSwizzleOffsets;
+
+ 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);
+
+ TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
+
+ static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right);
+ static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right);
+ static TQualifier GetCommaQualifier(int shaderVersion,
+ const TIntermTyped *left,
+ const TIntermTyped *right);
+
+ TIntermBinary *getAsBinaryNode() override { return this; };
+ void traverse(TIntermTraverser *it) override;
+ 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);
+
+ void setAddIndexClamp() { mAddIndexClamp = true; }
+ bool getAddIndexClamp() { return mAddIndexClamp; }
+
+ protected:
+ TIntermTyped* mLeft;
+ TIntermTyped* mRight;
+
+ // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
+ bool mAddIndexClamp;
+
+ private:
+ void promote();
+
+ TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private!
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator
+{
+ public:
+ TIntermUnary(TOperator op, TIntermTyped *operand);
+
+ TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
+
+ void traverse(TIntermTraverser *it) override;
+ TIntermUnary *getAsUnaryNode() override { return this; }
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
+
+ TIntermTyped *getOperand() { return mOperand; }
+ TIntermTyped *fold(TDiagnostics *diagnostics);
+
+ 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;
+
+ private:
+ void promote();
+
+ TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
+};
+
+class TFunctionSymbolInfo
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TFunctionSymbolInfo() : mId(0) {}
+
+ TFunctionSymbolInfo(const TFunctionSymbolInfo &) = default;
+ TFunctionSymbolInfo &operator=(const TFunctionSymbolInfo &) = default;
+
+ void setFromFunction(const TFunction &function);
+
+ void setNameObj(const TName &name) { mName = name; }
+ const TName &getNameObj() const { return mName; }
+
+ const TString &getName() const { return mName.getString(); }
+ void setName(const TString &name) { mName.setString(name); }
+ bool isMain() const { return mName.getString() == "main("; }
+
+ void setId(int functionId) { mId = functionId; }
+ int getId() const { return mId; }
+ private:
+ TName mName;
+ int mId;
+};
+
+// Node for function definitions.
+class TIntermFunctionDefinition : public TIntermTyped
+{
+ public:
+ // TODO(oetuaho@nvidia.com): See if TFunctionSymbolInfo could be added to constructor
+ // parameters.
+ TIntermFunctionDefinition(const TType &type, TIntermAggregate *parameters, TIntermBlock *body)
+ : TIntermTyped(type), mParameters(parameters), mBody(body)
+ {
+ ASSERT(parameters != nullptr);
+ ASSERT(body != nullptr);
+ }
+
+ TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *deepCopy() const override
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+ bool hasSideEffects() const override
+ {
+ UNREACHABLE();
+ return true;
+ }
+
+ TIntermAggregate *getFunctionParameters() const { return mParameters; }
+ TIntermBlock *getBody() const { return mBody; }
+
+ TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
+ const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
+
+ private:
+ TIntermAggregate *mParameters;
+ TIntermBlock *mBody;
+
+ TFunctionSymbolInfo mFunctionInfo;
+};
+
+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:
+ TIntermAggregate()
+ : TIntermOperator(EOpNull),
+ mUserDefined(false),
+ mUseEmulatedFunction(false),
+ mGotPrecisionFromChildren(false)
+ {
+ }
+ TIntermAggregate(TOperator op)
+ : TIntermOperator(op),
+ mUserDefined(false),
+ mUseEmulatedFunction(false),
+ mGotPrecisionFromChildren(false)
+ {
+ }
+ ~TIntermAggregate() { }
+
+ // Note: only supported for nodes that can be a part of an expression.
+ TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
+
+ void setOp(TOperator op) { mOp = op; }
+
+ TIntermAggregate *getAsAggregate() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ // Conservatively assume function calls and other aggregate operators have side-effects
+ bool hasSideEffects() const override { return true; }
+ TIntermTyped *fold(TDiagnostics *diagnostics);
+
+ TIntermSequence *getSequence() override { return &mSequence; }
+ const TIntermSequence *getSequence() const override { return &mSequence; }
+
+ void setUserDefined() { mUserDefined = true; }
+ bool isUserDefined() const { return mUserDefined; }
+
+ void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
+
+ bool areChildrenConstQualified();
+ void setPrecisionFromChildren();
+ void setBuiltInFunctionPrecision();
+
+ // Returns true if changing parameter precision may affect the return value.
+ bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
+
+ TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
+ const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
+
+ protected:
+ TIntermSequence mSequence;
+ bool mUserDefined; // used for user defined function names
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool mUseEmulatedFunction;
+
+ bool mGotPrecisionFromChildren;
+
+ TFunctionSymbolInfo mFunctionInfo;
+
+ private:
+ TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
+};
+
+// 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) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ // Only intended for initially building the block.
+ void appendStatement(TIntermNode *statement);
+
+ TIntermSequence *getSequence() override { return &mStatements; }
+ const TIntermSequence *getSequence() const override { return &mStatements; }
+
+ protected:
+ TIntermSequence mStatements;
+};
+
+// For ternary operators like a ? b : c.
+class TIntermTernary : public TIntermTyped
+{
+ public:
+ TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getCondition() const { return mCondition; }
+ TIntermTyped *getTrueExpression() const { return mTrueExpression; }
+ TIntermTyped *getFalseExpression() const { return mFalseExpression; }
+ TIntermTernary *getAsTernaryNode() override { return this; }
+
+ TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
+
+ bool hasSideEffects() const override
+ {
+ return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() ||
+ mFalseExpression->hasSideEffects();
+ }
+
+ static TQualifier DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression);
+
+ private:
+ TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
+
+ TIntermTyped *mCondition;
+ TIntermTyped *mTrueExpression;
+ TIntermTyped *mFalseExpression;
+};
+
+class TIntermIfElse : public TIntermNode
+{
+ public:
+ TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
+ : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
+ {
+ }
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getCondition() const { return mCondition; }
+ TIntermBlock *getTrueBlock() const { return mTrueBlock; }
+ TIntermBlock *getFalseBlock() const { return mFalseBlock; }
+ TIntermIfElse *getAsIfElseNode() override { return this; }
+
+ protected:
+ TIntermTyped *mCondition;
+ TIntermBlock *mTrueBlock;
+ TIntermBlock *mFalseBlock;
+};
+
+//
+// Switch statement.
+//
+class TIntermSwitch : public TIntermNode
+{
+ public:
+ TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
+ : TIntermNode(), mInit(init), mStatementList(statementList)
+ {
+ }
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermSwitch *getAsSwitchNode() override { return this; }
+
+ TIntermTyped *getInit() { return mInit; }
+ TIntermBlock *getStatementList() { return mStatementList; }
+ void setStatementList(TIntermBlock *statementList) { mStatementList = statementList; }
+
+ protected:
+ TIntermTyped *mInit;
+ TIntermBlock *mStatementList;
+};
+
+//
+// Case label.
+//
+class TIntermCase : public TIntermNode
+{
+ public:
+ TIntermCase(TIntermTyped *condition)
+ : TIntermNode(),
+ mCondition(condition)
+ {
+ }
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermCase *getAsCaseNode() override { return this; }
+
+ bool hasCondition() const { return mCondition != nullptr; }
+ TIntermTyped *getCondition() const { return mCondition; }
+
+ protected:
+ TIntermTyped *mCondition;
+};
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+//
+// 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 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.
+//
+// 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.
+//
+class TIntermTraverser : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
+ virtual ~TIntermTraverser();
+
+ virtual void visitSymbol(TIntermSymbol *node) {}
+ virtual void visitRaw(TIntermRaw *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 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 visitLoop(Visit visit, TIntermLoop *node) { return true; }
+ virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
+
+ // 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.
+ virtual void traverseSymbol(TIntermSymbol *node);
+ virtual void traverseRaw(TIntermRaw *node);
+ virtual void traverseConstantUnion(TIntermConstantUnion *node);
+ virtual void traverseSwizzle(TIntermSwizzle *node);
+ virtual void traverseBinary(TIntermBinary *node);
+ virtual void traverseUnary(TIntermUnary *node);
+ virtual void traverseTernary(TIntermTernary *node);
+ virtual void traverseIfElse(TIntermIfElse *node);
+ virtual void traverseSwitch(TIntermSwitch *node);
+ virtual void traverseCase(TIntermCase *node);
+ virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
+ virtual void traverseAggregate(TIntermAggregate *node);
+ virtual void traverseBlock(TIntermBlock *node);
+ virtual void traverseLoop(TIntermLoop *node);
+ virtual void traverseBranch(TIntermBranch *node);
+
+ int getMaxDepth() const { return mMaxDepth; }
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ static TString hash(const TString &name, ShHashFunction64 hashFunction);
+
+ // 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();
+
+ // Start creating temporary symbols from the given temporary symbol index + 1.
+ void useTemporaryIndex(unsigned int *temporaryIndex);
+
+ protected:
+ void incrementDepth(TIntermNode *current)
+ {
+ mDepth++;
+ mMaxDepth = std::max(mMaxDepth, mDepth);
+ mPath.push_back(current);
+ }
+
+ void decrementDepth()
+ {
+ mDepth--;
+ mPath.pop_back();
+ }
+
+ TIntermNode *getParentNode()
+ {
+ return mPath.size() == 0 ? NULL : mPath.back();
+ }
+
+ // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
+ TIntermNode *getAncestorNode(unsigned int n)
+ {
+ if (mPath.size() > n)
+ {
+ return mPath[mPath.size() - n - 1u];
+ }
+ return nullptr;
+ }
+
+ void pushParentBlock(TIntermBlock *node);
+ void incrementParentBlockPos();
+ void popParentBlock();
+
+ bool parentNodeIsBlock()
+ {
+ return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node;
+ }
+
+ // To replace a single node with multiple nodes on the parent aggregate node
+ struct NodeReplaceWithMultipleEntry
+ {
+ NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
+ TIntermNode *_original,
+ TIntermSequence _replacements)
+ : parent(_parent), original(_original), replacements(_replacements)
+ {
+ }
+
+ TIntermAggregateBase *parent;
+ TIntermNode *original;
+ TIntermSequence replacements;
+ };
+
+ // To insert multiple nodes on the parent aggregate node
+ 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;
+ };
+
+ // Helper to insert statements in the parent block (sequence) 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 from sequence nodes.
+ // Note that inserting more than one set of nodes to the same parent node on a single updateTree call is 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);
+
+ // Helper to create a temporary symbol node with the given qualifier.
+ TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
+ // Helper to create a temporary symbol node.
+ TIntermSymbol *createTempSymbol(const TType &type);
+ // Create a node that declares but doesn't initialize a temporary symbol.
+ TIntermAggregate *createTempDeclaration(const TType &type);
+ // Create a node that initializes the current temporary symbol with initializer having the given qualifier.
+ TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
+ // Create a node that initializes the current temporary symbol with initializer.
+ TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer);
+ // Create a node that assigns rightNode to the current temporary symbol.
+ TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
+ // Increment temporary symbol index.
+ void nextTemporaryIndex();
+
+ enum class OriginalNode
+ {
+ BECOMES_CHILD,
+ IS_DROPPED
+ };
+
+ void clearReplacementQueue();
+ void queueReplacement(TIntermNode *original,
+ TIntermNode *replacement,
+ OriginalNode originalStatus);
+ void queueReplacementWithParent(TIntermNode *parent,
+ TIntermNode *original,
+ TIntermNode *replacement,
+ OriginalNode originalStatus);
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+
+ int mDepth;
+ int mMaxDepth;
+
+ // All the nodes from root to the current node's parent during traversing.
+ TVector<TIntermNode *> mPath;
+
+ 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;
+ std::vector<NodeInsertMultipleEntry> mInsertions;
+
+ private:
+ // 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<NodeUpdateEntry> mReplacements;
+
+ // All the code blocks from the root to the current node's parent during traversal.
+ std::vector<ParentBlock> mParentBlockStack;
+
+ unsigned int *mTemporaryIndex;
+};
+
+// 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,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TIntermTraverser(preVisit, inVisit, postVisit),
+ mOperatorRequiresLValue(false),
+ mInFunctionCallOutParameter(false),
+ mSymbolTable(symbolTable),
+ mShaderVersion(shaderVersion)
+ {
+ }
+ virtual ~TLValueTrackingTraverser() {}
+
+ void traverseBinary(TIntermBinary *node) final;
+ void traverseUnary(TIntermUnary *node) final;
+ void traverseFunctionDefinition(TIntermFunctionDefinition *node) final;
+ void traverseAggregate(TIntermAggregate *node) final;
+
+ protected:
+ bool isLValueRequiredHere() const
+ {
+ return mOperatorRequiresLValue || mInFunctionCallOutParameter;
+ }
+
+ // Return true if the prototype or definition of the function being called has been encountered
+ // during traversal.
+ bool isInFunctionMap(const TIntermAggregate *callNode) const;
+
+ 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; }
+
+ // Add a function encountered during traversal to the function map.
+ void addToFunctionMap(const TName &name, TIntermSequence *paramSequence);
+
+ // Return the parameters sequence from the function definition or prototype.
+ TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
+
+ // Track whether an l-value is required inside a function call.
+ void setInFunctionCallOutParameter(bool inOutParameter);
+ bool isInFunctionCallOutParameter() const;
+
+ bool mOperatorRequiresLValue;
+ bool mInFunctionCallOutParameter;
+
+ struct TNameComparator
+ {
+ bool operator()(const TName &a, const TName &b) const
+ {
+ int compareResult = a.getString().compare(b.getString());
+ if (compareResult != 0)
+ return compareResult < 0;
+ // Internal functions may have same names as non-internal functions.
+ return !a.isInternal() && b.isInternal();
+ }
+ };
+
+ // Map from mangled function names to their parameter sequences
+ TMap<TName, TIntermSequence *, TNameComparator> mFunctionMap;
+
+ const TSymbolTable &mSymbolTable;
+ const int mShaderVersion;
+};
+
+//
+// For traversing the tree, and computing max depth.
+// Takes a maximum depth limit to prevent stack overflow.
+//
+class TMaxDepthTraverser : public TIntermTraverser
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TMaxDepthTraverser(int depthLimit)
+ : TIntermTraverser(true, true, false),
+ mDepthLimit(depthLimit) { }
+
+ bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
+ bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
+ bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
+ bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
+ bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
+ bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
+ bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
+ bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
+
+ protected:
+ bool depthCheck() const { return mMaxDepth < mDepthLimit; }
+
+ int mDepthLimit;
+};
+
+#endif // COMPILER_TRANSLATOR_INTERMNODE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.cpp
new file mode 100644
index 000000000..4177b05ac
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.cpp
@@ -0,0 +1,104 @@
+//
+// 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/IntermNodePatternMatcher.h"
+
+#include "compiler/translator/IntermNode.h"
+
+IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask)
+{
+}
+
+// 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(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->getOp() == EOpFunctionCall) &&
+ !parentNode->getAsBlock())
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermTernary *node)
+{
+ if ((mMask & kUnfoldedShortCircuitExpression) != 0)
+ {
+ return true;
+ }
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.h b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.h
new file mode 100644
index 000000000..3e24f8560
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNodePatternMatcher.h
@@ -0,0 +1,53 @@
+//
+// 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_INTERMNODEPATTERNMATCHER_H_
+#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
+
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermNode;
+class TIntermTernary;
+
+class IntermNodePatternMatcher
+{
+ public:
+ 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 = 0x0002,
+
+ // Matches dynamic indexing of vectors or matrices in l-values.
+ kDynamicIndexingOfVectorOrMatrixInLValue = 0x0004
+ };
+ IntermNodePatternMatcher(const unsigned int mask);
+
+ 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);
+
+ private:
+ const unsigned int mMask;
+
+ bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
+};
+
+#endif
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermTraverse.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermTraverse.cpp
new file mode 100644
index 000000000..29f81f401
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/IntermTraverse.cpp
@@ -0,0 +1,792 @@
+//
+// 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/IntermNode.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/SymbolTable.h"
+
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+ it->traverseSymbol(this);
+}
+
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+ it->traverseRaw(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+ it->traverseConstantUnion(this);
+}
+
+void TIntermSwizzle::traverse(TIntermTraverser *it)
+{
+ it->traverseSwizzle(this);
+}
+
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+ it->traverseBinary(this);
+}
+
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+ it->traverseUnary(this);
+}
+
+void TIntermTernary::traverse(TIntermTraverser *it)
+{
+ it->traverseTernary(this);
+}
+
+void TIntermIfElse::traverse(TIntermTraverser *it)
+{
+ it->traverseIfElse(this);
+}
+
+void TIntermSwitch::traverse(TIntermTraverser *it)
+{
+ it->traverseSwitch(this);
+}
+
+void TIntermCase::traverse(TIntermTraverser *it)
+{
+ it->traverseCase(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 TIntermBranch::traverse(TIntermTraverser *it)
+{
+ it->traverseBranch(this);
+}
+
+TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
+ : preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ mDepth(0),
+ mMaxDepth(0),
+ mInGlobalScope(true),
+ mTemporaryIndex(nullptr)
+{
+}
+
+TIntermTraverser::~TIntermTraverser()
+{
+}
+
+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());
+ NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
+ insertionsBefore, insertionsAfter);
+ mInsertions.push_back(insert);
+}
+
+void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
+{
+ TIntermSequence insertions;
+ insertions.push_back(statement);
+ insertStatementsInParentBlock(insertions);
+}
+
+TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
+{
+ // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
+ TInfoSinkBase symbolNameOut;
+ ASSERT(mTemporaryIndex != nullptr);
+ symbolNameOut << "s" << (*mTemporaryIndex);
+ TString symbolName = symbolNameOut.c_str();
+
+ TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
+ node->setInternal(true);
+ node->getTypePointer()->setQualifier(qualifier);
+ return node;
+}
+
+TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
+{
+ return createTempSymbol(type, EvqTemporary);
+}
+
+TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
+{
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ tempDeclaration->getSequence()->push_back(createTempSymbol(type));
+ return tempDeclaration;
+}
+
+TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
+{
+ ASSERT(initializer != nullptr);
+ TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
+ tempDeclaration->getSequence()->push_back(tempInit);
+ return tempDeclaration;
+}
+
+TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
+{
+ return createTempInitDeclaration(initializer, EvqTemporary);
+}
+
+TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
+{
+ ASSERT(rightNode != nullptr);
+ TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
+ TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
+ return assignment;
+}
+
+void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
+{
+ mTemporaryIndex = temporaryIndex;
+}
+
+void TIntermTraverser::nextTemporaryIndex()
+{
+ ASSERT(mTemporaryIndex != nullptr);
+ ++(*mTemporaryIndex);
+}
+
+void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
+{
+ mFunctionMap[name] = paramSequence;
+}
+
+bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
+{
+ ASSERT(callNode->getOp() == EOpFunctionCall);
+ return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
+ mFunctionMap.end());
+}
+
+TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
+{
+ ASSERT(isInFunctionMap(callNode));
+ return mFunctionMap[callNode->getFunctionSymbolInfo()->getNameObj()];
+}
+
+void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
+{
+ mInFunctionCallOutParameter = inOutParameter;
+}
+
+bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
+{
+ return mInFunctionCallOutParameter;
+}
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
+{
+ visitSymbol(node);
+}
+
+void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
+{
+ visitConstantUnion(node);
+}
+
+void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitSwizzle(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ node->getOperand()->traverse(this);
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitSwizzle(PostVisit, node);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermTraverser::traverseBinary(TIntermBinary *node)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if (preVisit)
+ visit = visitBinary(PreVisit, node);
+
+ //
+ // Visit the children, in the right order.
+ //
+ if (visit)
+ {
+ incrementDepth(node);
+
+ if (node->getLeft())
+ node->getLeft()->traverse(this);
+
+ if (inVisit)
+ visit = visitBinary(InVisit, node);
+
+ if (visit && node->getRight())
+ node->getRight()->traverse(this);
+
+ decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if (visit && postVisit)
+ visitBinary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if (preVisit)
+ visit = visitBinary(PreVisit, node);
+
+ //
+ // Visit the children, in the right order.
+ //
+ if (visit)
+ {
+ incrementDepth(node);
+
+ // Some binary operations like indexing can be inside an expression which must be an
+ // l-value.
+ bool parentOperatorRequiresLValue = operatorRequiresLValue();
+ bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
+ if (node->isAssignment())
+ {
+ ASSERT(!isLValueRequiredHere());
+ setOperatorRequiresLValue(true);
+ }
+
+ if (node->getLeft())
+ node->getLeft()->traverse(this);
+
+ if (inVisit)
+ visit = visitBinary(InVisit, node);
+
+ if (node->isAssignment())
+ setOperatorRequiresLValue(false);
+
+ // 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);
+ }
+
+ if (visit && node->getRight())
+ node->getRight()->traverse(this);
+
+ setOperatorRequiresLValue(parentOperatorRequiresLValue);
+ setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
+
+ decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if (visit && postVisit)
+ visitBinary(PostVisit, node);
+}
+
+//
+// Traverse a unary node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseUnary(TIntermUnary *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitUnary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ node->getOperand()->traverse(this);
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitUnary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitUnary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ ASSERT(!operatorRequiresLValue());
+ switch (node->getOp())
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ setOperatorRequiresLValue(true);
+ break;
+ default:
+ break;
+ }
+
+ node->getOperand()->traverse(this);
+
+ setOperatorRequiresLValue(false);
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitUnary(PostVisit, node);
+}
+
+// Traverse a function definition node.
+void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitFunctionDefinition(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ mInGlobalScope = false;
+
+ node->getFunctionParameters()->traverse(this);
+ if (inVisit)
+ visit = visitFunctionDefinition(InVisit, node);
+ node->getBody()->traverse(this);
+
+ mInGlobalScope = true;
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitFunctionDefinition(PostVisit, node);
+}
+
+// Traverse a block node.
+void TIntermTraverser::traverseBlock(TIntermBlock *node)
+{
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = visitBlock(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ pushParentBlock(node);
+
+ for (auto *child : *sequence)
+ {
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitBlock(InVisit, node);
+ }
+
+ incrementParentBlockPos();
+ }
+
+ popParentBlock();
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitBlock(PostVisit, node);
+}
+
+// Traverse an aggregate node. Same comments in binary node apply here.
+void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
+{
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = visitAggregate(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ for (auto *child : *sequence)
+ {
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+ }
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitAggregate(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
+{
+ TIntermAggregate *params = node->getFunctionParameters();
+ ASSERT(params != nullptr);
+ ASSERT(params->getOp() == EOpParameters);
+ addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), params->getSequence());
+
+ TIntermTraverser::traverseFunctionDefinition(node);
+}
+
+void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
+{
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+ if (node->getOp() == EOpPrototype)
+ {
+ addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
+ }
+
+ if (preVisit)
+ visit = visitAggregate(PreVisit, node);
+
+ if (visit)
+ {
+ bool inFunctionMap = false;
+ if (node->getOp() == EOpFunctionCall)
+ {
+ inFunctionMap = isInFunctionMap(node);
+ if (!inFunctionMap)
+ {
+ // The function is not user-defined - it is likely built-in texture function.
+ // Assume that those do not have out parameters.
+ setInFunctionCallOutParameter(false);
+ }
+ }
+
+ incrementDepth(node);
+
+ if (inFunctionMap)
+ {
+ TIntermSequence *params = getFunctionParameters(node);
+ TIntermSequence::iterator paramIter = params->begin();
+ for (auto *child : *sequence)
+ {
+ ASSERT(paramIter != params->end());
+ TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+
+ ++paramIter;
+ }
+
+ setInFunctionCallOutParameter(false);
+ }
+ else
+ {
+ // Find the built-in function corresponding to this op so that we can determine the
+ // in/out qualifiers of its parameters.
+ TFunction *builtInFunc = nullptr;
+ TString opString = GetOperatorString(node->getOp());
+ if (!node->isConstructor() && !opString.empty())
+ {
+ // The return type doesn't affect the mangled name of the function, which is used
+ // to look it up from the symbol table.
+ TType dummyReturnType;
+ TFunction call(&opString, &dummyReturnType, node->getOp());
+ for (auto *child : *sequence)
+ {
+ TType *paramType = child->getAsTyped()->getTypePointer();
+ TConstParameter p(paramType);
+ call.addParameter(p);
+ }
+
+ TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
+ if (sym != nullptr && sym->isFunction())
+ {
+ builtInFunc = static_cast<TFunction *>(sym);
+ ASSERT(builtInFunc->getParamCount() == sequence->size());
+ }
+ }
+
+ size_t paramIndex = 0;
+
+ for (auto *child : *sequence)
+ {
+ TQualifier qualifier = EvqIn;
+ if (builtInFunc != nullptr)
+ qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+ child->traverse(this);
+
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+
+ ++paramIndex;
+ }
+
+ setInFunctionCallOutParameter(false);
+ }
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitAggregate(PostVisit, node);
+}
+
+//
+// Traverse a ternary node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseTernary(TIntermTernary *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitTernary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ node->getCondition()->traverse(this);
+ if (node->getTrueExpression())
+ node->getTrueExpression()->traverse(this);
+ if (node->getFalseExpression())
+ node->getFalseExpression()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitTernary(PostVisit, node);
+}
+
+// Traverse an if-else node. Same comments in binary node apply here.
+void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitIfElse(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ node->getCondition()->traverse(this);
+ if (node->getTrueBlock())
+ node->getTrueBlock()->traverse(this);
+ if (node->getFalseBlock())
+ node->getFalseBlock()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitIfElse(PostVisit, node);
+}
+
+//
+// Traverse a switch node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitSwitch(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ node->getInit()->traverse(this);
+ if (inVisit)
+ visit = visitSwitch(InVisit, node);
+ if (visit && node->getStatementList())
+ node->getStatementList()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitSwitch(PostVisit, node);
+}
+
+//
+// Traverse a case node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseCase(TIntermCase *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitCase(PreVisit, node);
+
+ if (visit && node->getCondition())
+ {
+ incrementDepth(node);
+ node->getCondition()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitCase(PostVisit, node);
+}
+
+//
+// Traverse a loop node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseLoop(TIntermLoop *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitLoop(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ if (node->getInit())
+ node->getInit()->traverse(this);
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+
+ if (node->getBody())
+ node->getBody()->traverse(this);
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitLoop(PostVisit, node);
+}
+
+//
+// Traverse a branch node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseBranch(TIntermBranch *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitBranch(PreVisit, node);
+
+ if (visit && node->getExpression())
+ {
+ incrementDepth(node);
+ node->getExpression()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitBranch(PostVisit, node);
+}
+
+void TIntermTraverser::traverseRaw(TIntermRaw *node)
+{
+ visitRaw(node);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.cpp
new file mode 100644
index 000000000..8e6519dd6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.cpp
@@ -0,0 +1,382 @@
+//
+// 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 <algorithm>
+
+#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/SymbolTable.h"
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol *TIntermediate::addSymbol(
+ int id, const TString &name, const TType &type, const TSourceLoc &line)
+{
+ TIntermSymbol *node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped *TIntermediate::addIndex(TOperator op,
+ TIntermTyped *base,
+ TIntermTyped *index,
+ const TSourceLoc &line,
+ TDiagnostics *diagnostics)
+{
+ TIntermBinary *node = new TIntermBinary(op, base, index);
+ node->setLine(line);
+
+ TIntermTyped *folded = node->fold(diagnostics);
+ if (folded)
+ {
+ return folded;
+ }
+
+ return node;
+}
+
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate but no operator was set.
+TIntermAggregate *TIntermediate::setAggregateOperator(
+ TIntermNode *node, TOperator op, const TSourceLoc &line)
+{
+ TIntermAggregate *aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node)
+ {
+ aggNode = node->getAsAggregate();
+ if (aggNode == NULL || aggNode->getOp() != EOpNull)
+ {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence()->push_back(node);
+ }
+ }
+ else
+ {
+ aggNode = new TIntermAggregate();
+ }
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate *TIntermediate::growAggregate(
+ TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
+{
+ if (left == NULL && right == NULL)
+ return NULL;
+
+ TIntermAggregate *aggNode = NULL;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull)
+ {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence()->push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence()->push_back(right);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless NULL was passed in for the existing node.
+//
+TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceLoc &line)
+{
+ if (node == nullptr)
+ return nullptr;
+
+ TIntermAggregate *aggNode = new TIntermAggregate;
+ aggNode->getSequence()->push_back(node);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+// 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 *TIntermediate::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->getSequence()->push_back(node);
+ return blockNode;
+}
+
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the node created.
+TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
+ TIntermNodePair nodePair,
+ const TSourceLoc &line)
+{
+ // For compile time constant conditions, prune the code now.
+
+ if (cond->getAsConstantUnion())
+ {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ {
+ return EnsureBlock(nodePair.node1);
+ }
+ else
+ {
+ return EnsureBlock(nodePair.node2);
+ }
+ }
+
+ TIntermIfElse *node =
+ new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &line,
+ int shaderVersion)
+{
+ TIntermTyped *commaNode = nullptr;
+ if (!left->hasSideEffects())
+ {
+ commaNode = right;
+ }
+ else
+ {
+ commaNode = new TIntermBinary(EOpComma, left, right);
+ commaNode->setLine(line);
+ }
+ TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
+ commaNode->getTypePointer()->setQualifier(resultQualifier);
+ return commaNode;
+}
+
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
+// could be folded.
+TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line)
+{
+ // Note that the node resulting from here can be a constant union without being qualified as
+ // constant.
+ if (cond->getAsConstantUnion())
+ {
+ TQualifier resultQualifier =
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
+ if (cond->getAsConstantUnion()->getBConst(0))
+ {
+ trueExpression->getTypePointer()->setQualifier(resultQualifier);
+ return trueExpression;
+ }
+ else
+ {
+ falseExpression->getTypePointer()->setQualifier(resultQualifier);
+ return falseExpression;
+ }
+ }
+
+ // Make a ternary node.
+ TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
+ TIntermBlock *statementList,
+ const TSourceLoc &line)
+{
+ TIntermSwitch *node = new TIntermSwitch(init, statementList);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermCase *TIntermediate::addCase(
+ TIntermTyped *condition, const TSourceLoc &line)
+{
+ TIntermCase *node = new TIntermCase(condition);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
+ const TType &type,
+ const TSourceLoc &line)
+{
+ TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
+ const TVectorFields &fields,
+ const TSourceLoc &dotLocation)
+{
+ TVector<int> fieldsVector;
+ for (int i = 0; i < fields.num; ++i)
+ {
+ fieldsVector.push_back(fields.offsets[i]);
+ }
+ TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
+ node->setLine(dotLocation);
+
+ TIntermTyped *folded = node->fold();
+ if (folded)
+ {
+ return folded;
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode *TIntermediate::addLoop(
+ TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
+ TIntermNode *body, const TSourceLoc &line)
+{
+ TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(
+ TOperator branchOp, const TSourceLoc &line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(
+ TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
+{
+ TIntermBranch *node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
+{
+ switch (aggregate->getOp())
+ {
+ case EOpAtan:
+ case EOpPow:
+ case EOpMod:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpMul:
+ case EOpOuterProduct:
+ case EOpLessThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThan:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ return aggregate->fold(diagnostics);
+ default:
+ // TODO: Add support for folding array constructors
+ if (aggregate->isConstructor() && !aggregate->isArray())
+ {
+ return aggregate->fold(diagnostics);
+ }
+ // Constant folding not supported for the built-in.
+ return nullptr;
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.h
new file mode 100644
index 000000000..a4fb7cc9e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Intermediate.h
@@ -0,0 +1,74 @@
+//
+// 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_INTERMEDIATE_H_
+#define COMPILER_TRANSLATOR_INTERMEDIATE_H_
+
+#include "compiler/translator/IntermNode.h"
+
+struct TVectorFields
+{
+ int offsets[4];
+ int num;
+};
+
+//
+// Set of helper functions to help build the tree.
+//
+class TIntermediate
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermediate() {}
+
+ TIntermSymbol *addSymbol(
+ int id, const TString &, const TType &, const TSourceLoc &);
+ TIntermTyped *addIndex(TOperator op,
+ TIntermTyped *base,
+ TIntermTyped *index,
+ const TSourceLoc &line,
+ TDiagnostics *diagnostics);
+ TIntermTyped *addUnaryMath(
+ TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
+ TIntermAggregate *growAggregate(
+ TIntermNode *left, TIntermNode *right, const TSourceLoc &);
+ static TIntermAggregate *MakeAggregate(TIntermNode *node, const TSourceLoc &line);
+ static TIntermBlock *EnsureBlock(TIntermNode *node);
+ TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
+ TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
+ static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line);
+ TIntermSwitch *addSwitch(TIntermTyped *init,
+ TIntermBlock *statementList,
+ const TSourceLoc &line);
+ TIntermCase *addCase(
+ TIntermTyped *condition, const TSourceLoc &line);
+ static TIntermTyped *AddComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &line,
+ int shaderVersion);
+ TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
+ const TType &type,
+ const TSourceLoc &line);
+ TIntermNode *addLoop(TLoopType, TIntermNode *, TIntermTyped *, TIntermTyped *,
+ TIntermNode *, const TSourceLoc &);
+ TIntermBranch *addBranch(TOperator, const TSourceLoc &);
+ TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
+ static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression,
+ const TVectorFields &fields,
+ const TSourceLoc &dotLocation);
+
+ static void outputTree(TIntermNode *, TInfoSinkBase &);
+
+ TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
+
+ private:
+ void operator=(TIntermediate &); // prevent assignments
+};
+
+#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.cpp
new file mode 100644
index 000000000..d931a18a2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.cpp
@@ -0,0 +1,211 @@
+//
+// 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/LoopInfo.h"
+
+namespace
+{
+
+int EvaluateIntConstant(TIntermConstantUnion *node)
+{
+ ASSERT(node && node->getUnionArrayPointer());
+ return node->getIConst(0);
+}
+
+int GetLoopIntIncrement(TIntermLoop *node)
+{
+ TIntermNode *expr = node->getExpression();
+ // 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 ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermConstantUnion *incrementNode = NULL;
+ if (unOp)
+ {
+ op = unOp->getOp();
+ }
+ else if (binOp)
+ {
+ op = binOp->getOp();
+ ASSERT(binOp->getRight());
+ incrementNode = binOp->getRight()->getAsConstantUnion();
+ ASSERT(incrementNode);
+ }
+
+ int increment = 0;
+ // The operator is one of: ++ -- += -=.
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ ASSERT(unOp && !binOp);
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ ASSERT(unOp && !binOp);
+ increment = -1;
+ break;
+ case EOpAddAssign:
+ ASSERT(!unOp && binOp);
+ increment = EvaluateIntConstant(incrementNode);
+ break;
+ case EOpSubAssign:
+ ASSERT(!unOp && binOp);
+ increment = - EvaluateIntConstant(incrementNode);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return increment;
+}
+
+} // namespace anonymous
+
+TLoopIndexInfo::TLoopIndexInfo()
+ : mId(-1),
+ mType(EbtVoid),
+ mInitValue(0),
+ mStopValue(0),
+ mIncrementValue(0),
+ mOp(EOpNull),
+ mCurrentValue(0)
+{
+}
+
+void TLoopIndexInfo::fillInfo(TIntermLoop *node)
+{
+ if (node == NULL)
+ return;
+
+ // Here we assume all the operations are valid, because the loop node is
+ // already validated in ValidateLimitations.
+ TIntermSequence *declSeq =
+ node->getInit()->getAsAggregate()->getSequence();
+ TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+
+ mId = symbol->getId();
+ mType = symbol->getBasicType();
+
+ if (mType == EbtInt)
+ {
+ TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
+ mInitValue = EvaluateIntConstant(initNode);
+ mCurrentValue = mInitValue;
+ mIncrementValue = GetLoopIntIncrement(node);
+
+ TIntermBinary* binOp = node->getCondition()->getAsBinaryNode();
+ mStopValue = EvaluateIntConstant(
+ binOp->getRight()->getAsConstantUnion());
+ mOp = binOp->getOp();
+ }
+}
+
+bool TLoopIndexInfo::satisfiesLoopCondition() const
+{
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (mOp)
+ {
+ case EOpEqual:
+ return (mCurrentValue == mStopValue);
+ case EOpNotEqual:
+ return (mCurrentValue != mStopValue);
+ case EOpLessThan:
+ return (mCurrentValue < mStopValue);
+ case EOpGreaterThan:
+ return (mCurrentValue > mStopValue);
+ case EOpLessThanEqual:
+ return (mCurrentValue <= mStopValue);
+ case EOpGreaterThanEqual:
+ return (mCurrentValue >= mStopValue);
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+TLoopInfo::TLoopInfo()
+ : loop(NULL)
+{
+}
+
+TLoopInfo::TLoopInfo(TIntermLoop *node)
+ : loop(node)
+{
+ index.fillInfo(node);
+}
+
+TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol)
+{
+ if (!symbol)
+ return NULL;
+ for (iterator iter = begin(); iter != end(); ++iter)
+ {
+ if (iter->index.getId() == symbol->getId())
+ return iter->loop;
+ }
+ return NULL;
+}
+
+TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol)
+{
+ if (!symbol)
+ return NULL;
+ for (iterator iter = begin(); iter != end(); ++iter)
+ {
+ if (iter->index.getId() == symbol->getId())
+ return &(iter->index);
+ }
+ return NULL;
+}
+
+void TLoopStack::step()
+{
+ ASSERT(!empty());
+ rbegin()->index.step();
+}
+
+bool TLoopStack::satisfiesLoopCondition()
+{
+ ASSERT(!empty());
+ return rbegin()->index.satisfiesLoopCondition();
+}
+
+bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol)
+{
+ TIntermLoop *loop = findLoop(symbol);
+ return loop && loop->getUnrollFlag();
+}
+
+int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol)
+{
+ TLoopIndexInfo *info = getIndexInfo(symbol);
+ ASSERT(info);
+ return info->getCurrentValue();
+}
+
+void TLoopStack::push(TIntermLoop *loop)
+{
+ TLoopInfo info(loop);
+ push_back(info);
+}
+
+void TLoopStack::pop()
+{
+ pop_back();
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.h b/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.h
new file mode 100644
index 000000000..ec73fd0fa
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/LoopInfo.h
@@ -0,0 +1,80 @@
+//
+// 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_LOOPINFO_H_
+#define COMPILER_TRANSLATOR_LOOPINFO_H_
+
+#include "compiler/translator/IntermNode.h"
+
+class TLoopIndexInfo
+{
+ public:
+ TLoopIndexInfo();
+
+ // If type is EbtInt, fill all fields of the structure with info
+ // extracted from a loop node.
+ // If type is not EbtInt, only fill id and type.
+ void fillInfo(TIntermLoop *node);
+
+ int getId() const { return mId; }
+ void setId(int id) { mId = id; }
+ TBasicType getType() const { return mType; }
+ void setType(TBasicType type) { mType = type; }
+ int getCurrentValue() const { return mCurrentValue; }
+
+ void step() { mCurrentValue += mIncrementValue; }
+
+ // Check if the current value satisfies the loop condition.
+ bool satisfiesLoopCondition() const;
+
+ private:
+ int mId;
+ TBasicType mType; // Either EbtInt or EbtFloat
+
+ // Below fields are only valid if the index's type is int.
+ int mInitValue;
+ int mStopValue;
+ int mIncrementValue;
+ TOperator mOp;
+ int mCurrentValue;
+};
+
+struct TLoopInfo
+{
+ TLoopIndexInfo index;
+ TIntermLoop *loop;
+
+ TLoopInfo();
+ TLoopInfo(TIntermLoop *node);
+};
+
+class TLoopStack : public TVector<TLoopInfo>
+{
+ public:
+ // Search loop stack for a loop whose index matches the input symbol.
+ TIntermLoop *findLoop(TIntermSymbol *symbol);
+
+ // Find the loop index info in the loop stack by the input symbol.
+ TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol);
+
+ // Update the currentValue for the next loop iteration.
+ void step();
+
+ // Return false if loop condition is no longer satisfied.
+ bool satisfiesLoopCondition();
+
+ // Check if the symbol is the index of a loop that's unrolled.
+ bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol);
+
+ // Return the current value of a given loop index symbol.
+ int getLoopIndexValue(TIntermSymbol *symbol);
+
+ void push(TIntermLoop *info);
+ void pop();
+};
+
+#endif // COMPILER_TRANSLATOR_LOOPINFO_H_
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MMap.h b/Source/ThirdParty/ANGLE/src/compiler/translator/MMap.h
index a30867151..fca843992 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/MMap.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/MMap.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef _MMAP_INCLUDED_
-#define _MMAP_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_MMAP_H_
+#define COMPILER_TRANSLATOR_MMAP_H_
//
// Encapsulate memory mapped files
@@ -53,4 +53,4 @@ private:
char* fBuff; // the actual data;
};
-#endif // _MMAP_INCLUDED_
+#endif // COMPILER_TRANSLATOR_MMAP_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/NodeSearch.h b/Source/ThirdParty/ANGLE/src/compiler/translator/NodeSearch.h
index 27e471dbb..b13b1baab 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/NodeSearch.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/NodeSearch.h
@@ -6,8 +6,10 @@
// NodeSearch.h: Utilities for searching translator node graphs
//
-#ifndef TRANSLATOR_NODESEARCH_H_
-#define TRANSLATOR_NODESEARCH_H_
+#ifndef COMPILER_TRANSLATOR_NODESEARCH_H_
+#define COMPILER_TRANSLATOR_NODESEARCH_H_
+
+#include "compiler/translator/IntermNode.h"
namespace sh
{
@@ -17,7 +19,8 @@ class NodeSearchTraverser : public TIntermTraverser
{
public:
NodeSearchTraverser()
- : mFound(false)
+ : TIntermTraverser(true, false, false),
+ mFound(false)
{}
bool found() const { return mFound; }
@@ -51,28 +54,6 @@ class FindDiscard : public NodeSearchTraverser<FindDiscard>
}
};
-class FindSideEffectRewriting : public NodeSearchTraverser<FindSideEffectRewriting>
-{
- public:
- virtual bool visitBinary(Visit visit, TIntermBinary *node)
- {
- switch (node->getOp())
- {
- case EOpLogicalOr:
- case EOpLogicalAnd:
- if (node->getRight()->hasSideEffects())
- {
- mFound = true;
- }
- break;
-
- default: break;
- }
-
- return !mFound;
- }
-};
-
}
-#endif // TRANSLATOR_NODESEARCH_H_
+#endif // COMPILER_TRANSLATOR_NODESEARCH_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.cpp
new file mode 100644
index 000000000..0b693e2d0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.cpp
@@ -0,0 +1,227 @@
+//
+// 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: ops from EOpNull to EOpPrototype can't be handled here.
+
+ case EOpNegative: return "-";
+ case EOpPositive: return "+";
+ case EOpLogicalNot: return "!";
+ case EOpVectorLogicalNot: return "not";
+ case EOpBitwiseNot: return "~";
+
+ case EOpPostIncrement: return "++";
+ case EOpPostDecrement: return "--";
+ case EOpPreIncrement: return "++";
+ case EOpPreDecrement: return "--";
+
+ case EOpAdd: return "+";
+ case EOpSub: return "-";
+ case EOpMul: return "*";
+ case EOpDiv: return "/";
+ case EOpIMod: return "%";
+ case EOpEqual: return "==";
+ case EOpNotEqual: return "!=";
+ case EOpVectorEqual: return "equal";
+ case EOpVectorNotEqual: return "notEqual";
+ case EOpLessThan: return "<";
+ case EOpGreaterThan: return ">";
+ case EOpLessThanEqual: return "<=";
+ case EOpGreaterThanEqual: return ">=";
+ case EOpComma: return ",";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar: 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 EOpPackSnorm2x16: return "packSnorm2x16";
+ case EOpPackUnorm2x16: return "packUnorm2x16";
+ case EOpPackHalf2x16: return "packHalf2x16";
+ case EOpUnpackSnorm2x16: return "unpackSnorm2x16";
+ case EOpUnpackUnorm2x16: return "unpackUnorm2x16";
+ case EOpUnpackHalf2x16: return "unpackHalf2x16";
+
+ 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 EOpMatrixTimesMatrix: return "*";
+
+ 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 EOpKill: return "kill";
+ case EOpReturn: return "return";
+ case EOpBreak: return "break";
+ case EOpContinue: return "continue";
+
+ case EOpConstructInt: return "int";
+ case EOpConstructUInt: return "uint";
+ case EOpConstructBool: return "bool";
+ case EOpConstructFloat: return "float";
+ case EOpConstructVec2: return "vec2";
+ case EOpConstructVec3: return "vec3";
+ case EOpConstructVec4: return "vec4";
+ case EOpConstructBVec2: return "bvec2";
+ case EOpConstructBVec3: return "bvec3";
+ case EOpConstructBVec4: return "bvec4";
+ case EOpConstructIVec2: return "ivec2";
+ case EOpConstructIVec3: return "ivec3";
+ case EOpConstructIVec4: return "ivec4";
+ case EOpConstructUVec2: return "uvec2";
+ case EOpConstructUVec3: return "uvec3";
+ case EOpConstructUVec4: return "uvec4";
+ case EOpConstructMat2: return "mat2";
+ case EOpConstructMat2x3: return "mat2x3";
+ case EOpConstructMat2x4: return "mat2x4";
+ case EOpConstructMat3x2: return "mat3x2";
+ case EOpConstructMat3: return "mat3";
+ case EOpConstructMat3x4: return "mat3x4";
+ case EOpConstructMat4x2: return "mat4x2";
+ case EOpConstructMat4x3: return "mat4x3";
+ case EOpConstructMat4: return "mat4";
+ // Note: EOpConstructStruct can't be handled here
+
+ 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 "|=";
+
+ 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;
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.h
new file mode 100644
index 000000000..42c5c6322
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Operator.h
@@ -0,0 +1,230 @@
+//
+// 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
+ EOpFunctionCall,
+ EOpParameters, // an aggregate listing the parameters to a function
+
+ EOpDeclaration,
+ EOpInvariantDeclaration, // Specialized declarations for attributing invariance
+ EOpPrototype,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpPositive,
+ EOpLogicalNot,
+ EOpVectorLogicalNot,
+ EOpBitwiseNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ //
+ // binary operations
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpIMod,
+ EOpEqual,
+ EOpNotEqual,
+ EOpVectorEqual,
+ EOpVectorNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpBitShiftLeft,
+ EOpBitShiftRight,
+
+ EOpBitwiseAnd,
+ EOpBitwiseXor,
+ EOpBitwiseOr,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+ EOpIndexDirectInterfaceBlock,
+
+ //
+ // Built-in functions potentially mapped to operators
+ //
+
+ 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,
+
+ EOpPackSnorm2x16,
+ EOpPackUnorm2x16,
+ EOpPackHalf2x16,
+ EOpUnpackSnorm2x16,
+ EOpUnpackUnorm2x16,
+ EOpUnpackHalf2x16,
+
+ 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
+
+ EOpMatrixTimesMatrix,
+
+ EOpOuterProduct,
+ EOpTranspose,
+ EOpDeterminant,
+ EOpInverse,
+
+ EOpAny,
+ EOpAll,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructors
+ //
+
+ EOpConstructInt,
+ EOpConstructUInt,
+ EOpConstructBool,
+ EOpConstructFloat,
+ EOpConstructVec2,
+ EOpConstructVec3,
+ EOpConstructVec4,
+ EOpConstructBVec2,
+ EOpConstructBVec3,
+ EOpConstructBVec4,
+ EOpConstructIVec2,
+ EOpConstructIVec3,
+ EOpConstructIVec4,
+ EOpConstructUVec2,
+ EOpConstructUVec3,
+ EOpConstructUVec4,
+ EOpConstructMat2,
+ EOpConstructMat2x3,
+ EOpConstructMat2x4,
+ EOpConstructMat3x2,
+ EOpConstructMat3,
+ EOpConstructMat3x4,
+ EOpConstructMat4x2,
+ EOpConstructMat4x3,
+ EOpConstructMat4,
+ EOpConstructStruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+
+ EOpDivAssign,
+ EOpIModAssign,
+ EOpBitShiftLeftAssign,
+ EOpBitShiftRightAssign,
+ EOpBitwiseAndAssign,
+ EOpBitwiseXorAssign,
+ EOpBitwiseOrAssign
+};
+
+// 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);
+
+#endif // COMPILER_TRANSLATOR_OPERATOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.cpp
new file mode 100644
index 000000000..77e0a8fb3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.cpp
@@ -0,0 +1,38 @@
+//
+// 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"
+
+TOutputESSL::TOutputESSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable &symbolTable,
+ int shaderVersion,
+ bool forceHighp)
+ : TOutputGLSLBase(objSink,
+ clampingStrategy,
+ hashFunction,
+ nameMap,
+ symbolTable,
+ shaderVersion,
+ SH_ESSL_OUTPUT),
+ 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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.h
new file mode 100644
index 000000000..c5a963499
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputESSL.h
@@ -0,0 +1,30 @@
+//
+// 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"
+
+class TOutputESSL : public TOutputGLSLBase
+{
+public:
+ TOutputESSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion,
+ bool forceHighp);
+
+protected:
+ bool writeVariablePrecision(TPrecision precision) override;
+
+private:
+ bool mForceHighp;
+};
+
+#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.cpp
new file mode 100644
index 000000000..431425020
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.cpp
@@ -0,0 +1,102 @@
+//
+// 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"
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion,
+ ShShaderOutput output)
+ : TOutputGLSLBase(objSink,
+ clampingStrategy,
+ hashFunction,
+ nameMap,
+ symbolTable,
+ shaderVersion,
+ output)
+{
+}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase& out = objSink();
+
+ const TString &symbol = node->getSymbol();
+ if (symbol == "gl_FragDepthEXT")
+ {
+ out << "gl_FragDepth";
+ }
+ else if (symbol == "gl_FragColor" && IsGLSL130OrNewer(getShaderOutput()))
+ {
+ out << "webgl_FragColor";
+ }
+ else if (symbol == "gl_FragData" && IsGLSL130OrNewer(getShaderOutput()))
+ {
+ out << "webgl_FragData";
+ }
+ else if (symbol == "gl_SecondaryFragColorEXT")
+ {
+ out << "angle_SecondaryFragColor";
+ }
+ else if (symbol == "gl_SecondaryFragDataEXT")
+ {
+ out << "angle_SecondaryFragData";
+ }
+ else
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ }
+}
+
+TString TOutputGLSL::translateTextureFunction(TString &name)
+{
+ static const char *simpleRename[] = {
+ "texture2DLodEXT", "texture2DLod",
+ "texture2DProjLodEXT", "texture2DProjLod",
+ "textureCubeLodEXT", "textureCubeLod",
+ "texture2DGradEXT", "texture2DGradARB",
+ "texture2DProjGradEXT", "texture2DProjGradARB",
+ "textureCubeGradEXT", "textureCubeGradARB",
+ NULL, NULL
+ };
+ static const char *legacyToCoreRename[] = {
+ "texture2D", "texture",
+ "texture2DProj", "textureProj",
+ "texture2DLod", "textureLod",
+ "texture2DProjLod", "textureProjLod",
+ "texture2DRect", "texture",
+ "textureCube", "texture",
+ "textureCubeLod", "textureLod",
+ // Extensions
+ "texture2DLodEXT", "textureLod",
+ "texture2DProjLodEXT", "textureProjLod",
+ "textureCubeLodEXT", "textureLod",
+ "texture2DGradEXT", "textureGrad",
+ "texture2DProjGradEXT", "textureProjGrad",
+ "textureCubeGradEXT", "textureGrad",
+ NULL, NULL
+ };
+ const char **mapping = (IsGLSL130OrNewer(getShaderOutput())) ?
+ legacyToCoreRename : simpleRename;
+
+ for (int i = 0; mapping[i] != NULL; i += 2)
+ {
+ if (name == mapping[i])
+ {
+ return mapping[i+1];
+ }
+ }
+
+ return name;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.h
new file mode 100644
index 000000000..9b1aca4ea
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSL.h
@@ -0,0 +1,29 @@
+//
+// 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"
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+ public:
+ TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion,
+ ShShaderOutput output);
+
+ protected:
+ bool writeVariablePrecision(TPrecision) override;
+ void visitSymbol(TIntermSymbol *node) override;
+ TString translateTextureFunction(TString &name) override;
+};
+
+#endif // COMPILER_TRANSLATOR_OUTPUTGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.cpp
new file mode 100644
index 000000000..430155961
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.cpp
@@ -0,0 +1,1264 @@
+//
+// 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 "common/debug.h"
+
+#include <cfloat>
+
+namespace
+{
+TString arrayBrackets(const TType &type)
+{
+ ASSERT(type.isArray());
+ TInfoSinkBase out;
+ out << "[" << type.getArraySize() << "]";
+ return TString(out.c_str());
+}
+
+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;
+ }
+ return true;
+}
+
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable &symbolTable,
+ int shaderVersion,
+ ShShaderOutput output)
+ : TIntermTraverser(true, true, true),
+ mObjSink(objSink),
+ mDeclaringVariables(false),
+ mClampingStrategy(clampingStrategy),
+ mHashFunction(hashFunction),
+ mNameMap(nameMap),
+ mSymbolTable(symbolTable),
+ mShaderVersion(shaderVersion),
+ mOutput(output)
+{
+}
+
+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, const char *preStr, bool useEmulatedFunction)
+{
+ TString preString = useEmulatedFunction ?
+ BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
+ writeTriplet(visit, preString.c_str(), ", ", ")");
+}
+
+void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
+{
+ if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
+ {
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+ if (layoutQualifier.location >= 0)
+ {
+ TInfoSinkBase &out = objSink();
+ out << "layout(location = " << layoutQualifier.location << ") ";
+ }
+ }
+}
+
+void TOutputGLSLBase::writeVariableType(const TType &type)
+{
+ TInfoSinkBase &out = objSink();
+ if (type.isInvariant())
+ {
+ out << "invariant ";
+ }
+ if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlockLayout(interfaceBlock);
+ }
+ TQualifier qualifier = type.getQualifier();
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ {
+ if (IsGLSL130OrNewer(mOutput))
+ {
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ out << "in ";
+ break;
+ case EvqVaryingIn:
+ out << "in ";
+ break;
+ case EvqVaryingOut:
+ out << "out ";
+ break;
+ default:
+ out << type.getQualifierString() << " ";
+ break;
+ }
+ }
+ else
+ {
+ out << type.getQualifierString() << " ";
+ }
+ }
+ // Declare the struct if we have not done so already.
+ if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
+ {
+ TStructure *structure = type.getStruct();
+
+ declareStruct(structure);
+
+ if (!structure->name().empty())
+ {
+ mDeclaredStructs.insert(structure->uniqueId());
+ }
+ }
+ else if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlock(interfaceBlock);
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
+{
+ TInfoSinkBase &out = objSink();
+ for (TIntermSequence::const_iterator iter = args.begin();
+ iter != args.end(); ++iter)
+ {
+ const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
+ ASSERT(arg != NULL);
+
+ const TType &type = arg->getType();
+ writeVariableType(type);
+
+ const TString &name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << hashName(name);
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ // Put a comma if this is not the last argument.
+ if (iter != args.end() - 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->name()) << "(";
+
+ const TFieldList &fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TType *fieldType = fields[i]->type();
+ ASSERT(fieldType != NULL);
+ 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:
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
+ break;
+ case EbtInt:
+ out << pConstUnion->getIConst();
+ break;
+ case EbtUInt:
+ out << pConstUnion->getUConst() << "u";
+ break;
+ case EbtBool:
+ out << pConstUnion->getBConst();
+ 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 << arrayBrackets(type);
+ out << "(";
+ }
+ else
+ {
+ out << getTypeName(type) << "(";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, ", ", ")");
+ }
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
+ out << mLoopUnrollStack.getLoopIndexValue(node);
+ else
+ out << hashVariableName(node->getSymbol());
+
+ if (mDeclaringVariables && node->getType().isArray())
+ out << arrayBrackets(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+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.
+ mDeclaringVariables = 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, NULL, "[", "]");
+ 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)
+ {
+ int maxSize;
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (left->isArray())
+ {
+ // The shader will fail validation if the array length is not > 0.
+ maxSize = static_cast<int>(leftType.getArraySize()) - 1;
+ }
+ else
+ {
+ maxSize = leftType.getNominalSize() - 1;
+ }
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "), 0.0, float(" << maxSize << ")))]";
+ else
+ out << ", 0, " << maxSize << ")]";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, NULL, "[", "]");
+ }
+ 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)];
+
+ TString fieldName = field->name();
+ if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ 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)];
+
+ TString fieldName = field->name();
+ ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ 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)
+{
+ TString preString;
+ TString postString = ")";
+
+ switch (node->getOp())
+ {
+ case EOpNegative: preString = "(-"; break;
+ case EOpPositive: preString = "(+"; break;
+ case EOpVectorLogicalNot: preString = "not("; 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 EOpRadians:
+ preString = "radians(";
+ break;
+ case EOpDegrees:
+ preString = "degrees(";
+ break;
+ case EOpSin:
+ preString = "sin(";
+ break;
+ case EOpCos:
+ preString = "cos(";
+ break;
+ case EOpTan:
+ preString = "tan(";
+ break;
+ case EOpAsin:
+ preString = "asin(";
+ break;
+ case EOpAcos:
+ preString = "acos(";
+ break;
+ case EOpAtan:
+ preString = "atan(";
+ break;
+
+ case EOpSinh:
+ preString = "sinh(";
+ break;
+ case EOpCosh:
+ preString = "cosh(";
+ break;
+ case EOpTanh:
+ preString = "tanh(";
+ break;
+ case EOpAsinh:
+ preString = "asinh(";
+ break;
+ case EOpAcosh:
+ preString = "acosh(";
+ break;
+ case EOpAtanh:
+ preString = "atanh(";
+ break;
+
+ case EOpExp:
+ preString = "exp(";
+ break;
+ case EOpLog:
+ preString = "log(";
+ break;
+ case EOpExp2:
+ preString = "exp2(";
+ break;
+ case EOpLog2:
+ preString = "log2(";
+ break;
+ case EOpSqrt:
+ preString = "sqrt(";
+ break;
+ case EOpInverseSqrt:
+ preString = "inversesqrt(";
+ break;
+
+ case EOpAbs:
+ preString = "abs(";
+ break;
+ case EOpSign:
+ preString = "sign(";
+ break;
+ case EOpFloor:
+ preString = "floor(";
+ break;
+ case EOpTrunc:
+ preString = "trunc(";
+ break;
+ case EOpRound:
+ preString = "round(";
+ break;
+ case EOpRoundEven:
+ preString = "roundEven(";
+ break;
+ case EOpCeil:
+ preString = "ceil(";
+ break;
+ case EOpFract:
+ preString = "fract(";
+ break;
+ case EOpIsNan:
+ preString = "isnan(";
+ break;
+ case EOpIsInf:
+ preString = "isinf(";
+ break;
+
+ case EOpFloatBitsToInt:
+ preString = "floatBitsToInt(";
+ break;
+ case EOpFloatBitsToUint:
+ preString = "floatBitsToUint(";
+ break;
+ case EOpIntBitsToFloat:
+ preString = "intBitsToFloat(";
+ break;
+ case EOpUintBitsToFloat:
+ preString = "uintBitsToFloat(";
+ break;
+
+ case EOpPackSnorm2x16:
+ preString = "packSnorm2x16(";
+ break;
+ case EOpPackUnorm2x16:
+ preString = "packUnorm2x16(";
+ break;
+ case EOpPackHalf2x16:
+ preString = "packHalf2x16(";
+ break;
+ case EOpUnpackSnorm2x16:
+ preString = "unpackSnorm2x16(";
+ break;
+ case EOpUnpackUnorm2x16:
+ preString = "unpackUnorm2x16(";
+ break;
+ case EOpUnpackHalf2x16:
+ preString = "unpackHalf2x16(";
+ break;
+
+ case EOpLength:
+ preString = "length(";
+ break;
+ case EOpNormalize:
+ preString = "normalize(";
+ break;
+
+ case EOpDFdx:
+ preString = "dFdx(";
+ break;
+ case EOpDFdy:
+ preString = "dFdy(";
+ break;
+ case EOpFwidth:
+ preString = "fwidth(";
+ break;
+
+ case EOpTranspose:
+ preString = "transpose(";
+ break;
+ case EOpDeterminant:
+ preString = "determinant(";
+ break;
+ case EOpInverse:
+ preString = "inverse(";
+ break;
+
+ case EOpAny:
+ preString = "any(";
+ break;
+ case EOpAll:
+ preString = "all(";
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ if (visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+
+ 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";
+
+ incrementDepth(node);
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
+ return false;
+}
+
+bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ if (node->getStatementList())
+ {
+ writeTriplet(visit, "switch (", ") ", nullptr);
+ // The curly braces get written when visiting the statementList aggregate
+ }
+ else
+ {
+ // No statementList, so it won't output curly braces
+ writeTriplet(visit, "switch (", ") {", "}\n");
+ }
+ 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 (mDepth > 0)
+ {
+ out << "{\n";
+ }
+
+ incrementDepth(node);
+ 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";
+ }
+ decrementDepth();
+
+ // Scope the blocks except when at the global scope.
+ if (mDepth > 0)
+ {
+ out << "}\n";
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ ASSERT(visit == PreVisit);
+ {
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+ }
+
+ out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+
+ incrementDepth(node);
+
+ // Traverse function parameters.
+ TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ visitCodeBlock(node->getBody());
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ // Function declaration.
+ ASSERT(visit == PreVisit);
+ {
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+ }
+
+ out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+
+ out << "(";
+ writeFunctionParameters(*(node->getSequence()));
+ out << ")";
+
+ visitChildren = false;
+ break;
+ case EOpFunctionCall:
+ // Function call.
+ if (visit == PreVisit)
+ out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
+ else if (visit == InVisit)
+ out << ", ";
+ else
+ out << ")";
+ break;
+ case EOpParameters:
+ // Function parameters.
+ ASSERT(visit == PreVisit);
+ out << "(";
+ writeFunctionParameters(*(node->getSequence()));
+ out << ")";
+ visitChildren = false;
+ break;
+ case EOpDeclaration:
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ const TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeLayoutQualifier(variable->getType());
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpInvariantDeclaration:
+ // Invariant declaration.
+ ASSERT(visit == PreVisit);
+ {
+ const TIntermSequence *sequence = node->getSequence();
+ ASSERT(sequence && sequence->size() == 1);
+ const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
+ ASSERT(symbol);
+ out << "invariant " << hashVariableName(symbol->getSymbol());
+ }
+ visitChildren = false;
+ break;
+ case EOpConstructFloat:
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructBool:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructInt:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructUInt:
+ case EOpConstructUVec2:
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ case EOpConstructStruct:
+ writeConstructorTriplet(visit, node->getType());
+ break;
+
+ case EOpOuterProduct:
+ writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
+ break;
+
+ case EOpLessThan:
+ writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
+ break;
+ case EOpGreaterThan:
+ writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
+ break;
+ case EOpLessThanEqual:
+ writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
+ break;
+ case EOpGreaterThanEqual:
+ writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
+ break;
+ case EOpVectorEqual:
+ writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
+ break;
+ case EOpVectorNotEqual:
+ writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
+ break;
+
+ case EOpMod:
+ writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
+ break;
+ case EOpModf:
+ writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
+ break;
+ case EOpPow:
+ writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
+ break;
+ case EOpAtan:
+ writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
+ break;
+ case EOpMin:
+ writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
+ break;
+ case EOpMax:
+ writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
+ break;
+ case EOpClamp:
+ writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
+ break;
+ case EOpMix:
+ writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
+ break;
+ case EOpStep:
+ writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
+ break;
+ case EOpSmoothStep:
+ writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
+ break;
+ case EOpDistance:
+ writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
+ break;
+ case EOpDot:
+ writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
+ break;
+ case EOpCross:
+ writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
+ break;
+ case EOpFaceForward:
+ writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
+ break;
+ case EOpReflect:
+ writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
+ break;
+ case EOpRefract:
+ writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
+ break;
+ case EOpMul:
+ writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ incrementDepth(node);
+
+ TLoopType loopType = node->getType();
+
+ // Only for loops can be unrolled
+ ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
+
+ if (loopType == ELoopFor) // for loop
+ {
+ if (!node->getUnrollFlag())
+ {
+ 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
+ {
+ // Need to put a one-iteration loop here to handle break.
+ TIntermSequence *declSeq =
+ node->getInit()->getAsAggregate()->getSequence();
+ TIntermSymbol *indexSymbol =
+ (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+ TString name = hashVariableName(indexSymbol->getSymbol());
+ out << "for (int " << name << " = 0; "
+ << name << " < 1; "
+ << "++" << name << ")\n";
+
+ out << "{\n";
+ mLoopUnrollStack.push(node);
+ while (mLoopUnrollStack.satisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnrollStack.step();
+ }
+ mLoopUnrollStack.pop();
+ out << "}\n";
+ }
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ 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() != NULL);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+
+ decrementDepth();
+
+ // 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", NULL, NULL);
+ break;
+ case EOpBreak:
+ writeTriplet(visit, "break", NULL, NULL);
+ break;
+ case EOpContinue:
+ writeTriplet(visit, "continue", NULL, NULL);
+ break;
+ case EOpReturn:
+ writeTriplet(visit, "return ", NULL, NULL);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (node != NULL)
+ {
+ 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.
+ }
+}
+
+TString TOutputGLSLBase::getTypeName(const TType &type)
+{
+ if (type.getBasicType() == EbtStruct)
+ return hashName(type.getStruct()->name());
+ else
+ return type.getBuiltInTypeNameString();
+}
+
+TString TOutputGLSLBase::hashName(const TString &name)
+{
+ if (mHashFunction == NULL || name.empty())
+ return name;
+ NameMap::const_iterator it = mNameMap.find(name.c_str());
+ if (it != mNameMap.end())
+ return it->second.c_str();
+ TString hashedName = TIntermTraverser::hash(name, mHashFunction);
+ mNameMap[name.c_str()] = hashedName.c_str();
+ return hashedName;
+}
+
+TString TOutputGLSLBase::hashVariableName(const TString &name)
+{
+ if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
+ return name;
+ return hashName(name);
+}
+
+TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
+{
+ TString mangledStr = mangledName.getString();
+ TString name = TFunction::unmangleName(mangledStr);
+ if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
+ return translateTextureFunction(name);
+ if (mangledName.isInternal())
+ return name;
+ else
+ return hashName(name);
+}
+
+bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
+{
+ ASSERT(structure);
+ if (structure->name().empty())
+ {
+ return false;
+ }
+
+ return (mDeclaredStructs.count(structure->uniqueId()) > 0);
+}
+
+void TOutputGLSLBase::declareStruct(const TStructure *structure)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "struct " << hashName(structure->name()) << "{\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()) << " " << hashName(field->name());
+ if (field->type()->isArray())
+ out << arrayBrackets(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+}
+
+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;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ out << ", ";
+
+ switch (interfaceBlock->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 << ") ";
+}
+
+void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << hashName(interfaceBlock->name()) << "{\n";
+ const TFieldList &fields = interfaceBlock->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()) << " " << hashName(field->name());
+ if (field->type()->isArray())
+ out << arrayBrackets(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.h b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.h
new file mode 100644
index 000000000..aa861c73c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputGLSLBase.h
@@ -0,0 +1,102 @@
+//
+// 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/IntermNode.h"
+#include "compiler/translator/LoopInfo.h"
+#include "compiler/translator/ParseContext.h"
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+ public:
+ TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion,
+ ShShaderOutput output);
+
+ ShShaderOutput getShaderOutput() const
+ {
+ return mOutput;
+ }
+
+ protected:
+ TInfoSinkBase &objSink() { return mObjSink; }
+ void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
+ void writeLayoutQualifier(const TType &type);
+ void writeVariableType(const TType &type);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TIntermSequence &args);
+ const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion);
+ void writeConstructorTriplet(Visit visit, const TType &type);
+ TString 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;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
+
+ void visitCodeBlock(TIntermBlock *node);
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ TString hashName(const TString &name);
+ // Same as hashName(), but without hashing built-in variables.
+ TString hashVariableName(const TString &name);
+ // Same as hashName(), but without hashing built-in functions and with unmangling.
+ TString hashFunctionNameIfNeeded(const TName &mangledName);
+ // Used to translate function names for differences between ESSL and GLSL
+ virtual TString translateTextureFunction(TString &name) { return name; }
+
+ private:
+ bool structDeclared(const TStructure *structure) const;
+ void declareStruct(const TStructure *structure);
+
+ void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock);
+ void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock);
+
+ void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction);
+
+ TInfoSinkBase &mObjSink;
+ bool mDeclaringVariables;
+
+ // This set contains all the ids of the structs from every scope.
+ std::set<int> mDeclaredStructs;
+
+ // Stack of loops that need to be unrolled.
+ TLoopStack mLoopUnrollStack;
+
+ ShArrayIndexClampingStrategy mClampingStrategy;
+
+ // name hashing.
+ ShHashFunction64 mHashFunction;
+
+ NameMap &mNameMap;
+
+ TSymbolTable &mSymbolTable;
+
+ const int mShaderVersion;
+
+ ShShaderOutput mOutput;
+};
+
+#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.cpp
new file mode 100644
index 000000000..feae684d5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.cpp
@@ -0,0 +1,2897 @@
+//
+// 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 <algorithm>
+#include <cfloat>
+#include <stdio.h>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/utilities.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "compiler/translator/FlagStd140Structs.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/NodeSearch.h"
+#include "compiler/translator/RemoveSwitchFallThrough.h"
+#include "compiler/translator/SearchSymbol.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/TextureFunctionHLSL.h"
+#include "compiler/translator/TranslatorHLSL.h"
+#include "compiler/translator/UniformHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayout.h"
+#include "compiler/translator/util.h"
+
+namespace
+{
+
+void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
+{
+ ASSERT(constUnion != nullptr);
+ switch (constUnion->getType())
+ {
+ case EbtFloat:
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, 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 *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;
+}
+
+} // namespace
+
+namespace sh
+{
+
+OutputHLSL::OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions)
+ : TIntermTraverser(true, true, true),
+ mShaderType(shaderType),
+ mShaderVersion(shaderVersion),
+ mExtensionBehavior(extensionBehavior),
+ mSourcePath(sourcePath),
+ mOutputType(outputType),
+ mCompileOptions(compileOptions),
+ mNumRenderTargets(numRenderTargets),
+ mCurrentFunctionMetadata(nullptr)
+{
+ mInsideFunction = false;
+
+ mUsesFragColor = false;
+ mUsesFragData = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesInstanceID = false;
+ mUsesVertexID = false;
+ mUsesFragDepth = false;
+ mUsesXor = false;
+ mUsesDiscardRewriting = false;
+ mUsesNestedBreak = false;
+ mRequiresIEEEStrictCompiling = false;
+
+ mUniqueIndex = 0;
+
+ mOutputLod0Function = false;
+ mInsideDiscontinuousLoop = false;
+ mNestedLoopDepth = 0;
+
+ mExcessiveLoopIndex = NULL;
+
+ mStructureHLSL = new StructureHLSL;
+ mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
+ mTextureFunctionHLSL = new TextureFunctionHLSL;
+
+ 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.
+ mUniformHLSL->reserveUniformRegisters(3);
+ }
+
+ // Reserve registers for the default uniform block and driver constants
+ mUniformHLSL->reserveInterfaceBlockRegisters(2);
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ SafeDelete(mStructureHLSL);
+ SafeDelete(mUniformHLSL);
+ SafeDelete(mTextureFunctionHLSL);
+ for (auto &eqFunction : mStructEqualityFunctions)
+ {
+ SafeDelete(eqFunction);
+ }
+ for (auto &eqFunction : mArrayEqualityFunctions)
+ {
+ SafeDelete(eqFunction);
+ }
+}
+
+void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
+{
+ const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
+ makeFlaggedStructMaps(flaggedStructs);
+
+ 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, &objSink);
+ ASSERT(success == CallDAG::INITDAG_SUCCESS);
+ UNUSED_ASSERTION_VARIABLE(success);
+ mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
+
+ // 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, &builtInFunctionEmulator);
+ mInfoSinkStack.pop();
+
+ objSink << mHeader.c_str();
+ objSink << mBody.c_str();
+ objSink << mFooter.c_str();
+
+ builtInFunctionEmulator.Cleanup();
+}
+
+void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
+{
+ for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
+ {
+ TIntermTyped *flaggedNode = flaggedStructs[structIndex];
+
+ TInfoSinkBase structInfoSink;
+ mInfoSinkStack.push(&structInfoSink);
+
+ // This will mark the necessary block elements as referenced
+ flaggedNode->traverse(this);
+
+ TString structName(structInfoSink.c_str());
+ mInfoSinkStack.pop();
+
+ mFlaggedStructOriginalNames[flaggedNode] = structName;
+
+ for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
+ {
+ structName.erase(pos, 1);
+ }
+
+ mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
+ }
+}
+
+const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
+{
+ return mUniformHLSL->getInterfaceBlockRegisterMap();
+}
+
+const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
+{
+ return mUniformHLSL->getUniformRegisterMap();
+}
+
+int OutputHLSL::vectorSize(const TType &type) const
+{
+ int elementSize = type.isMatrix() ? type.getCols() : 1;
+ unsigned int arraySize = type.isArray() ? type.getArraySize() : 1u;
+
+ return elementSize * arraySize;
+}
+
+TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
+{
+ TString init;
+
+ TString preIndentString;
+ TString fullIndentString;
+
+ for (int spaces = 0; spaces < (indent * 4); spaces++)
+ {
+ preIndentString += ' ';
+ }
+
+ for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
+ {
+ fullIndentString += ' ';
+ }
+
+ init += preIndentString + "{\n";
+
+ const TFieldList &fields = structure.fields();
+ for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ const TField &field = *fields[fieldIndex];
+ const TString &fieldName = rhsStructName + "." + Decorate(field.name());
+ const TType &fieldType = *field.type();
+
+ if (fieldType.getStruct())
+ {
+ init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
+ }
+ else
+ {
+ init += fullIndentString + fieldName + ",\n";
+ }
+ }
+
+ init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
+
+ return init;
+}
+
+void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
+{
+ TString varyings;
+ TString attributes;
+ TString flaggedStructs;
+
+ for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
+ {
+ TIntermTyped *structNode = flaggedStructIt->first;
+ const TString &mappedName = flaggedStructIt->second;
+ const TStructure &structure = *structNode->getType().getStruct();
+ const TString &originalName = mFlaggedStructOriginalNames[structNode];
+
+ flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
+ flaggedStructs += structInitializerString(0, structure, originalName);
+ flaggedStructs += "\n";
+ }
+
+ for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
+ {
+ const TType &type = varying->second->getType();
+ const TString &name = varying->second->getSymbol();
+
+ // Program linking depends on this exact format
+ varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
+ Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
+ }
+
+ for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
+ {
+ const TType &type = attribute->second->getType();
+ const TString &name = attribute->second->getSymbol();
+
+ attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
+ }
+
+ out << mStructureHLSL->structsHeader();
+
+ mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
+ out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
+
+ 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";
+
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
+ const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
+
+ out << "// Varyings\n";
+ out << varyings;
+ out << "\n";
+
+ if (mShaderVersion >= 300)
+ {
+ for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
+ {
+ const TString &variableName = outputVariableIt->first;
+ const TType &variableType = outputVariableIt->second->getType();
+
+ out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
+ " = " + initializer(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 (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 (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ mUniformHLSL->samplerMetadataUniforms(out, "c4");
+ }
+
+ 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 (!flaggedStructs.empty())
+ {
+ out << "// Std140 Structures accessed by value\n";
+ out << "\n";
+ out << flaggedStructs;
+ out << "\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";
+ }
+ }
+ else // Vertex shader
+ {
+ out << "// Attributes\n";
+ out << attributes;
+ 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";
+ out << varyings;
+ 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 (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ mUniformHLSL->samplerMetadataUniforms(out, "c4");
+ }
+
+ 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";
+ }
+
+ if (!flaggedStructs.empty())
+ {
+ out << "// Std140 Structures accessed by value\n";
+ out << "\n";
+ out << flaggedStructs;
+ out << "\n";
+ }
+ }
+
+ bool getDimensionsIgnoresBaseLevel =
+ (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
+ mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
+
+ 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 (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)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ // Handle accessing std140 structs by value
+ if (mFlaggedStructMappedNames.count(node) > 0)
+ {
+ out << mFlaggedStructMappedNames[node];
+ return;
+ }
+
+ TString name = node->getSymbol();
+
+ if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else
+ {
+ TQualifier qualifier = node->getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ const TType &nodeType = node->getType();
+ const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
+
+ if (interfaceBlock)
+ {
+ mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
+ }
+ else
+ {
+ mReferencedUniforms[name] = node;
+ }
+
+ ensureStructDefined(nodeType);
+
+ const TName &nameWithMetadata = node->getName();
+ out << DecorateUniform(nameWithMetadata, nodeType);
+ }
+ else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
+ {
+ mReferencedAttributes[name] = node;
+ out << Decorate(name);
+ }
+ else if (IsVarying(qualifier))
+ {
+ mReferencedVaryings[name] = node;
+ out << Decorate(name);
+ }
+ else if (qualifier == EvqFragmentOut)
+ {
+ mReferencedOutputVariables[name] = node;
+ 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 == 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
+ {
+ out << DecorateIfNeeded(node->getName());
+ }
+ }
+}
+
+void OutputHLSL::visitRaw(TIntermRaw *node)
+{
+ getInfoSink() << node->getRawText();
+}
+
+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(", " == ", ")");
+ }
+ }
+}
+
+bool OutputHLSL::ancestorEvaluatesToSamplerInStruct(Visit visit)
+{
+ // Inside InVisit the current node is already in the path.
+ const unsigned int initialN = visit == InVisit ? 1u : 0u;
+ for (unsigned int n = initialN; 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();
+
+ // Handle accessing std140 structs by value
+ if (mFlaggedStructMappedNames.count(node) > 0)
+ {
+ out << mFlaggedStructMappedNames[node];
+ return false;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpComma:
+ outputTriplet(out, visit, "(", ", ", ")");
+ break;
+ case EOpAssign:
+ if (node->getLeft()->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 || rightAgg->getOp() != EOpFunctionCall);
+
+ const TString &functionName = addArrayAssignmentFunction(node->getType());
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
+ }
+ else
+ {
+ outputTriplet(out, visit, "(", " = ", ")");
+ }
+ break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ ASSERT(symbolNode);
+ TIntermTyped *expression = node->getRight();
+
+ // Global initializers must be constant at this point.
+ ASSERT(symbolNode->getQualifier() != EvqGlobal ||
+ canWriteAsHLSLLiteral(expression));
+
+ // 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, expression))
+ {
+ // Skip initializing the rest of the expression
+ return false;
+ }
+ else if (writeConstantInitialization(out, symbolNode, expression))
+ {
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ }
+ 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)
+ {
+ TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
+ const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
+ mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
+ out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
+ return false;
+ }
+ }
+ else if (ancestorEvaluatesToSamplerInStruct(visit))
+ {
+ // 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
+ {
+ outputTriplet(out, visit, "", "[", "]");
+ }
+ }
+ break;
+ case EOpIndexIndirect:
+ // We do not currently support indirect references to interface blocks
+ ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
+ 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(visit);
+ }
+ if (visit == InVisit)
+ {
+ if (indexingReturnsSampler)
+ {
+ out << "_" + field->name();
+ }
+ else
+ {
+ out << "." + DecorateField(field->name(), *structure);
+ }
+
+ return false;
+ }
+ }
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ if (visit == InVisit)
+ {
+ const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
+ const TField* field = interfaceBlock->fields()[index->getIConst(0)];
+ 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 EOpVectorLogicalNot:
+ 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:
+ outputTriplet(out, visit, "tanh(", "", ")");
+ break;
+ case EOpAsinh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "asinh(");
+ break;
+ case EOpAcosh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "acosh(");
+ break;
+ case EOpAtanh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "atanh(");
+ 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, "roundEven(");
+ break;
+ case EOpCeil:
+ outputTriplet(out, visit, "ceil(", "", ")");
+ break;
+ case EOpFract:
+ outputTriplet(out, visit, "frac(", "", ")");
+ break;
+ case EOpIsNan:
+ if (node->getUseEmulatedFunction())
+ writeEmulatedFunctionTriplet(out, visit, "isnan(");
+ 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:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
+ break;
+ case EOpPackUnorm2x16:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
+ break;
+ case EOpPackHalf2x16:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
+ break;
+ case EOpUnpackSnorm2x16:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
+ break;
+ case EOpUnpackUnorm2x16:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
+ break;
+ case EOpUnpackHalf2x16:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
+ 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, "inverse(");
+ break;
+
+ case EOpAny:
+ outputTriplet(out, visit, "any(", "", ")");
+ break;
+ case EOpAll:
+ outputTriplet(out, visit, "all(", "", ")");
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
+{
+ if (node->getAsSymbolNode())
+ {
+ return node->getAsSymbolNode()->getSymbol();
+ }
+ TIntermBinary *nodeBinary = node->getAsBinaryNode();
+ switch (nodeBinary->getOp())
+ {
+ case EOpIndexDirect:
+ {
+ int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
+
+ TInfoSinkBase prefixSink;
+ prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
+ return TString(prefixSink.c_str());
+ }
+ case EOpIndexDirectStruct:
+ {
+ TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
+ int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
+ const TField *field = s->fields()[index];
+
+ TInfoSinkBase prefixSink;
+ prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
+ << field->name();
+ return TString(prefixSink.c_str());
+ }
+ default:
+ UNREACHABLE();
+ return TString("");
+ }
+}
+
+bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(out, node->getLine().first_line);
+ out << "{\n";
+ }
+
+ for (TIntermSequence::iterator sit = node->getSequence()->begin();
+ sit != node->getSequence()->end(); sit++)
+ {
+ outputLineDirective(out, (*sit)->getLine().first_line);
+
+ (*sit)->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 no need to output ; after if statements or sequences. This is done just for
+ // code clarity.
+ if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
+ (*sit)->getAsBlock() == nullptr)
+ out << ";\n";
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(out, node->getLine().last_line);
+ out << "}\n";
+ }
+
+ return false;
+}
+
+bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(mCurrentFunctionMetadata == nullptr);
+
+ size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(index != CallDAG::InvalidIndex);
+ mCurrentFunctionMetadata = &mASTMetadataList[index];
+
+ out << TypeString(node->getType()) << " ";
+
+ TIntermSequence *parameters = node->getFunctionParameters()->getSequence();
+
+ if (node->getFunctionSymbolInfo()->isMain())
+ {
+ out << "gl_main(";
+ }
+ else
+ {
+ out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
+ << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
+ }
+
+ for (unsigned int i = 0; i < parameters->size(); i++)
+ {
+ TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ ensureStructDefined(symbol->getType());
+
+ out << argumentString(symbol);
+
+ if (i < parameters->size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else
+ UNREACHABLE();
+ }
+
+ out << ")\n";
+
+ mInsideFunction = true;
+ // The function body node will output braces.
+ node->getBody()->traverse(this);
+ mInsideFunction = false;
+
+ mCurrentFunctionMetadata = nullptr;
+
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ ASSERT(!node->getFunctionSymbolInfo()->isMain());
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getOp())
+ {
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ TIntermTyped *variable = (*sequence)[0]->getAsTyped();
+ ASSERT(sequence->size() == 1);
+
+ if (variable &&
+ (variable->getQualifier() == EvqTemporary ||
+ variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
+ {
+ ensureStructDefined(variable->getType());
+
+ if (!variable->getAsSymbolNode() ||
+ variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
+ {
+ if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << TypeString(variable->getType()) + " ";
+
+ TIntermSymbol *symbol = variable->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << ArrayString(symbol->getType());
+ out << " = " + initializer(symbol->getType());
+ }
+ else
+ {
+ variable->traverse(this);
+ }
+ }
+ else if (variable->getAsSymbolNode() &&
+ variable->getAsSymbolNode()->getSymbol() ==
+ "") // Type (struct) declaration
+ {
+ // Already added to constructor map
+ }
+ else
+ UNREACHABLE();
+ }
+ else if (variable && IsVaryingOut(variable->getQualifier()))
+ {
+ for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end();
+ sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ // Vertex (output) varyings which are declared but not written to should
+ // still be declared to allow successful linking
+ mReferencedVaryings[symbol->getSymbol()] = symbol;
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+ }
+ }
+
+ return false;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ break;
+ case EOpInvariantDeclaration:
+ // Do not do any translation
+ return false;
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
+ // Skip the prototype if it is not implemented (and thus not used)
+ if (index == CallDAG::InvalidIndex)
+ {
+ return false;
+ }
+
+ TIntermSequence *arguments = node->getSequence();
+
+ TString name =
+ DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+ out << TypeString(node->getType()) << " " << name
+ << DisambiguateFunctionName(arguments) << (mOutputLod0Function ? "Lod0(" : "(");
+
+ for (unsigned int i = 0; i < arguments->size(); i++)
+ {
+ TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments->size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else
+ UNREACHABLE();
+ }
+
+ 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;
+ }
+
+ return false;
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ TIntermSequence *arguments = node->getSequence();
+
+ bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
+ if (node->isUserDefined())
+ {
+ if (node->isArray())
+ {
+ UNIMPLEMENTED();
+ }
+ size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(index != CallDAG::InvalidIndex);
+ lod0 &= mASTMetadataList[index].mNeedsLod0;
+
+ out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+ out << DisambiguateFunctionName(node->getSequence());
+ out << (lod0 ? "Lod0(" : "(");
+ }
+ else if (node->getFunctionSymbolInfo()->getNameObj().isInternal())
+ {
+ // This path is used for internal functions that don't have their definitions in the
+ // AST, such as precision emulation functions.
+ out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
+ }
+ else
+ {
+ TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
+ TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
+ int coords = (*arguments)[1]->getAsTyped()->getNominalSize();
+ TString 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<TIntermSymbol *> samplerSymbols;
+ TString structName = samplerNamePrefixFromStruct(typedArg);
+ argType.createSamplerSymbols("angle_" + structName, "",
+ argType.isArray() ? argType.getArraySize() : 0u,
+ &samplerSymbols, nullptr);
+ for (const TIntermSymbol *sampler : samplerSymbols)
+ {
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << ", texture_" << sampler->getSymbol();
+ out << ", sampler_" << sampler->getSymbol();
+ }
+ 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->getSymbol();
+ }
+ }
+ }
+
+ if (arg < arguments->end() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ case EOpParameters:
+ outputTriplet(out, visit, "(", ", ", ")\n{\n");
+ break;
+ case EOpConstructFloat:
+ outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
+ break;
+ case EOpConstructVec2:
+ outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
+ break;
+ case EOpConstructVec3:
+ outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
+ break;
+ case EOpConstructVec4:
+ outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
+ break;
+ case EOpConstructBool:
+ outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
+ break;
+ case EOpConstructBVec2:
+ outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
+ break;
+ case EOpConstructBVec3:
+ outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
+ break;
+ case EOpConstructBVec4:
+ outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
+ break;
+ case EOpConstructInt:
+ outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
+ break;
+ case EOpConstructIVec2:
+ outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
+ break;
+ case EOpConstructIVec3:
+ outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
+ break;
+ case EOpConstructIVec4:
+ outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
+ break;
+ case EOpConstructUInt:
+ outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
+ break;
+ case EOpConstructUVec2:
+ outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
+ break;
+ case EOpConstructUVec3:
+ outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
+ break;
+ case EOpConstructUVec4:
+ outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
+ break;
+ case EOpConstructMat2:
+ outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
+ break;
+ case EOpConstructMat2x3:
+ outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
+ break;
+ case EOpConstructMat2x4:
+ outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
+ break;
+ case EOpConstructMat3x2:
+ outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
+ break;
+ case EOpConstructMat3:
+ outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
+ break;
+ case EOpConstructMat3x4:
+ outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
+ break;
+ case EOpConstructMat4x2:
+ outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
+ break;
+ case EOpConstructMat4x3:
+ outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
+ break;
+ case EOpConstructMat4:
+ outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
+ break;
+ case EOpConstructStruct:
+ {
+ if (node->getType().isArray())
+ {
+ UNIMPLEMENTED();
+ }
+ const TString &structName = StructNameString(*node->getType().getStruct());
+ mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
+ outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
+ }
+ 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 EOpVectorEqual:
+ outputTriplet(out, visit, "(", " == ", ")");
+ break;
+ case EOpVectorNotEqual:
+ outputTriplet(out, visit, "(", " != ", ")");
+ break;
+ case EOpMod:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "mod(");
+ 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, "atan(");
+ 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, "mix(");
+ }
+ else
+ {
+ outputTriplet(out, visit, "lerp(", ", ", ")");
+ }
+ break;
+ }
+ case EOpStep:
+ outputTriplet(out, visit, "step(", ", ", ")");
+ break;
+ case EOpSmoothStep:
+ outputTriplet(out, visit, "smoothstep(", ", ", ")");
+ 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, "faceforward(");
+ break;
+ case EOpReflect:
+ outputTriplet(out, visit, "reflect(", ", ", ")");
+ break;
+ case EOpRefract:
+ outputTriplet(out, visit, "refract(", ", ", ")");
+ break;
+ case EOpOuterProduct:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
+ break;
+ case EOpMul:
+ outputTriplet(out, visit, "(", " * ", ")");
+ 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();
+
+ if (node->getStatementList())
+ {
+ node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
+ outputTriplet(out, visit, "switch (", ") ", "");
+ // The curly braces get written when visiting the statementList aggregate
+ }
+ else
+ {
+ // No statementList, so it won't output curly braces
+ outputTriplet(out, visit, "switch (", ") {", "}\n");
+ }
+ 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->getUnionArrayPointer());
+}
+
+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(\n";
+
+ node->getCondition()->traverse(this);
+
+ out << ");";
+ }
+
+ out << "}\n";
+
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+ mNestedLoopDepth--;
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ outputTriplet(out, visit, "discard;\n", "", "");
+ break;
+ case EOpBreak:
+ if (visit == PreVisit)
+ {
+ if (mNestedLoopDepth > 1)
+ {
+ mUsesNestedBreak = true;
+ }
+
+ if (mExcessiveLoopIndex)
+ {
+ out << "{Break";
+ mExcessiveLoopIndex->traverse(this);
+ out << " = true; break;}\n";
+ }
+ else
+ {
+ out << "break;\n";
+ }
+ }
+ break;
+ case EOpContinue:
+ outputTriplet(out, visit, "continue;\n", "", "");
+ break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ {
+ if (node->getExpression())
+ {
+ out << "return ";
+ }
+ else
+ {
+ out << "return;\n";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getExpression())
+ {
+ out << ";\n";
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ if (node->getAsBlock())
+ {
+ return false;
+ }
+
+ TIntermAggregate *aggregate = node->getAsAggregate();
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpDeclaration)
+ {
+ // Declaring multiple comma-separated variables must be considered multiple statements
+ // because each individual declaration has side effects which are visible in the next.
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ 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 = NULL;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+ 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 != NULL && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ comparator = test->getOp();
+ limit = constant->getIConst(0);
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != NULL && 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 != NULL && 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 = NULL; // 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";
+ }
+}
+
+TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
+{
+ TQualifier qualifier = symbol->getQualifier();
+ const TType &type = symbol->getType();
+ const TName &name = symbol->getName();
+ TString nameStr;
+
+ if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
+ {
+ nameStr = "x" + str(mUniqueIndex++);
+ }
+ else
+ {
+ nameStr = DecorateIfNeeded(name);
+ }
+
+ 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);
+ return "const uint " + nameStr + ArrayString(type);
+ }
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
+ " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
+ " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
+ ArrayString(type);
+ }
+ }
+
+ TStringStream argString;
+ argString << 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<TIntermSymbol *> samplerSymbols;
+ type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
+ for (const TIntermSymbol *sampler : samplerSymbols)
+ {
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
+ }
+ else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ const TType &samplerType = sampler->getType();
+ ASSERT((!type.isArray() && !samplerType.isArray()) ||
+ type.getArraySize() == samplerType.getArraySize());
+ ASSERT(IsSampler(samplerType.getBasicType()));
+ argString << ", " << QualifierString(qualifier) << " "
+ << TextureString(samplerType.getBasicType()) << " texture_"
+ << sampler->getSymbol() << ArrayString(type) << ", "
+ << QualifierString(qualifier) << " "
+ << SamplerString(samplerType.getBasicType()) << " sampler_"
+ << sampler->getSymbol() << ArrayString(type);
+ }
+ else
+ {
+ const TType &samplerType = sampler->getType();
+ ASSERT((!type.isArray() && !samplerType.isArray()) ||
+ type.getArraySize() == samplerType.getArraySize());
+ ASSERT(IsSampler(samplerType.getBasicType()));
+ argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
+ << " " << sampler->getSymbol() << ArrayString(type);
+ }
+ }
+ }
+
+ return argString.str();
+}
+
+TString OutputHLSL::initializer(const TType &type)
+{
+ TString string;
+
+ size_t size = type.getObjectSize();
+ for (size_t component = 0; component < size; component++)
+ {
+ string += "0";
+
+ if (component + 1 < size)
+ {
+ string += ", ";
+ }
+ }
+
+ return "{" + string + "}";
+}
+
+void OutputHLSL::outputConstructor(TInfoSinkBase &out,
+ Visit visit,
+ const TType &type,
+ const char *name,
+ const TIntermSequence *parameters)
+{
+ if (type.isArray())
+ {
+ UNIMPLEMENTED();
+ }
+
+ if (visit == PreVisit)
+ {
+ TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
+
+ 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)
+{
+ const TConstantUnion *constUnionIterated = constUnion;
+
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ out << StructNameString(*structure) + "_ctor(";
+
+ 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, const char *preStr)
+{
+ TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
+ outputTriplet(out, visit, preString.c_str(), ", ", ")");
+}
+
+bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
+{
+ sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
+ expression->traverse(&searchSymbol);
+
+ if (searchSymbol.foundMatch())
+ {
+ // 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::canWriteAsHLSLLiteral(TIntermTyped *expression)
+{
+ // We support writing constant unions and constructors that only take constant unions as
+ // parameters as HLSL literals.
+ return expression->getAsConstantUnion() ||
+ expression->isConstructorWithOnlyConstantUnionParameters();
+}
+
+bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression)
+{
+ if (canWriteAsHLSLLiteral(expression))
+ {
+ symbolNode->traverse(this);
+ if (expression->getType().isArray())
+ {
+ out << "[" << expression->getType().getArraySize() << "]";
+ }
+ out << " = {";
+ if (expression->getAsConstantUnion())
+ {
+ TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
+ const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+ WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+ }
+ else
+ {
+ TIntermAggregate *constructor = expression->getAsAggregate();
+ ASSERT(constructor != nullptr);
+ for (TIntermNode *&node : *constructor->getSequence())
+ {
+ TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
+ ASSERT(nodeConst);
+ const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+ WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+ if (node != constructor->getSequence()->back())
+ {
+ out << ", ";
+ }
+ }
+ }
+ 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;
+ }
+ }
+
+ const TString &typeName = TypeString(type);
+
+ ArrayHelperFunction *function = new ArrayHelperFunction();
+ function->type = type;
+
+ TInfoSinkBase fnNameOut;
+ fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
+ function->functionName = fnNameOut.c_str();
+
+ TType nonArrayType = type;
+ nonArrayType.clearArrayness();
+
+ TInfoSinkBase fnOut;
+
+ fnOut << "bool " << function->functionName << "("
+ << typeName << " a[" << type.getArraySize() << "], "
+ << typeName << " b[" << type.getArraySize() << "])\n"
+ << "{\n"
+ " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
+ " {\n"
+ " if (";
+
+ outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
+ fnOut << "a[i]";
+ outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
+ fnOut << "b[i]";
+ outputEqual(PostVisit, nonArrayType, 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;
+ }
+ }
+
+ const TString &typeName = TypeString(type);
+
+ ArrayHelperFunction function;
+ function.type = type;
+
+ TInfoSinkBase fnNameOut;
+ fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
+ function.functionName = fnNameOut.c_str();
+
+ TInfoSinkBase fnOut;
+
+ fnOut << "void " << function.functionName << "(out "
+ << typeName << " a[" << type.getArraySize() << "], "
+ << typeName << " b[" << type.getArraySize() << "])\n"
+ << "{\n"
+ " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
+ " {\n"
+ " a[i] = b[i];\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;
+ }
+ }
+
+ const TString &typeName = TypeString(type);
+
+ ArrayHelperFunction function;
+ function.type = type;
+
+ TInfoSinkBase fnNameOut;
+ fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
+ function.functionName = fnNameOut.c_str();
+
+ TInfoSinkBase fnOut;
+
+ fnOut << "void " << function.functionName << "(out "
+ << typeName << " a[" << type.getArraySize() << "]";
+ for (unsigned int i = 0u; i < type.getArraySize(); ++i)
+ {
+ fnOut << ", " << typeName << " b" << i;
+ }
+ fnOut << ")\n"
+ "{\n";
+
+ for (unsigned int i = 0u; i < type.getArraySize(); ++i)
+ {
+ fnOut << " a[" << i << "] = b" << i << ";\n";
+ }
+ fnOut << "}\n";
+
+ function.functionDefinition = fnOut.c_str();
+
+ mArrayConstructIntoFunctions.push_back(function);
+
+ return function.functionName;
+}
+
+void OutputHLSL::ensureStructDefined(const TType &type)
+{
+ TStructure *structure = type.getStruct();
+
+ if (structure)
+ {
+ mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
+ }
+}
+
+
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.h
new file mode 100644
index 000000000..f296dd928
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/OutputHLSL.h
@@ -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.
+//
+
+#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/IntermNode.h"
+#include "compiler/translator/ParseContext.h"
+
+class BuiltInFunctionEmulator;
+
+namespace sh
+{
+class StructureHLSL;
+class TextureFunctionHLSL;
+class UnfoldShortCircuit;
+class UniformHLSL;
+
+typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions);
+
+ ~OutputHLSL();
+
+ void output(TIntermNode *treeRoot, TInfoSinkBase &objSink);
+
+ const std::map<std::string, unsigned int> &getInterfaceBlockRegisterMap() const;
+ const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
+
+ static TString initializer(const TType &type);
+
+ TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); }
+
+ static bool canWriteAsHLSLLiteral(TIntermTyped *expression);
+
+ protected:
+ void header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator);
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol*) override;
+ void visitRaw(TIntermRaw*) 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;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate*) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitLoop(Visit visit, TIntermLoop*) override;
+ bool visitBranch(Visit visit, TIntermBranch*) override;
+
+ bool isSingleStatement(TIntermNode *node);
+ 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);
+ TString argumentString(const TIntermSymbol *symbol);
+ int vectorSize(const TType &type) const;
+
+ // Emit constructor. Called with literal names so using const char* instead of TString.
+ void outputConstructor(TInfoSinkBase &out,
+ Visit visit,
+ const TType &type,
+ const char *name,
+ const TIntermSequence *parameters);
+ const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
+ const TType &type,
+ const TConstantUnion *constUnion);
+
+ void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
+
+ void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr);
+ void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
+
+ // 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 writeDeferredGlobalInitializers(TInfoSinkBase &out);
+ 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);
+
+ sh::GLenum mShaderType;
+ int mShaderVersion;
+ const TExtensionBehavior &mExtensionBehavior;
+ const char *mSourcePath;
+ const ShShaderOutput mOutputType;
+ ShCompileOptions mCompileOptions;
+
+ bool mInsideFunction;
+
+ // 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;
+
+ ReferencedSymbols mReferencedUniforms;
+ ReferencedSymbols mReferencedInterfaceBlocks;
+ ReferencedSymbols mReferencedAttributes;
+ ReferencedSymbols mReferencedVaryings;
+ ReferencedSymbols mReferencedOutputVariables;
+
+ StructureHLSL *mStructureHLSL;
+ UniformHLSL *mUniformHLSL;
+ TextureFunctionHLSL *mTextureFunctionHLSL;
+
+ // 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 mUsesVertexID;
+ bool mUsesFragDepth;
+ bool mUsesXor;
+ bool mUsesDiscardRewriting;
+ bool mUsesNestedBreak;
+ bool mRequiresIEEEStrictCompiling;
+
+
+ int mNumRenderTargets;
+
+ 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 TStructure &structure, const TString &rhsStructName);
+
+ std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
+ std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
+
+ 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;
+
+ private:
+ TString samplerNamePrefixFromStruct(TIntermTyped *node);
+ bool ancestorEvaluatesToSamplerInStruct(Visit visit);
+};
+
+}
+
+#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.cpp
new file mode 100644
index 000000000..70c0c27cf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.cpp
@@ -0,0 +1,3965 @@
+//
+// 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 "compiler/preprocessor/SourceLocation.h"
+#include "compiler/translator/Cache.h"
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/ValidateSwitch.h"
+#include "compiler/translator/ValidateGlobalInitializer.h"
+#include "compiler/translator/util.h"
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a vector.
+//
+bool TParseContext::parseVectorFields(const TString &compString,
+ int vecSize,
+ TVectorFields &fields,
+ const TSourceLoc &line)
+{
+ fields.num = (int)compString.size();
+ if (fields.num > 4)
+ {
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+
+ enum
+ {
+ exyzw,
+ ergba,
+ estpq
+ } fieldSet[4];
+
+ for (int i = 0; i < fields.num; ++i)
+ {
+ switch (compString[i])
+ {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+ }
+
+ for (int i = 0; i < fields.num; ++i)
+ {
+ if (fields.offsets[i] >= vecSize)
+ {
+ error(line, "vector field selection out of range", compString.c_str());
+ return false;
+ }
+
+ if (i > 0)
+ {
+ if (fieldSet[i] != fieldSet[i - 1])
+ {
+ error(line, "illegal - vector component fields not from the same set",
+ compString.c_str());
+ 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,
+ const char *extraInfo)
+{
+ mDiagnostics.error(loc, reason, token, extraInfo);
+}
+
+void TParseContext::warning(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
+{
+ mDiagnostics.warning(loc, reason, token, extraInfo);
+}
+
+void TParseContext::outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
+{
+ if (isError)
+ {
+ error(loc, reason, token, extraInfo);
+ }
+ else
+ {
+ warning(loc, reason, token, extraInfo);
+ }
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes an operand of type "
+ << operand << " (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand type", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(const TSourceLoc &line,
+ const char *op,
+ TString left,
+ TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "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)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand types ", op, extraInfo.c_str());
+}
+
+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 (IsSampler(type))
+ {
+ error(line, "No precision specified (sampler)", "");
+ return;
+ }
+ }
+ }
+}
+
+// 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)
+{
+ TIntermSymbol *symNode = node->getAsSymbolNode();
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ 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;
+ }
+
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ return checkCanBeLValue(line, op, binaryNode->getLeft());
+ default:
+ break;
+ }
+ error(line, " l-value required", op);
+ return false;
+ }
+
+ const char *symbol = 0;
+ if (symNode != 0)
+ symbol = symNode->getSymbol().c_str();
+
+ const char *message = 0;
+ 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:
+ message = "can't modify an input";
+ break;
+ case EvqVertexIn:
+ 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 EvqComputeIn:
+ message = "can't modify work group size variable";
+ break;
+ default:
+ //
+ // Type that can't be written to?
+ //
+ if (node->getBasicType() == EbtVoid)
+ {
+ message = "can't modify void";
+ }
+ if (IsSampler(node->getBasicType()))
+ {
+ message = "can't modify a sampler";
+ }
+ }
+
+ if (message == 0 && binaryNode == 0 && symNode == 0)
+ {
+ error(line, " l-value required", op);
+
+ return false;
+ }
+
+ //
+ // Everything else is okay, no error.
+ //
+ if (message == 0)
+ return true;
+
+ //
+ // If we get here, we have an error and a message.
+ //
+ if (symNode)
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "\"" << symbol << "\" (" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+ else
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "(" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+
+ 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;
+}
+
+// For now, keep it simple: if it starts "gl_", it's reserved, independent
+// of scope. Except, if the symbol table is at the built-in push-level,
+// which is when we are parsing built-ins.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
+// webgl shader.
+bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &identifier)
+{
+ static const char *reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel())
+ {
+ if (identifier.compare(0, 3, "gl_") == 0)
+ {
+ error(line, reservedErrMsg, "gl_");
+ return false;
+ }
+ if (IsWebGLBasedSpec(mShaderSpec))
+ {
+ if (identifier.compare(0, 6, "webgl_") == 0)
+ {
+ error(line, reservedErrMsg, "webgl_");
+ return false;
+ }
+ if (identifier.compare(0, 7, "_webgl_") == 0)
+ {
+ error(line, reservedErrMsg, "_webgl_");
+ return false;
+ }
+ }
+ if (identifier.find("__") != TString::npos)
+ {
+ error(line,
+ "identifiers containing two consecutive underscores (__) are reserved as "
+ "possible future keywords",
+ identifier.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Make sure there is enough data provided to the constructor to build
+// something of the type of the constructor. Also returns the type of
+// the constructor.
+bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
+ TIntermNode *argumentsNode,
+ const TFunction &function,
+ TOperator op,
+ const TType &type)
+{
+ bool constructingMatrix = false;
+ switch (op)
+ {
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // 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 matrixInMatrix = false;
+ bool arrayArg = false;
+ for (size_t i = 0; i < function.getParamCount(); ++i)
+ {
+ const TConstParameter &param = function.getParam(i);
+ size += param.type->getObjectSize();
+
+ if (constructingMatrix && param.type->isMatrix())
+ matrixInMatrix = true;
+ if (full)
+ overFull = true;
+ if (op != EOpConstructStruct && !type.isArray() && size >= type.getObjectSize())
+ full = true;
+ if (param.type->isArray())
+ arrayArg = true;
+ }
+
+ if (type.isArray())
+ {
+ // The size of an unsized constructor should already have been determined.
+ ASSERT(!type.isUnsizedArray());
+ if (static_cast<size_t>(type.getArraySize()) != function.getParamCount())
+ {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return false;
+ }
+ }
+
+ if (arrayArg && op != EOpConstructStruct)
+ {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return false;
+ }
+
+ if (matrixInMatrix && !type.isArray())
+ {
+ if (function.getParamCount() != 1)
+ {
+ error(line, "constructing matrix from matrix can only take one argument",
+ "constructor");
+ return false;
+ }
+ }
+
+ if (overFull)
+ {
+ error(line, "too many arguments", "constructor");
+ return false;
+ }
+
+ if (op == EOpConstructStruct && !type.isArray() &&
+ type.getStruct()->fields().size() != function.getParamCount())
+ {
+ error(line,
+ "Number of constructor parameters does not match the number of structure fields",
+ "constructor");
+ return false;
+ }
+
+ if (!type.isMatrix() || !matrixInMatrix)
+ {
+ if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) ||
+ (op == EOpConstructStruct && size < type.getObjectSize()))
+ {
+ error(line, "not enough data provided for construction", "constructor");
+ return false;
+ }
+ }
+
+ if (argumentsNode == nullptr)
+ {
+ error(line, "constructor does not have any arguments", "constructor");
+ return false;
+ }
+
+ TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate();
+ for (TIntermNode *&argNode : *argumentsAgg->getSequence())
+ {
+ TIntermTyped *argTyped = argNode->getAsTyped();
+ ASSERT(argTyped != nullptr);
+ if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType()))
+ {
+ error(line, "cannot convert a sampler", "constructor");
+ return false;
+ }
+ if (argTyped->getBasicType() == EbtVoid)
+ {
+ error(line, "cannot convert a void", "constructor");
+ return false;
+ }
+ }
+
+ if (type.isArray())
+ {
+ // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
+ // the array.
+ for (TIntermNode *&argNode : *argumentsAgg->getSequence())
+ {
+ const TType &argType = argNode->getAsTyped()->getType();
+ // It has already been checked that the argument is not an array.
+ ASSERT(!argType.isArray());
+ if (!argType.sameElementType(type))
+ {
+ error(line, "Array constructor argument has an incorrect type", "Error");
+ return false;
+ }
+ }
+ }
+ else if (op == EOpConstructStruct)
+ {
+ const TFieldList &fields = type.getStruct()->fields();
+ TIntermSequence *args = argumentsAgg->getSequence();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
+ {
+ error(line, "Structure constructor arguments do not match structure fields",
+ "Error");
+ 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 TString &identifier,
+ const TBasicType &type)
+{
+ if (type == EbtVoid)
+ {
+ error(line, "illegal use of type 'void'", identifier.c_str());
+ 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 TIntermTyped *type)
+{
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
+ {
+ error(line, "boolean expression expected", "");
+ }
+}
+
+// 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::checkIsNotSampler(const TSourceLoc &line,
+ const TTypeSpecifierNonArray &pType,
+ const char *reason)
+{
+ if (pType.type == EbtStruct)
+ {
+ if (containsSampler(*pType.userDef))
+ {
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+ return false;
+ }
+
+ return true;
+ }
+ else if (IsSampler(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)
+ {
+ error(location, "invalid layout qualifier:", "location",
+ "only valid on program inputs and outputs");
+ }
+}
+
+void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line,
+ TQualifier qualifier,
+ const TType &type)
+{
+ if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct &&
+ IsSampler(type.getBasicType()))
+ {
+ error(line, "samplers cannot be output parameters", type.getBasicString());
+ }
+}
+
+bool TParseContext::containsSampler(const TType &type)
+{
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
+ {
+ const TFieldList &fields = type.getStruct()->fields();
+ for (unsigned int i = 0; i < fields.size(); ++i)
+ {
+ if (containsSampler(*fields[i]->type()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Do size checking for an array type's size.
+unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr)
+{
+ TIntermConstantUnion *constant = expr->getAsConstantUnion();
+
+ // TODO(oetuaho@nvidia.com): Get rid of the constant == nullptr check here once all constant
+ // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+ // fold as array size.
+ 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::checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType)
+{
+ //
+ // Can the type be an array?
+ //
+ if (elementType.array)
+ {
+ error(line, "cannot declare arrays of arrays",
+ TType(elementType).getCompleteString().c_str());
+ 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).
+ if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
+ sh::IsVarying(elementType.qualifier))
+ {
+ error(line, "cannot declare arrays of structs of this qualifier",
+ TType(elementType).getCompleteString().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Check if this qualified element type can be formed into an array.
+bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
+ const TPublicType &elementType)
+{
+ if (checkIsValidTypeForArray(indexLocation, elementType))
+ {
+ return checkIsValidQualifierForArray(indexLocation, elementType);
+ }
+ return false;
+}
+
+// Enforce non-initializer type/qualifier rules.
+void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ TPublicType *type)
+{
+ ASSERT(type != nullptr);
+ if (type->qualifier == EvqConst)
+ {
+ // Make the qualifier make sense.
+ type->qualifier = 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.c_str());
+ }
+ else
+ {
+ error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
+ }
+ return;
+ }
+ if (type->isUnsizedArray())
+ {
+ error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
+ }
+}
+
+// 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 TString &identifier,
+ const TType &type,
+ TVariable **variable)
+{
+ ASSERT((*variable) == nullptr);
+
+ bool needsReservedCheck = true;
+
+ // gl_LastFragData may be redeclared with a new precision qualifier
+ if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
+ {
+ const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
+ symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
+ if (static_cast<int>(type.getArraySize()) == maxDrawBuffers->getConstPointer()->getIConst())
+ {
+ if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
+ {
+ needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->getExtension());
+ }
+ }
+ else
+ {
+ error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
+ identifier.c_str());
+ return false;
+ }
+ }
+
+ if (needsReservedCheck && !checkIsNotReserved(line, identifier))
+ return false;
+
+ (*variable) = new TVariable(&identifier, type);
+ if (!symbolTable.declare(*variable))
+ {
+ error(line, "redefinition", identifier.c_str());
+ *variable = nullptr;
+ return false;
+ }
+
+ if (!checkIsNonVoid(line, identifier, type.getBasicType()))
+ return false;
+
+ return true;
+}
+
+void TParseContext::checkIsParameterQualifierValid(
+ const TSourceLoc &line,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TType *type)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics);
+
+ if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
+ {
+ checkOutParameterIsNotSampler(line, typeQualifier.qualifier, *type);
+ }
+
+ type->setQualifier(typeQualifier.qualifier);
+
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ type->setPrecision(typeQualifier.precision);
+ }
+}
+
+bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension)
+{
+ const TExtensionBehavior &extBehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
+ if (iter == extBehavior.end())
+ {
+ error(line, "extension", extension.c_str(), "is not supported");
+ return false;
+ }
+ // In GLSL ES, an extension's default behavior is "disable".
+ if (iter->second == EBhDisable || iter->second == EBhUndefined)
+ {
+ error(line, "extension", extension.c_str(), "is disabled");
+ return false;
+ }
+ if (iter->second == EBhWarn)
+ {
+ warning(line, "extension", extension.c_str(), "is being used");
+ return true;
+ }
+
+ return true;
+}
+
+// These checks are common for all declarations starting a declarator list, and declarators that
+// follow an empty declaration.
+void TParseContext::singleDeclarationErrorCheck(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;
+ }
+
+ default:
+ break;
+ }
+
+ if (publicType.qualifier != EvqUniform &&
+ !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
+ "samplers must be uniform"))
+ {
+ return;
+ }
+
+ // check for layout qualifier issues
+ const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ error(identifierLocation, "layout qualifier",
+ getMatrixPackingString(layoutQualifier.matrixPacking),
+ "only valid for interface blocks");
+ return;
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(identifierLocation, "layout qualifier",
+ getBlockStorageString(layoutQualifier.blockStorage),
+ "only valid for interface blocks");
+ return;
+ }
+
+ if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut)
+ {
+ checkLocationIsNotSpecified(identifierLocation, publicType.layoutQualifier);
+ }
+}
+
+void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
+ const TString &layoutQualifierName,
+ int versionRequired)
+{
+
+ if (mShaderVersion < versionRequired)
+ {
+ error(location, "invalid layout qualifier:", layoutQualifierName.c_str(), "not supported");
+ }
+}
+
+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:", getWorkGroupSizeString(i),
+ "only valid when used with 'in' in a compute shader global layout declaration");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
+ TIntermAggregate *fnCall)
+{
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
+ {
+ TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut)
+ {
+ TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped();
+ if (!checkCanBeLValue(argument->getLine(), "assign", argument))
+ {
+ error(argument->getLine(),
+ "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ 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::supportsExtension(const char *extension)
+{
+ const TExtensionBehavior &extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+ return (iter != extbehavior.end());
+}
+
+bool TParseContext::isExtensionEnabled(const char *extension) const
+{
+ return ::IsExtensionEnabled(extensionBehavior(), extension);
+}
+
+void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
+ const char *extName,
+ const char *behavior)
+{
+ 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)
+{
+ 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;
+ for (size_t i = 0u; i < result.size(); ++i)
+ {
+ if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1)
+ {
+ result[i] = 1;
+ }
+ else
+ {
+ result[i] = mComputeShaderLocalSize[i];
+ }
+ }
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
+ const TString *name,
+ const TSymbol *symbol)
+{
+ const TVariable *variable = NULL;
+
+ if (!symbol)
+ {
+ error(location, "undeclared identifier", name->c_str());
+ }
+ else if (!symbol->isVariable())
+ {
+ error(location, "variable expected", name->c_str());
+ }
+ else
+ {
+ variable = static_cast<const TVariable *>(symbol);
+
+ if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
+ !variable->getExtension().empty())
+ {
+ checkCanUseExtension(location, variable->getExtension());
+ }
+
+ // Reject shaders using both gl_FragData and gl_FragColor
+ TQualifier qualifier = variable->getType().getQualifier();
+ if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
+ {
+ mUsesFragData = true;
+ }
+ else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
+ {
+ mUsesFragColor = true;
+ }
+ if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
+ {
+ mUsesSecondaryOutputs = true;
+ }
+
+ // This validation is not quite correct - it's only an error to write to
+ // both FragData and FragColor. For simplicity, and because users shouldn't
+ // be rewarded for reading from undefined varaibles, return an error
+ // if they are both referenced, rather than assigned.
+ if (mUsesFragData && mUsesFragColor)
+ {
+ const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
+ if (mUsesSecondaryOutputs)
+ {
+ errorMessage =
+ "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
+ " and (gl_FragColor, gl_SecondaryFragColorEXT)";
+ }
+ error(location, errorMessage, name->c_str());
+ }
+
+ // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables
+ if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared &&
+ qualifier == EvqWorkGroupSize)
+ {
+ error(location,
+ "It is an error to use gl_WorkGroupSize before declaring the local group size",
+ "gl_WorkGroupSize");
+ }
+ }
+
+ if (!variable)
+ {
+ TType type(EbtFloat, EbpUndefined);
+ TVariable *fakeVariable = new TVariable(name, type);
+ symbolTable.declare(fakeVariable);
+ variable = fakeVariable;
+ }
+
+ return variable;
+}
+
+TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
+ const TString *name,
+ const TSymbol *symbol)
+{
+ const TVariable *variable = getNamedVariable(location, name, symbol);
+
+ if (variable->getConstPointer())
+ {
+ const TConstantUnion *constArray = variable->getConstPointer();
+ return intermediate.addConstantUnion(constArray, variable->getType(), location);
+ }
+ else
+ {
+ return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
+ variable->getType(), location);
+ }
+}
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise 0.
+//
+const TFunction *TParseContext::findFunction(const TSourceLoc &line,
+ TFunction *call,
+ int inputShaderVersion,
+ bool *builtIn)
+{
+ // First find by unmangled name to check whether the function name has been
+ // hidden by a variable name or struct typename.
+ // If a function is found, check for one with a matching argument list.
+ const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
+ if (symbol == 0 || symbol->isFunction())
+ {
+ symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
+ }
+
+ if (symbol == 0)
+ {
+ error(line, "no matching overloaded function found", call->getName().c_str());
+ return 0;
+ }
+
+ if (!symbol->isFunction())
+ {
+ error(line, "function name expected", call->getName().c_str());
+ return 0;
+ }
+
+ return static_cast<const TFunction *>(symbol);
+}
+
+//
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+// Returns true on error, false if no error
+//
+bool TParseContext::executeInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ const TPublicType &pType,
+ TIntermTyped *initializer,
+ TIntermNode **intermNode)
+{
+ ASSERT(intermNode != nullptr);
+ TType type = TType(pType);
+
+ TVariable *variable = nullptr;
+ if (type.isUnsizedArray())
+ {
+ type.setArraySize(initializer->getArraySize());
+ }
+ if (!declareVariable(line, identifier, type, &variable))
+ {
+ return true;
+ }
+
+ bool globalInitWarning = false;
+ if (symbolTable.atGlobalLevel() &&
+ !ValidateGlobalInitializer(initializer, this, &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 true;
+ }
+ 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
+ //
+ TQualifier qualifier = variable->getType().getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
+ {
+ error(line, " cannot initialize this type of qualifier ",
+ variable->getType().getQualifierString());
+ return true;
+ }
+ //
+ // test for and propagate constant
+ //
+
+ if (qualifier == EvqConst)
+ {
+ if (qualifier != initializer->getType().getQualifier())
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " assigning non-constant to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (type != initializer->getType())
+ {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+
+ // Save the constant folded value to the variable if possible. For example array
+ // initializers are not folded, since that way copying the array literal to multiple places
+ // in the shader is avoided.
+ // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
+ // it would be beneficial.
+ if (initializer->getAsConstantUnion())
+ {
+ variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+ *intermNode = nullptr;
+ return false;
+ }
+ else if (initializer->getAsSymbolNode())
+ {
+ const TSymbol *symbol =
+ symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
+ const TVariable *tVar = static_cast<const TVariable *>(symbol);
+
+ const TConstantUnion *constArray = tVar->getConstPointer();
+ if (constArray)
+ {
+ variable->shareConstPointer(constArray);
+ *intermNode = nullptr;
+ return false;
+ }
+ }
+ }
+
+ TIntermSymbol *intermSymbol = intermediate.addSymbol(
+ variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (*intermNode == nullptr)
+ {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
+ }
+
+ return false;
+}
+
+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.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.array)
+ {
+ 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.array)
+ {
+ error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
+ }
+ // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
+ 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 singleDeclarationErrorCheck
+ 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.array)
+ {
+ 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));
+ }
+ }
+}
+
+TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const TString &identifier)
+{
+ TType type(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.
+ //
+ // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of
+ // the specification, but there are desktop OpenGL drivers that expect that this is the
+ // behavior of the #pragma when specified in ESSL 1.00 fragment shaders.
+ if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn)
+ {
+ type.setInvariant(true);
+ }
+ }
+
+ TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, type, identifierOrTypeLocation);
+
+ bool emptyDeclaration = (identifier == "");
+
+ mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
+
+ if (emptyDeclaration)
+ {
+ if (publicType.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(identifierOrTypeLocation, "empty array declaration needs to specify a size",
+ identifier.c_str());
+ }
+ }
+ else
+ {
+ singleDeclarationErrorCheck(publicType, identifierOrTypeLocation);
+
+ checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &publicType);
+
+ TVariable *variable = nullptr;
+ declareVariable(identifierOrTypeLocation, identifier, type, &variable);
+
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+
+ return TIntermediate::MakeAggregate(symbol, identifierOrTypeLocation);
+}
+
+TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression)
+{
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
+
+ TType arrayType(publicType);
+
+ unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression);
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
+
+ TVariable *variable = nullptr;
+ declareVariable(identifierLocation, identifier, arrayType, &variable);
+
+ TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+
+ return TIntermediate::MakeAggregate(symbol, identifierLocation);
+}
+
+TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
+ {
+ //
+ // Build intermediate representation
+ //
+ return intermNode ? TIntermediate::MakeAggregate(intermNode, initLocation) : nullptr;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
+ TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
+
+ TPublicType arrayType(publicType);
+
+ unsigned int size = 0u;
+ // If indexExpression is nullptr, then the array will eventually get its size implicitly from
+ // the initializer.
+ if (indexExpression != nullptr)
+ {
+ size = checkIsValidArraySize(identifierLocation, indexExpression);
+ }
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
+
+ // initNode will correspond to the whole of "type b[n] = initializer".
+ TIntermNode *initNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ return initNode ? TIntermediate::MakeAggregate(initNode, initLocation) : nullptr;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+TIntermAggregate *TParseContext::parseInvariantDeclaration(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &identifierLoc,
+ const TString *identifier,
+ const TSymbol *symbol)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
+ if (!typeQualifier.invariant)
+ {
+ error(identifierLoc, "Expected invariant", identifier->c_str());
+ return nullptr;
+ }
+ if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
+ {
+ return nullptr;
+ }
+ if (!symbol)
+ {
+ error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
+ 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);
+ ASSERT(variable);
+ const TType &type = variable->getType();
+
+ checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(),
+ typeQualifier.line);
+
+ symbolTable.addInvariantVarying(std::string(identifier->c_str()));
+
+ TIntermSymbol *intermSymbol =
+ intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
+
+ TIntermAggregate *aggregate = TIntermediate::MakeAggregate(intermSymbol, identifierLoc);
+ aggregate->setOp(EOpInvariantDeclaration);
+ return aggregate;
+}
+
+TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
+
+ TVariable *variable = nullptr;
+ declareVariable(identifierLocation, identifier, TType(publicType), &variable);
+
+ TIntermSymbol *symbol =
+ intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
+}
+
+TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &arrayLocation,
+ TIntermTyped *indexExpression)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
+
+ if (checkIsValidTypeAndQualifierForArray(arrayLocation, publicType))
+ {
+ TType arrayType = TType(publicType);
+ unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression);
+ arrayType.setArraySize(size);
+
+ TVariable *variable = nullptr;
+ declareVariable(identifierLocation, identifier, arrayType, &variable);
+
+ TIntermSymbol *symbol =
+ intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
+ }
+
+ return nullptr;
+}
+
+TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
+ {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ {
+ return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
+ }
+ else
+ {
+ return aggregateDeclaration;
+ }
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ singleDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
+
+ TPublicType arrayType(publicType);
+
+ unsigned int size = 0u;
+ // If indexExpression is nullptr, then the array will eventually get its size implicitly from
+ // the initializer.
+ if (indexExpression != nullptr)
+ {
+ size = checkIsValidArraySize(identifierLocation, indexExpression);
+ }
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
+
+ // initNode will correspond to the whole of "b[n] = initializer".
+ TIntermNode *initNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ if (initNode)
+ {
+ return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
+ }
+ else
+ {
+ return aggregateDeclaration;
+ }
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+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 combination:", "layout");
+ return;
+ }
+
+ 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("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 errorMessageStream;
+ errorMessageStream << "Value must be at least 1 and no greater than "
+ << maxComputeWorkGroupSizeValue;
+ const std::string &errorMessage = errorMessageStream.str();
+
+ error(typeQualifier.line, "invalid value:", getWorkGroupSizeString(i),
+ errorMessage.c_str());
+ return;
+ }
+ }
+ }
+
+ mComputeShaderLocalSizeDeclared = true;
+ }
+ else
+ {
+
+ if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier))
+ {
+ return;
+ }
+
+ if (typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:",
+ getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
+ return;
+ }
+
+ if (mShaderVersion < 300)
+ {
+ error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above",
+ "layout");
+ return;
+ }
+
+ checkLocationIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier);
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ mDefaultMatrixPacking = layoutQualifier.matrixPacking;
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ mDefaultBlockStorage = layoutQualifier.blockStorage;
+ }
+ }
+}
+
+TIntermAggregate *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.
+ TFunction *function = static_cast<TFunction *>(
+ symbolTable.find(parsedFunction.getMangledName(), getShaderVersion()));
+ if (function->hasPrototypeDeclaration() && 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");
+ }
+ function->setHasPrototypeDeclaration();
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ // TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could
+ // point to the data that already exists in the symbol table.
+ prototype->setType(function->getReturnType());
+ prototype->getFunctionSymbolInfo()->setFromFunction(*function);
+
+ for (size_t i = 0; i < function->getParamCount(); i++)
+ {
+ const TConstParameter &param = function->getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ TIntermSymbol *paramSymbol = intermediate.addSymbol(
+ variable.getUniqueId(), variable.getName(), variable.getType(), location);
+ prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ }
+ else
+ {
+ TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
+ prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+
+ 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(
+ const TFunction &function,
+ TIntermAggregate *functionParameters,
+ TIntermBlock *functionBody,
+ const TSourceLoc &location)
+{
+ // Check that non-void functions have at least one return statement.
+ if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
+ {
+ error(location, "function does not return a value:", "", function.getName().c_str());
+ }
+
+ if (functionBody == nullptr)
+ {
+ functionBody = new TIntermBlock();
+ functionBody->setLine(location);
+ }
+ TIntermFunctionDefinition *functionNode =
+ new TIntermFunctionDefinition(function.getReturnType(), functionParameters, functionBody);
+ functionNode->setLine(location);
+
+ functionNode->getFunctionSymbolInfo()->setFromFunction(function);
+
+ symbolTable.pop();
+ return functionNode;
+}
+
+void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
+ TFunction **function,
+ TIntermAggregate **aggregateOut)
+{
+ ASSERT(function);
+ ASSERT(*function);
+ const TSymbol *builtIn =
+ symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
+
+ if (builtIn)
+ {
+ error(location, "built-in functions cannot be redefined", (*function)->getName().c_str());
+ }
+ else
+ {
+ TFunction *prevDec = static_cast<TFunction *>(
+ symbolTable.find((*function)->getMangledName(), getShaderVersion()));
+
+ // Note: 'prevDec' 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 != prevDec)
+ {
+ // Swap the parameters of the previous declaration to the parameters of the function
+ // definition (parameter names may differ).
+ prevDec->swapParameters(**function);
+
+ // The function definition will share the same symbol as any previous declaration.
+ *function = prevDec;
+ }
+
+ if ((*function)->isDefined())
+ {
+ error(location, "function already has a body", (*function)->getName().c_str());
+ }
+
+ (*function)->setDefined();
+ }
+
+ // Raise error message if main function takes any parameters or return anything other than void
+ if ((*function)->getName() == "main")
+ {
+ if ((*function)->getParamCount() > 0)
+ {
+ error(location, "function cannot take any parameter(s)",
+ (*function)->getName().c_str());
+ }
+ if ((*function)->getReturnType().getBasicType() != EbtVoid)
+ {
+ error(location, "", (*function)->getReturnType().getBasicString(),
+ "main function cannot return a value");
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ mCurrentFunctionType = &((*function)->getReturnType());
+ mFunctionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate *paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < (*function)->getParamCount(); i++)
+ {
+ const TConstParameter &param = (*function)->getParam(i);
+ if (param.name != 0)
+ {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (!symbolTable.declare(variable))
+ {
+ error(location, "redefinition", variable->getName().c_str());
+ paramNodes = intermediate.growAggregate(
+ paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
+ continue;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ TIntermSymbol *symbol = intermediate.addSymbol(
+ variable->getUniqueId(), variable->getName(), variable->getType(), location);
+
+ paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
+ }
+ else
+ {
+ paramNodes = intermediate.growAggregate(
+ paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
+ }
+ }
+ intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
+ *aggregateOut = paramNodes;
+ setLoopNestingLevel(0);
+}
+
+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.
+ //
+ // Return types and parameter qualifiers must match in all redeclarations, so those are checked
+ // here.
+ //
+ TFunction *prevDec =
+ static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+
+ if (getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str()))
+ {
+ // With ESSL 3.00, 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->getName().c_str());
+ }
+ else 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).type->getQualifier() !=
+ function->getParam(i).type->getQualifier())
+ {
+ error(location,
+ "function must have the same parameter qualifiers in all of its declarations",
+ function->getParam(i).type->getQualifierString());
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ error(location, "redefinition", function->getName().c_str(), "function");
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ symbolTable.getOuterLevel()->insertUnmangled(function);
+ }
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ symbolTable.getOuterLevel()->insert(function);
+
+ //
+ // 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 TString *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 a sampler is not involved as well...
+ checkIsNotSampler(location, type.typeSpecifierNonArray,
+ "samplers can't be function return values");
+ 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.arraySize == 0 || mDiagnostics.numErrors() > 0);
+
+ if (type.isStructureContainingArrays())
+ {
+ // ESSL 1.00.17 section 6.1 Function Definitions
+ error(location, "structures containing arrays can't be function return values",
+ TType(type).getCompleteString().c_str());
+ }
+ }
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ return new TFunction(name, new TType(type));
+}
+
+TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
+{
+ TPublicType publicType = publicTypeIn;
+ if (publicType.isStructSpecifier())
+ {
+ error(publicType.getLine(), "constructor can't be a structure definition",
+ getBasicString(publicType.getBasicType()));
+ }
+
+ TOperator op = EOpNull;
+ if (publicType.getUserDef())
+ {
+ op = EOpConstructStruct;
+ }
+ else
+ {
+ op = sh::TypeToConstructorOperator(TType(publicType));
+ if (op == EOpNull)
+ {
+ error(publicType.getLine(), "cannot construct this type",
+ getBasicString(publicType.getBasicType()));
+ publicType.setBasicType(EbtFloat);
+ op = EOpConstructFloat;
+ }
+ }
+
+ TString tempString;
+ const TType *type = new TType(publicType);
+ return new TFunction(&tempString, type, op);
+}
+
+// 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(TIntermNode *arguments,
+ TOperator op,
+ TFunction *fnCall,
+ const TSourceLoc &line)
+{
+ TType type = fnCall->getReturnType();
+ if (type.isUnsizedArray())
+ {
+ type.setArraySize(static_cast<unsigned int>(fnCall->getParamCount()));
+ }
+ bool constType = true;
+ for (size_t i = 0; i < fnCall->getParamCount(); ++i)
+ {
+ const TConstParameter &param = fnCall->getParam(i);
+ if (param.type->getQualifier() != EvqConst)
+ constType = false;
+ }
+ if (constType)
+ type.setQualifier(EvqConst);
+
+ if (!checkConstructorArguments(line, arguments, *fnCall, op, type))
+ {
+ TIntermTyped *dummyNode = intermediate.setAggregateOperator(nullptr, op, line);
+ dummyNode->setType(type);
+ return dummyNode;
+ }
+ TIntermAggregate *constructor = arguments->getAsAggregate();
+ ASSERT(constructor != nullptr);
+
+ // Turn the argument list itself into a constructor
+ constructor->setOp(op);
+ constructor->setLine(line);
+ ASSERT(constructor->isConstructor());
+
+ // Need to set type before setPrecisionFromChildren() because bool doesn't have precision.
+ constructor->setType(type);
+
+ // Structs should not be precision qualified, the individual members may be.
+ // Built-in types on the other hand should be precision qualified.
+ if (op != EOpConstructStruct)
+ {
+ constructor->setPrecisionFromChildren();
+ type.setPrecision(constructor->getPrecision());
+ }
+
+ constructor->setType(type);
+
+ TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
+ if (constConstructor)
+ {
+ return constConstructor;
+ }
+
+ return constructor;
+}
+
+//
+// Interface/uniform blocks
+//
+TIntermAggregate *TParseContext::addInterfaceBlock(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &nameLine,
+ const TString &blockName,
+ TFieldList *fieldList,
+ const TString *instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine)
+{
+ checkIsNotReserved(nameLine, blockName);
+
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
+ if (typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
+ "interface blocks must be uniform");
+ }
+
+ if (typeQualifier.invariant)
+ {
+ error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
+ }
+
+ TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
+ checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
+
+ if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
+ }
+
+ if (blockLayoutQualifier.blockStorage == EbsUnspecified)
+ {
+ blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
+ }
+
+ checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier);
+
+ TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
+ if (!symbolTable.declare(blockNameSymbol))
+ {
+ error(nameLine, "redefinition", blockName.c_str(), "interface block name");
+ }
+
+ // 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 (IsSampler(fieldType->getBasicType()))
+ {
+ error(field->line(), "unsupported type", fieldType->getBasicString(),
+ "sampler types are not allowed in interface blocks");
+ }
+
+ const TQualifier qualifier = fieldType->getQualifier();
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ case EvqUniform:
+ 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);
+
+ if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(field->line(), "invalid layout qualifier:",
+ getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
+ }
+
+ if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
+ }
+ else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
+ {
+ warning(field->line(), "extraneous layout qualifier:",
+ getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
+ "only has an effect on matrix types");
+ }
+
+ fieldType->setLayoutQualifier(fieldLayoutQualifier);
+ }
+
+ // add array index
+ unsigned int arraySize = 0;
+ if (arrayIndex != nullptr)
+ {
+ arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
+ }
+
+ TInterfaceBlock *interfaceBlock =
+ new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
+ TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
+ arraySize);
+
+ TString symbolName = "";
+ int symbolId = 0;
+
+ if (!instanceName)
+ {
+ // define symbols for the members of the interface block
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField *field = (*fieldList)[memberIndex];
+ TType *fieldType = field->type();
+
+ // set parent pointer of the field variable
+ fieldType->setInterfaceBlock(interfaceBlock);
+
+ TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
+ fieldVariable->setQualifier(typeQualifier.qualifier);
+
+ if (!symbolTable.declare(fieldVariable))
+ {
+ error(field->line(), "redefinition", field->name().c_str(),
+ "interface block member name");
+ }
+ }
+ }
+ else
+ {
+ checkIsNotReserved(instanceLine, *instanceName);
+
+ // add a symbol for this interface block
+ TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
+ instanceTypeDef->setQualifier(typeQualifier.qualifier);
+
+ if (!symbolTable.declare(instanceTypeDef))
+ {
+ error(instanceLine, "redefinition", instanceName->c_str(),
+ "interface block instance name");
+ }
+
+ symbolId = instanceTypeDef->getUniqueId();
+ symbolName = instanceTypeDef->getName();
+ }
+
+ TIntermAggregate *aggregate = TIntermediate::MakeAggregate(
+ intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
+ nameLine);
+ aggregate->setOp(EOpDeclaration);
+
+ exitStructDeclaration();
+ return aggregate;
+}
+
+void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
+{
+ ++mStructNestingLevel;
+
+ // Embedded structure definitions are not supported per GLSL ES spec.
+ // They aren't allowed in GLSL either, but we need to detect this here
+ // so we don't rely on the GLSL compiler to catch it.
+ if (mStructNestingLevel > 1)
+ {
+ error(line, "", "Embedded struct definitions are not allowed");
+ }
+}
+
+void TParseContext::exitStructDeclaration()
+{
+ --mStructNestingLevel;
+}
+
+namespace
+{
+const int kWebGLMaxStructNesting = 4;
+
+} // namespace
+
+void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field)
+{
+ if (!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;
+ reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
+ << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
+ std::string reason = reasonStream.str();
+ error(line, reason.c_str(), field.name().c_str(), "");
+ 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()->getSymbol().c_str());
+ }
+ else
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
+ }
+
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst),
+ location);
+ }
+
+ TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
+
+ // TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
+ // to constant fold all constant expressions. Right now we don't allow indexing interface blocks
+ // or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
+ // index is a constant expression.
+ if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
+ {
+ if (baseExpression->isInterfaceBlock())
+ {
+ error(
+ location, "", "[",
+ "array indexes for interface blocks arrays must be constant integral expressions");
+ }
+ 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 = indexConstantUnion->getIConst(0);
+
+ int safeIndex = -1;
+
+ if (baseExpression->isArray())
+ {
+ if (baseExpression->getQualifier() == EvqFragData && index > 0)
+ {
+ if (mShaderSpec == SH_WEBGL2_SPEC)
+ {
+ // Error has been already generated if index is not const.
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ error(location, "", "[",
+ "array index for gl_FragData must be constant zero");
+ }
+ safeIndex = 0;
+ }
+ else if (!isExtensionEnabled("GL_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)
+ {
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getArraySize(),
+ "array index out of range", "[]");
+ }
+ }
+ else if (baseExpression->isMatrix())
+ {
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getCols(),
+ "matrix field selection out of range", "[]");
+ }
+ else if (baseExpression->isVector())
+ {
+ safeIndex = checkIndexOutOfRange(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)
+ {
+ TConstantUnion *safeConstantUnion = new TConstantUnion();
+ safeConstantUnion->setIConst(safeIndex);
+ indexConstantUnion->replaceConstantUnion(safeConstantUnion);
+ }
+
+ return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
+ &mDiagnostics);
+ }
+ else
+ {
+ return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
+ &mDiagnostics);
+ }
+}
+
+int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError,
+ const TSourceLoc &location,
+ int index,
+ int arraySize,
+ const char *reason,
+ const char *token)
+{
+ if (index >= arraySize || index < 0)
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ outOfRangeError(outOfRangeIndexIsError, location, reason, token, extraInfo.c_str());
+ if (index < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return arraySize - 1;
+ }
+ }
+ return index;
+}
+
+TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const TString &fieldString,
+ const TSourceLoc &fieldLocation)
+{
+ if (baseExpression->isArray())
+ {
+ error(fieldLocation, "cannot apply dot operator to an array", ".");
+ return baseExpression;
+ }
+
+ if (baseExpression->isVector())
+ {
+ TVectorFields fields;
+ if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
+ fieldLocation))
+ {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ }
+
+ return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation);
+ }
+ 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 = TIntermTyped::CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
+ dotLocation, &mDiagnostics);
+ }
+ else
+ {
+ error(dotLocation, " no such field in structure", fieldString.c_str());
+ 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 = TIntermTyped::CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
+ dotLocation, &mDiagnostics);
+ }
+ else
+ {
+ error(dotLocation, " no such field in interface block", fieldString.c_str());
+ return baseExpression;
+ }
+ }
+ }
+ else
+ {
+ if (mShaderVersion < 300)
+ {
+ error(dotLocation, " field selection requires structure or vector on left hand side",
+ fieldString.c_str());
+ }
+ else
+ {
+ error(dotLocation,
+ " field selection requires structure, vector, or interface block on left hand "
+ "side",
+ fieldString.c_str());
+ }
+ return baseExpression;
+ }
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine)
+{
+ TLayoutQualifier qualifier = TLayoutQualifier::create();
+
+ if (qualifierType == "shared")
+ {
+ if (IsWebGLBasedSpec(mShaderSpec))
+ {
+ error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared");
+ }
+ qualifier.blockStorage = EbsShared;
+ }
+ else if (qualifierType == "packed")
+ {
+ if (IsWebGLBasedSpec(mShaderSpec))
+ {
+ error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed");
+ }
+ qualifier.blockStorage = EbsPacked;
+ }
+ 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", qualifierType.c_str(),
+ "location requires an argument");
+ }
+ else
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
+ }
+
+ return qualifier;
+}
+
+void TParseContext::parseLocalSize(const TString &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::string errorMessage = std::string(getWorkGroupSizeString(index)) + " must be positive";
+ error(intValueLine, "out of range:", intValueString.c_str(), errorMessage.c_str());
+ }
+ (*localSize)[index] = intValue;
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &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:", intValueString.c_str(),
+ "location must be non-negative");
+ }
+ else
+ {
+ qualifier.location = intValue;
+ qualifier.locationsSpecified = 1;
+ }
+ }
+ 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
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
+ }
+
+ return qualifier;
+}
+
+TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
+{
+ return new TTypeQualifierBuilder(
+ new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
+ mShaderVersion);
+}
+
+TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation)
+{
+ return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
+ &mDiagnostics);
+}
+
+TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TPublicType *typeSpecifier,
+ TFieldList *fieldList)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
+ typeSpecifier->qualifier = typeQualifier.qualifier;
+ typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
+ typeSpecifier->invariant = typeQualifier.invariant;
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ typeSpecifier->precision = typeQualifier.precision;
+ }
+ return addStructDeclaratorList(*typeSpecifier, fieldList);
+}
+
+TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
+ TFieldList *fieldList)
+{
+ checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
+ typeSpecifier.getBasicType());
+
+ checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType());
+
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
+
+ for (unsigned int i = 0; i < fieldList->size(); ++i)
+ {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType *type = (*fieldList)[i]->type();
+ type->setBasicType(typeSpecifier.getBasicType());
+ type->setPrimarySize(typeSpecifier.getPrimarySize());
+ type->setSecondarySize(typeSpecifier.getSecondarySize());
+ type->setPrecision(typeSpecifier.precision);
+ type->setQualifier(typeSpecifier.qualifier);
+ type->setLayoutQualifier(typeSpecifier.layoutQualifier);
+ type->setInvariant(typeSpecifier.invariant);
+
+ // don't allow arrays of arrays
+ if (type->isArray())
+ {
+ checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
+ }
+ if (typeSpecifier.array)
+ type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize));
+ if (typeSpecifier.getUserDef())
+ {
+ type->setStruct(typeSpecifier.getUserDef()->getStruct());
+ }
+
+ checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]);
+ }
+
+ return fieldList;
+}
+
+TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList)
+{
+ TStructure *structure = new TStructure(structName, fieldList);
+ TType *structureType = new TType(structure);
+
+ // 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 (!structName->empty())
+ {
+ checkIsNotReserved(nameLine, *structName);
+ TVariable *userTypeDef = new TVariable(structName, *structureType, true);
+ if (!symbolTable.declare(userTypeDef))
+ {
+ error(nameLine, "redefinition", structName->c_str(), "struct");
+ }
+ }
+
+ // ensure we do not specify any storage qualifiers on the struct members
+ for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
+ {
+ const 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");
+ }
+
+ checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
+ }
+
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ typeSpecifierNonArray.initialize(EbtStruct, structLine);
+ typeSpecifierNonArray.userDef = structureType;
+ typeSpecifierNonArray.isStructSpecifier = true;
+ 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;
+ }
+
+ if (statementList)
+ {
+ if (!ValidateSwitch::validate(switchType, this, statementList, loc))
+ {
+ return nullptr;
+ }
+ }
+
+ TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
+ if (node == nullptr)
+ {
+ error(loc, "erroneous switch statement", "switch");
+ return nullptr;
+ }
+ 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();
+ // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant
+ // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+ // fold in case labels.
+ if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
+ {
+ error(condition->getLine(), "case label must be constant", "case");
+ }
+ TIntermCase *node = intermediate.addCase(condition, loc);
+ if (node == nullptr)
+ {
+ error(loc, "erroneous case statement", "case");
+ return nullptr;
+ }
+ 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 = intermediate.addCase(nullptr, loc);
+ if (node == nullptr)
+ {
+ error(loc, "erroneous default statement", "default");
+ return nullptr;
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::createUnaryMath(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc,
+ const TType *funcReturnType)
+{
+ if (child == nullptr)
+ {
+ return nullptr;
+ }
+
+ switch (op)
+ {
+ case EOpLogicalNot:
+ if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
+ child->isVector())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpBitwiseNot:
+ if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
+ child->isMatrix() || child->isArray())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ case EOpPositive:
+ if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
+ child->isArray() || IsSampler(child->getBasicType()))
+ {
+ return nullptr;
+ }
+ // Operators for built-ins are already type checked against their prototype.
+ default:
+ break;
+ }
+
+ TIntermUnary *node = new TIntermUnary(op, child);
+ node->setLine(loc);
+
+ TIntermTyped *foldedNode = node->fold(&mDiagnostics);
+ if (foldedNode)
+ return foldedNode;
+
+ return node;
+}
+
+TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
+{
+ TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
+ if (node == nullptr)
+ {
+ unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
+ return child;
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc)
+{
+ checkCanBeLValue(loc, GetOperatorString(op), child);
+ return addUnaryMath(op, child, loc);
+}
+
+bool TParseContext::binaryOpCommonCheck(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ 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->isArray() || right->isArray())
+ {
+ if (mShaderVersion < 300)
+ {
+ error(loc, "Invalid operation for arrays", GetOperatorString(op));
+ return false;
+ }
+
+ if (left->isArray() != right->isArray())
+ {
+ error(loc, "array / non-array mismatch", 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->getArraySize() != right->getArraySize())
+ {
+ 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;
+ }
+
+ // GLSL ES 1.00 and 3.00 do not support implicit type casting.
+ // So the basic type should usually match.
+ if (!isBitShift && left->getBasicType() != right->getBasicType())
+ {
+ 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;
+ }
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->getNominalSize() != right->getNominalSize()) ||
+ (left->getSecondarySize() != right->getSecondarySize()))
+ {
+ 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:
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
+ !right->getType().getStruct());
+ if (left->isMatrix() || left->isVector())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
+ !right->getType().getStruct());
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
+ {
+ return nullptr;
+ }
+ 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);
+ node->setLine(loc);
+
+ // See if we can fold constants.
+ TIntermTyped *foldedNode = node->fold(&mDiagnostics);
+ if (foldedNode)
+ return foldedNode;
+
+ return 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->getCompleteString(),
+ right->getCompleteString());
+ 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 == 0)
+ {
+ binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
+ right->getCompleteString());
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setBConst(false);
+ return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
+ loc);
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::createAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ if (binaryOpCommonCheck(op, left, right, loc))
+ {
+ if (op == EOpMulAssign)
+ {
+ op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType());
+ if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
+ {
+ return nullptr;
+ }
+ }
+ TIntermBinary *node = new TIntermBinary(op, left, right);
+ node->setLine(loc);
+
+ return node;
+ }
+ return nullptr;
+}
+
+TIntermTyped *TParseContext::addAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ TIntermTyped *node = createAssign(op, left, right, loc);
+ if (node == nullptr)
+ {
+ assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
+ return left;
+ }
+ 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",
+ ",");
+ }
+
+ return TIntermediate::AddComma(left, right, loc, mShaderVersion);
+}
+
+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;
+ default:
+ // No checks for discard
+ break;
+ }
+ return intermediate.addBranch(op, loc);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op,
+ TIntermTyped *returnValue,
+ const TSourceLoc &loc)
+{
+ ASSERT(op == EOpReturn);
+ mFunctionReturnsValue = true;
+ if (mCurrentFunctionType->getBasicType() == EbtVoid)
+ {
+ error(loc, "void function cannot return a value", "return");
+ }
+ else if (*mCurrentFunctionType != returnValue->getType())
+ {
+ error(loc, "function return is not matching type:", "return");
+ }
+ return intermediate.addBranch(op, returnValue, loc);
+}
+
+void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
+{
+ ASSERT(!functionCall->isUserDefined());
+ const TString &name = functionCall->getFunctionSymbolInfo()->getName();
+ TIntermNode *offset = nullptr;
+ TIntermSequence *arguments = functionCall->getSequence();
+ if (name.compare(0, 16, "texelFetchOffset") == 0 ||
+ name.compare(0, 16, "textureLodOffset") == 0 ||
+ name.compare(0, 20, "textureProjLodOffset") == 0 ||
+ name.compare(0, 17, "textureGradOffset") == 0 ||
+ name.compare(0, 21, "textureProjGradOffset") == 0)
+ {
+ offset = arguments->back();
+ }
+ else if (name.compare(0, 13, "textureOffset") == 0 ||
+ name.compare(0, 17, "textureProjOffset") == 0)
+ {
+ // A bias parameter might follow the offset parameter.
+ ASSERT(arguments->size() >= 3);
+ offset = (*arguments)[2];
+ }
+ if (offset != nullptr)
+ {
+ TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
+ if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
+ {
+ TString unmangledName = TFunction::unmangleName(name);
+ error(functionCall->getLine(), "Texture offset must be a constant expression",
+ unmangledName.c_str());
+ }
+ else
+ {
+ ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
+ size_t size = offsetConstantUnion->getType().getObjectSize();
+ const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
+ for (size_t i = 0u; i < size; ++i)
+ {
+ int offsetValue = values[i].getIConst();
+ if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
+ {
+ std::stringstream tokenStream;
+ tokenStream << offsetValue;
+ std::string token = tokenStream.str();
+ error(offset->getLine(), "Texture offset value out of valid range",
+ token.c_str());
+ }
+ }
+ }
+ }
+}
+
+TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
+ TIntermNode *paramNode,
+ TIntermNode *thisNode,
+ const TSourceLoc &loc,
+ bool *fatalError)
+{
+ *fatalError = false;
+ TOperator op = fnCall->getBuiltInOp();
+ TIntermTyped *callNode = nullptr;
+
+ if (thisNode != nullptr)
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ int arraySize = 0;
+ TIntermTyped *typedThis = thisNode->getAsTyped();
+ if (fnCall->getName() != "length")
+ {
+ error(loc, "invalid method", fnCall->getName().c_str());
+ }
+ else if (paramNode != nullptr)
+ {
+ error(loc, "method takes no parameters", "length");
+ }
+ else if (typedThis == nullptr || !typedThis->isArray())
+ {
+ error(loc, "length can only be called on arrays", "length");
+ }
+ else
+ {
+ arraySize = typedThis->getArraySize();
+ if (typedThis->getAsSymbolNode() == nullptr)
+ {
+ // This code path can be hit with expressions like these:
+ // (a = b).length()
+ // (func()).length()
+ // (int[3](0, 1, 2)).length()
+ // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
+ // expression.
+ // It allows "An array name with the length method applied" in contrast to GLSL 4.4
+ // spec section 5.9 which allows "An array, vector or matrix expression with the
+ // length method applied".
+ error(loc, "length can only be called on array names, not on array expressions",
+ "length");
+ }
+ }
+ unionArray->setIConst(arraySize);
+ callNode =
+ intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
+ }
+ else if (op != EOpNull)
+ {
+ // Then this should be a constructor.
+ callNode = addConstructor(paramNode, op, fnCall, loc);
+ }
+ else
+ {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction *fnCandidate;
+ bool builtIn;
+ fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
+ if (fnCandidate)
+ {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty())
+ {
+ checkCanUseExtension(loc, fnCandidate->getExtension());
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull)
+ {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1)
+ {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ TIntermAggregate *paramAgg = paramNode->getAsAggregate();
+ paramNode = paramAgg->getSequence()->front();
+ callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
+ &fnCandidate->getReturnType());
+ if (callNode == nullptr)
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream
+ << "built in unary operator function. Type: "
+ << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ error(paramNode->getLine(), " wrong operand type", "Internal Error",
+ extraInfo.c_str());
+ *fatalError = true;
+ return nullptr;
+ }
+ }
+ else
+ {
+ TIntermAggregate *aggregate =
+ intermediate.setAggregateOperator(paramNode, op, loc);
+ aggregate->setType(fnCandidate->getReturnType());
+ aggregate->setPrecisionFromChildren();
+ if (aggregate->areChildrenConstQualified())
+ {
+ aggregate->getTypePointer()->setQualifier(EvqConst);
+ }
+
+ // Some built-in functions have out parameters too.
+ functionCallLValueErrorCheck(fnCandidate, aggregate);
+
+ // See if we can constant fold a built-in. Note that this may be possible even
+ // if it is not const-qualified.
+ TIntermTyped *foldedNode =
+ intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
+ if (foldedNode)
+ {
+ callNode = foldedNode;
+ }
+ else
+ {
+ callNode = aggregate;
+ }
+ }
+ }
+ else
+ {
+ // This is a real function call
+ TIntermAggregate *aggregate =
+ intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
+ aggregate->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user
+ // defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded
+ // builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ aggregate->setUserDefined();
+ aggregate->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
+
+ // This needs to happen after the function info including name is set
+ if (builtIn)
+ {
+ aggregate->setBuiltInFunctionPrecision();
+
+ checkTextureOffsetConst(aggregate);
+ }
+
+ callNode = aggregate;
+
+ functionCallLValueErrorCheck(fnCandidate, aggregate);
+ }
+ }
+ else
+ {
+ // error message was put out by findFunction()
+ // Put on a dummy node for error recovery
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ callNode = intermediate.addConstantUnion(unionArray,
+ TType(EbtFloat, EbpUndefined, EvqConst), loc);
+ }
+ }
+ return callNode;
+}
+
+TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &loc)
+{
+ checkIsScalarBool(loc, cond);
+
+ if (trueExpression->getType() != falseExpression->getType())
+ {
+ binaryOpError(loc, ":", trueExpression->getCompleteString(),
+ falseExpression->getCompleteString());
+ return falseExpression;
+ }
+ // ESSL1 sections 5.2 and 5.7:
+ // ESSL3 section 5.7:
+ // Ternary operator is not among the operators allowed for structures/arrays.
+ if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
+ {
+ error(loc, "ternary operator is not allowed for structures or arrays", ":");
+ 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;
+ }
+
+ return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
+}
+
+//
+// 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 == NULL))
+ 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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.h
new file mode 100644
index 000000000..6ca3a3cd5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ParseContext.h
@@ -0,0 +1,450 @@
+//
+// 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/translator/Compiler.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/DirectiveHandler.h"
+#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/QualifierTypes.h"
+#include "compiler/preprocessor/Preprocessor.h"
+
+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,
+ TInfoSink &is,
+ const ShBuiltInResources &resources)
+ : intermediate(),
+ symbolTable(symt),
+ mDeferredSingleDeclarationErrorCheck(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),
+ mDefaultMatrixPacking(EmpColumnMajor),
+ mDefaultBlockStorage(IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
+ mDiagnostics(is),
+ mDirectiveHandler(ext,
+ mDiagnostics,
+ mShaderVersion,
+ mShaderType,
+ resources.WEBGL_debug_shader_precision == 1),
+ mPreprocessor(&mDiagnostics, &mDirectiveHandler),
+ mScanner(nullptr),
+ mUsesFragData(false),
+ mUsesFragColor(false),
+ mUsesSecondaryOutputs(false),
+ mMinProgramTexelOffset(resources.MinProgramTexelOffset),
+ mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
+ mComputeShaderLocalSizeDeclared(false),
+ mDeclaringFunction(false)
+ {
+ mComputeShaderLocalSize.fill(-1);
+ }
+
+ const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
+ 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(); }
+ TInfoSink &infoSink() { return mDiagnostics.infoSink(); }
+ void error(const TSourceLoc &loc, const char *reason, const char *token,
+ const char *extraInfo="");
+ void warning(const TSourceLoc &loc, const char *reason, const char *token,
+ const char *extraInfo="");
+
+ // If isError is false, a warning will be reported instead.
+ void outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo = "");
+
+ 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;
+
+ void enterFunctionDeclaration() { mDeclaringFunction = true; }
+
+ void exitFunctionDeclaration() { mDeclaringFunction = false; }
+
+ bool declaringFunction() const { return mDeclaringFunction; }
+
+ // This method is guaranteed to succeed, even if no variable with 'name' exists.
+ const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
+ TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
+ const TString *name,
+ const TSymbol *symbol);
+
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line);
+
+ void assignError(const TSourceLoc &line, const char *op, TString left, TString right);
+ void unaryOpError(const TSourceLoc &line, const char *op, TString operand);
+ void binaryOpError(const TSourceLoc &line, const char *op, TString left, TString right);
+
+ // Check functions - the ones that return bool return false if an error was generated.
+
+ bool checkIsNotReserved(const TSourceLoc &line, const TString &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,
+ TIntermNode *argumentsNode,
+ const TFunction &function,
+ TOperator op,
+ 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 checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType);
+ bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
+ void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
+ void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
+ bool checkIsNotSampler(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 checkOutParameterIsNotSampler(const TSourceLoc &line,
+ TQualifier qualifier,
+ const TType &type);
+ void checkIsParameterQualifierValid(const TSourceLoc &line,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TType *type);
+ bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
+ void singleDeclarationErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation);
+ void checkLayoutQualifierSupported(const TSourceLoc &location,
+ const TString &layoutQualifierName,
+ int versionRequired);
+ bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier);
+
+ void functionCallLValueErrorCheck(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);
+
+ const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
+ const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
+ bool supportsExtension(const char *extension);
+ bool isExtensionEnabled(const char *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);
+
+ bool containsSampler(const TType &type);
+ const TFunction* findFunction(
+ const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
+ bool executeInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ const TPublicType &pType,
+ TIntermTyped *initializer,
+ TIntermNode **intermNode);
+
+ TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TPublicType &typeSpecifier);
+
+ TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const TString &identifier);
+ TIntermAggregate *parseSingleArrayDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression);
+ TIntermAggregate *parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &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"
+ TIntermAggregate *parseSingleArrayInitDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ TIntermAggregate *parseInvariantDeclaration(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &identifierLoc,
+ const TString *identifier,
+ const TSymbol *symbol);
+
+ TIntermAggregate *parseDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier);
+ TIntermAggregate *parseArrayDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &arrayLocation,
+ TIntermTyped *indexExpression);
+ TIntermAggregate *parseInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ // Parse a declarator like "a[n] = initializer"
+ TIntermAggregate *parseArrayInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
+ TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
+ const TSourceLoc &location);
+ TIntermFunctionDefinition *addFunctionDefinition(const TFunction &function,
+ TIntermAggregate *functionParameters,
+ TIntermBlock *functionBody,
+ const TSourceLoc &location);
+ void parseFunctionDefinitionHeader(const TSourceLoc &location,
+ TFunction **function,
+ TIntermAggregate **aggregateOut);
+ TFunction *parseFunctionDeclarator(const TSourceLoc &location,
+ TFunction *function);
+ TFunction *parseFunctionHeader(const TPublicType &type,
+ const TString *name,
+ const TSourceLoc &location);
+ TFunction *addConstructorFunc(const TPublicType &publicType);
+ TIntermTyped *addConstructor(TIntermNode *arguments,
+ TOperator op,
+ TFunction *fnCall,
+ const TSourceLoc &line);
+
+ TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
+ const TSourceLoc& location,
+ TIntermTyped *indexExpression);
+ TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const TString &fieldString,
+ const TSourceLoc &fieldLocation);
+
+ TFieldList *addStructDeclaratorListWithQualifiers(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TPublicType *typeSpecifier,
+ TFieldList *fieldList);
+ TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList);
+ TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList);
+
+ TIntermAggregate *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &nameLine,
+ const TString &blockName,
+ TFieldList *fieldList,
+ const TString *instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine);
+
+ void parseLocalSize(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ size_t index,
+ sh::WorkGroupSize *localSize);
+ TLayoutQualifier parseLayoutQualifier(
+ const TString &qualifierType, const TSourceLoc &qualifierTypeLine);
+ TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine);
+ TTypeQualifierBuilder *createTypeQualifierBuilder(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 TString &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 *returnValue, const TSourceLoc &loc);
+
+ void checkTextureOffsetConst(TIntermAggregate *functionCall);
+ TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall,
+ TIntermNode *paramNode,
+ TIntermNode *thisNode,
+ const TSourceLoc &loc,
+ bool *fatalError);
+
+ TIntermTyped *addTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line);
+
+ // TODO(jmadill): make these private
+ TIntermediate intermediate; // to build a parse tree
+ TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
+
+ private:
+ // Returns a clamped index.
+ int checkIndexOutOfRange(bool outOfRangeIndexIsError,
+ const TSourceLoc &location,
+ int index,
+ int arraySize,
+ const char *reason,
+ const char *token);
+
+ bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
+
+ void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ TPublicType *type);
+
+ bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
+ const TPublicType &elementType);
+
+ // Assumes that multiplication op has already been set based on the types.
+ bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
+
+ TIntermTyped *addBinaryMathInternal(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+ TIntermTyped *createAssign(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+ // The funcReturnType parameter is expected to be non-null when the operation is a built-in function.
+ // It is expected to be null for other unary operators.
+ TIntermTyped *createUnaryMath(
+ TOperator op, TIntermTyped *child, const TSourceLoc &loc, const TType *funcReturnType);
+
+ // Return true if the checks pass
+ bool binaryOpCommonCheck(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+
+ // Set to true when the last/current declarator list was started with an empty declaration.
+ bool mDeferredSingleDeclarationErrorCheck;
+
+ 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 mDefaultMatrixPacking;
+ TLayoutBlockStorage mDefaultBlockStorage;
+ TString mHashErrMsg;
+ TDiagnostics mDiagnostics;
+ TDirectiveHandler mDirectiveHandler;
+ pp::Preprocessor mPreprocessor;
+ void *mScanner;
+ bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
+ bool mUsesFragColor;
+ bool mUsesSecondaryOutputs; // Track if we are using either gl_SecondaryFragData or
+ // gl_Secondary FragColor or both.
+ int mMinProgramTexelOffset;
+ int mMaxProgramTexelOffset;
+
+ // keep track of local group size declared in layout. It should be declared only once.
+ bool mComputeShaderLocalSizeDeclared;
+ sh::WorkGroupSize mComputeShaderLocalSize;
+ // keeps track whether we are declaring / defining a function
+ bool mDeclaringFunction;
+};
+
+int PaParseStrings(
+ size_t count, const char *const string[], const int length[], TParseContext *context);
+
+#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.cpp
index eb993567b..3b44afe33 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.cpp
@@ -4,73 +4,64 @@
// found in the LICENSE file.
//
-#include "compiler/PoolAlloc.h"
+#include "compiler/translator/PoolAlloc.h"
-#ifndef _MSC_VER
#include <stdint.h>
-#endif
#include <stdio.h>
+#include <assert.h>
#include "common/angleutils.h"
-#include "compiler/InitializeGlobals.h"
-#include "compiler/osinclude.h"
+#include "common/debug.h"
+#include "common/platform.h"
+#include "common/tls.h"
+#include "compiler/translator/InitializeGlobals.h"
-OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
+TLSIndex PoolIndex = TLS_INVALID_INDEX;
bool InitializePoolIndex()
{
- assert(PoolIndex == OS_INVALID_TLS_INDEX);
+ assert(PoolIndex == TLS_INVALID_INDEX);
- PoolIndex = OS_AllocTLSIndex();
- return PoolIndex != OS_INVALID_TLS_INDEX;
+ PoolIndex = CreateTLSIndex();
+ return PoolIndex != TLS_INVALID_INDEX;
}
void FreePoolIndex()
{
- assert(PoolIndex != OS_INVALID_TLS_INDEX);
+ assert(PoolIndex != TLS_INVALID_INDEX);
- OS_FreeTLSIndex(PoolIndex);
- PoolIndex = OS_INVALID_TLS_INDEX;
+ DestroyTLSIndex(PoolIndex);
+ PoolIndex = TLS_INVALID_INDEX;
}
TPoolAllocator* GetGlobalPoolAllocator()
{
- assert(PoolIndex != OS_INVALID_TLS_INDEX);
- return static_cast<TPoolAllocator*>(OS_GetTLSValue(PoolIndex));
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ return static_cast<TPoolAllocator*>(GetTLSValue(PoolIndex));
}
void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
{
- assert(PoolIndex != OS_INVALID_TLS_INDEX);
- OS_SetTLSValue(PoolIndex, poolAllocator);
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ SetTLSValue(PoolIndex, poolAllocator);
}
//
// Implement the functionality of the TPoolAllocator class, which
// is documented in PoolAlloc.h.
//
-TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
- pageSize(growthIncrement),
- alignment(allocationAlignment),
- freeList(0),
- inUseList(0),
- numCalls(0),
- totalBytes(0)
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment)
+ : alignment(allocationAlignment),
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ pageSize(growthIncrement),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0),
+#endif
+ mLocked(false)
{
//
- // Don't allow page sizes we know are smaller than all common
- // OS page sizes.
- //
- if (pageSize < 4*1024)
- pageSize = 4*1024;
-
- //
- // A large currentPageOffset indicates a new page needs to
- // be obtained to allocate memory.
- //
- currentPageOffset = pageSize;
-
- //
// Adjust alignment to be at least pointer aligned and
// power of 2.
//
@@ -84,6 +75,20 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
alignment = a;
alignmentMask = a - 1;
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4 * 1024)
+ pageSize = 4 * 1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
//
// Align header skip
//
@@ -91,10 +96,14 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
if (headerSkip < sizeof(tHeader)) {
headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
}
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ mStack.push_back({});
+#endif
}
TPoolAllocator::~TPoolAllocator()
{
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
while (inUseList) {
tHeader* next = inUseList->nextPage;
inUseList->~tHeader();
@@ -111,6 +120,16 @@ TPoolAllocator::~TPoolAllocator()
delete [] reinterpret_cast<char*>(freeList);
freeList = next;
}
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ for (auto &allocs : mStack)
+ {
+ for (auto alloc : allocs)
+ {
+ free(alloc);
+ }
+ }
+ mStack.clear();
+#endif
}
// Support MSVC++ 6.0
@@ -151,14 +170,18 @@ void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, co
void TPoolAllocator::push()
{
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
tAllocState state = { currentPageOffset, inUseList };
- stack.push_back(state);
-
+ mStack.push_back(state);
+
//
// Indicate there is no current page to allocate from.
//
currentPageOffset = pageSize;
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ mStack.push_back({});
+#endif
}
//
@@ -170,11 +193,12 @@ void TPoolAllocator::push()
//
void TPoolAllocator::pop()
{
- if (stack.size() < 1)
+ if (mStack.size() < 1)
return;
- tHeader* page = stack.back().page;
- currentPageOffset = stack.back().offset;
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ tHeader *page = mStack.back().page;
+ currentPageOffset = mStack.back().offset;
while (inUseList != page) {
// invoke destructor to free allocation list
@@ -190,7 +214,14 @@ void TPoolAllocator::pop()
inUseList = nextInUse;
}
- stack.pop_back();
+ mStack.pop_back();
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ for (auto &alloc : mStack.back())
+ {
+ free(alloc);
+ }
+ mStack.pop_back();
+#endif
}
//
@@ -199,12 +230,15 @@ void TPoolAllocator::pop()
//
void TPoolAllocator::popAll()
{
- while (stack.size() > 0)
+ while (mStack.size() > 0)
pop();
}
void* TPoolAllocator::allocate(size_t numBytes)
{
+ ASSERT(!mLocked);
+
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
//
// Just keep some interesting statistics.
//
@@ -281,8 +315,27 @@ void* TPoolAllocator::allocate(size_t numBytes)
currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
return initializeAllocation(inUseList, ret, numBytes);
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ void *alloc = malloc(numBytes + alignmentMask);
+ mStack.back().push_back(alloc);
+
+ intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
+ intAlloc = (intAlloc + alignmentMask) & ~alignmentMask;
+ return reinterpret_cast<void *>(intAlloc);
+#endif
}
+void TPoolAllocator::lock()
+{
+ ASSERT(!mLocked);
+ mLocked = true;
+}
+
+void TPoolAllocator::unlock()
+{
+ ASSERT(mLocked);
+ mLocked = false;
+}
//
// Check all allocations in a list for damage by calling check on each.
diff --git a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h b/Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.h
index edd249c4d..f15b3e05d 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/PoolAlloc.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef _POOLALLOC_INCLUDED_
-#define _POOLALLOC_INCLUDED_
+#ifndef COMPILER_TRANSLATOR_POOLALLOC_H_
+#define COMPILER_TRANSLATOR_POOLALLOC_H_
#ifdef _DEBUG
#define GUARD_BLOCKS // define to enable guard block sanity checking
@@ -152,7 +152,17 @@ public:
// by calling pop(), and to not have to solve memory leak problems.
//
-protected:
+ // Catch unwanted allocations.
+ // TODO(jmadill): Remove this when we remove the global allocator.
+ void lock();
+ void unlock();
+
+ private:
+ size_t alignment; // all returned allocations will be aligned at
+ // this granularity, which will be a power of 2
+ size_t alignmentMask;
+
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
friend struct tHeader;
struct tHeader {
@@ -195,22 +205,24 @@ protected:
}
size_t pageSize; // granularity of allocation from the OS
- size_t alignment; // all returned allocations will be aligned at
- // this granularity, which will be a power of 2
- size_t alignmentMask;
size_t headerSkip; // amount of memory to skip to make room for the
// header (basically, size of header, rounded
// up to make it aligned
size_t currentPageOffset; // next offset in top of inUseList to allocate from
tHeader* freeList; // list of popped memory
tHeader* inUseList; // list of all memory currently being used
- tAllocStack stack; // stack of where to allocate from, to partition pool
+ tAllocStack mStack; // stack of where to allocate from, to partition pool
int numCalls; // just an interesting statistic
size_t totalBytes; // just an interesting statistic
-private:
+
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ std::vector<std::vector<void *>> mStack;
+#endif
+
TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator
TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor
+ bool mLocked;
};
@@ -247,18 +259,13 @@ public:
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
- pool_allocator() : allocator(GetGlobalPoolAllocator()) { }
- pool_allocator(TPoolAllocator& a) : allocator(&a) { }
- pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
-
- template <class Other>
- pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
- allocator = p.allocator;
- return *this;
- }
+ pool_allocator() { }
template<class Other>
- pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
+ 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.
@@ -284,17 +291,13 @@ public:
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 &getAllocator() == &rhs.getAllocator(); }
- bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+ 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; }
- void setAllocator(TPoolAllocator* a) { allocator = a; }
- TPoolAllocator& getAllocator() const { return *allocator; }
-
-protected:
- TPoolAllocator* allocator;
+ TPoolAllocator& getAllocator() const { return *GetGlobalPoolAllocator(); }
};
-#endif // _POOLALLOC_INCLUDED_
+#endif // COMPILER_TRANSLATOR_POOLALLOC_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Pragma.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Pragma.h
new file mode 100644
index 000000000..57b113497
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Pragma.h
@@ -0,0 +1,32 @@
+//
+// 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/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.cpp
new file mode 100644
index 000000000..4763dd6ed
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.cpp
@@ -0,0 +1,111 @@
+//
+// 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 PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
+
+#include "compiler/translator/PruneEmptyDeclarations.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class PruneEmptyDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ PruneEmptyDeclarationsTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
+{
+ PruneEmptyDeclarationsTraverser prune;
+ root->traverse(&prune);
+ prune.updateTree();
+}
+
+PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() >= 1)
+ {
+ TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
+ // Prune declarations without a variable name, unless it's an interface block declaration.
+ if (sym != nullptr && sym->getSymbol() == "" && !sym->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, sym, emptyReplacement));
+ }
+ else if (sym->getBasicType() != EbtStruct)
+ {
+ // Single struct declarations may just declare the struct type and no variables, so they should
+ // not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
+ // declaration that will be pruned:
+ // float;
+ TIntermSequence emptyReplacement;
+ TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
+ // The declaration may be inside a block or in a loop init expression.
+ ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
+ if (parentAsBlock)
+ {
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
+ }
+ else
+ {
+ queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
+ }
+ }
+ else if (sym->getType().getQualifier() != EvqGlobal &&
+ sym->getType().getQualifier() != EvqTemporary)
+ {
+ // We've hit 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."
+
+ if (mInGlobalScope)
+ {
+ sym->getTypePointer()->setQualifier(EvqGlobal);
+ }
+ else
+ {
+ sym->getTypePointer()->setQualifier(EvqTemporary);
+ }
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void PruneEmptyDeclarations(TIntermNode *root)
+{
+ PruneEmptyDeclarationsTraverser::apply(root);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.h b/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.h
new file mode 100644
index 000000000..122e83090
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/PruneEmptyDeclarations.h
@@ -0,0 +1,15 @@
+//
+// 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 PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
+
+#ifndef COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
+#define COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
+
+class TIntermNode;
+
+void PruneEmptyDeclarations(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.cpp
new file mode 100644
index 000000000..30d8c4eed
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.cpp
@@ -0,0 +1,646 @@
+//
+// 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 <algorithm>
+
+namespace sh
+{
+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.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];
+ }
+ }
+
+ return joinedQualifier;
+}
+} // namespace sh
+
+namespace
+{
+
+// 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;
+}
+
+#if defined(ANGLE_ENABLE_ASSERTS)
+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]);
+}
+#endif
+
+// 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,
+ std::string *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 = "The invariant qualifier specified multiple times.";
+ return true;
+ }
+ invariantFound = true;
+ break;
+ }
+ case QtPrecision:
+ {
+ if (precisionFound)
+ {
+ *errorMessage = "The precision qualifier specified multiple times.";
+ return true;
+ }
+ precisionFound = true;
+ break;
+ }
+ case QtLayout:
+ {
+ if (layoutFound && !areQualifierChecksRelaxed)
+ {
+ *errorMessage = "The layout qualifier specified multiple times.";
+ 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 =
+ "The layout qualifier and invariant qualifier cannot coexist in the same "
+ "declaration according to the grammar.";
+ 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 = "The interpolation qualifier specified multiple times.";
+ 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 = previousQualifierWrapper->getQualifierString().c_str();
+ *errorMessage += " specified multiple times";
+ 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 = "Output layout location specified multiple times.";
+ 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,
+ std::string *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 = "The invariant qualifier has to be first in the expression.";
+ return false;
+ }
+ break;
+ case QtInterpolation:
+ if (foundStorage)
+ {
+ *errorMessage = "Storage qualifiers have to be after interpolation qualifiers.";
+ return false;
+ }
+ else if (foundPrecision)
+ {
+ *errorMessage =
+ "Precision qualifiers have to be after interpolation qualifiers.";
+ return false;
+ }
+ foundInterpolation = true;
+ break;
+ case QtLayout:
+ if (foundStorage)
+ {
+ *errorMessage = "Storage qualifiers have to be after layout qualifiers.";
+ return false;
+ }
+ else if (foundPrecision)
+ {
+ *errorMessage = "Precision qualifiers have to be after layout qualifiers.";
+ return false;
+ }
+ break;
+ case QtStorage:
+ if (foundPrecision)
+ {
+ *errorMessage = "Precision qualifiers have to be after storage qualifiers.";
+ return false;
+ }
+ foundStorage = true;
+ 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:
+ *joinedQualifier = EvqSmoothOut;
+ break;
+ case EvqFragmentIn:
+ *joinedQualifier = EvqSmoothIn;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ case EvqFlat:
+ {
+ switch (storageQualifier)
+ {
+ case EvqCentroid:
+ *joinedQualifier = EvqFlat;
+ break;
+ case EvqVertexOut:
+ *joinedQualifier = EvqFlatOut;
+ break;
+ case EvqFragmentIn:
+ *joinedQualifier = EvqFlatIn;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ case EvqCentroid:
+ {
+ switch (storageQualifier)
+ {
+ case EvqVertexOut:
+ *joinedQualifier = EvqCentroidOut;
+ break;
+ case EvqFragmentIn:
+ *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;
+}
+
+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;
+ default:
+ UNREACHABLE();
+ }
+ if (!isQualifierValid)
+ {
+ const TString &qualifierString = qualifier->getQualifierString();
+ diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
+ qualifierString.c_str(), "");
+ 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 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 TString &qualifierString = qualifier->getQualifierString();
+ diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
+ qualifierString.c_str(), "");
+ 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
+
+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 TPrecisionQualifierWrapper::getRank() const
+{
+ return 5u;
+}
+
+TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
+ : layoutQualifier(TLayoutQualifier::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);
+ std::string errorMessage;
+ if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
+ {
+ diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(),
+ "");
+ return false;
+ }
+
+ if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage))
+ {
+ diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(),
+ "");
+ 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);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.h b/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.h
new file mode 100644
index 000000000..0bcc39a16
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/QualifierTypes.h
@@ -0,0 +1,170 @@
+//
+// 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/Types.h"
+
+class TDiagnostics;
+
+namespace sh
+{
+TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation,
+ TDiagnostics *diagnostics);
+} // namespace sh
+
+enum TQualifierType
+{
+ QtInvariant,
+ QtInterpolation,
+ QtLayout,
+ QtStorage,
+ QtPrecision
+};
+
+class TQualifierWrapperBase : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {}
+ virtual ~TQualifierWrapperBase(){};
+ virtual TQualifierType getType() const = 0;
+ virtual TString 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 { return QtInvariant; }
+ TString getQualifierString() const { return "invariant"; }
+ unsigned int getRank() const;
+};
+
+class TInterpolationQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier)
+ {
+ }
+ ~TInterpolationQualifierWrapper() {}
+
+ TQualifierType getType() const { return QtInterpolation; }
+ TString getQualifierString() const { return ::getQualifierString(mInterpolationQualifier); }
+ TQualifier getQualifier() const { return mInterpolationQualifier; }
+ unsigned int getRank() const;
+
+ private:
+ TQualifier mInterpolationQualifier;
+};
+
+class TLayoutQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier)
+ {
+ }
+ ~TLayoutQualifierWrapper() {}
+
+ TQualifierType getType() const { return QtLayout; }
+ TString getQualifierString() const { return "layout"; }
+ const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; }
+ unsigned int getRank() const;
+
+ private:
+ TLayoutQualifier mLayoutQualifier;
+};
+
+class TStorageQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mStorageQualifier(storageQualifier)
+ {
+ }
+ ~TStorageQualifierWrapper() {}
+
+ TQualifierType getType() const { return QtStorage; }
+ TString getQualifierString() const { return ::getQualifierString(mStorageQualifier); }
+ TQualifier getQualifier() const { return mStorageQualifier; }
+ unsigned int getRank() const;
+
+ private:
+ TQualifier mStorageQualifier;
+};
+
+class TPrecisionQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier)
+ {
+ }
+ ~TPrecisionQualifierWrapper() {}
+
+ TQualifierType getType() const { return QtPrecision; }
+ TString getQualifierString() const { return ::getPrecisionString(mPrecisionQualifier); }
+ TPrecision getQualifier() const { return mPrecisionQualifier; }
+ unsigned int getRank() const;
+
+ private:
+ TPrecision mPrecisionQualifier;
+};
+
+// 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;
+ 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;
+};
+
+#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.cpp
new file mode 100644
index 000000000..6eca229d8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.cpp
@@ -0,0 +1,162 @@
+//
+// 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/RecordConstantPrecision.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class RecordConstantPrecisionTraverser : public TIntermTraverser
+{
+ public:
+ RecordConstantPrecisionTraverser();
+
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+
+ void nextIteration();
+
+ bool foundHigherPrecisionConstant() const { return mFoundHigherPrecisionConstant; }
+ protected:
+ bool operandAffectsParentOperationPrecision(TIntermTyped *operand);
+
+ bool mFoundHigherPrecisionConstant;
+};
+
+RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser()
+ : TIntermTraverser(true, false, true),
+ 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.
+ TIntermSequence insertions;
+ insertions.push_back(createTempInitDeclaration(node, EvqConst));
+ insertStatementsInParentBlock(insertions);
+ queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
+ mFoundHigherPrecisionConstant = true;
+}
+
+void RecordConstantPrecisionTraverser::nextIteration()
+{
+ nextTemporaryIndex();
+ mFoundHigherPrecisionConstant = false;
+}
+
+} // namespace
+
+void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ RecordConstantPrecisionTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundHigherPrecisionConstant())
+ traverser.updateTree();
+ }
+ while (traverser.foundHigherPrecisionConstant());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.h
new file mode 100644
index 000000000..2cd401b41
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RecordConstantPrecision.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.
+//
+// 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_RECORDCONSTANTPRECISION_H_
+#define COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_
+
+class TIntermNode;
+
+void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.cpp
new file mode 100644
index 000000000..1a7d8aaf8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.cpp
@@ -0,0 +1,71 @@
+//
+// 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 "common/debug.h"
+#include "compiler/translator/RegenerateStructNames.h"
+
+void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol)
+{
+ ASSERT(symbol);
+ TType *type = symbol->getTypePointer();
+ ASSERT(type);
+ TStructure *userType = type->getStruct();
+ if (!userType)
+ return;
+
+ if (mSymbolTable.findBuiltIn(userType->name(), mShaderVersion))
+ {
+ // Built-in struct, do not touch it.
+ return;
+ }
+
+ int uniqueId = userType->uniqueId();
+
+ 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}.
+ const char kPrefix[] = "_webgl_struct_";
+ if (userType->name().find(kPrefix) == 0)
+ {
+ // The name has already been regenerated.
+ return;
+ }
+ std::string id = Str(uniqueId);
+ TString tmp = kPrefix + TString(id.c_str());
+ tmp += "_" + userType->name();
+ userType->setName(tmp);
+}
+
+bool RegenerateStructNames::visitBlock(Visit, TIntermBlock *block)
+{
+ ++mScopeDepth;
+ TIntermSequence &sequence = *(block->getSequence());
+ for (TIntermNode *node : sequence)
+ {
+ node->traverse(this);
+ }
+ --mScopeDepth;
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.h
new file mode 100644
index 000000000..a9101351e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RegenerateStructNames.h
@@ -0,0 +1,41 @@
+//
+// 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_REGENERATESTRUCTNAMES_H_
+#define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
+
+#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/SymbolTable.h"
+
+#include <set>
+
+class RegenerateStructNames : public TIntermTraverser
+{
+ public:
+ RegenerateStructNames(const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TIntermTraverser(true, false, false),
+ mSymbolTable(symbolTable),
+ mShaderVersion(shaderVersion),
+ mScopeDepth(0) {}
+
+ protected:
+ void visitSymbol(TIntermSymbol *) override;
+ bool visitBlock(Visit, TIntermBlock *block) override;
+
+ private:
+ const TSymbolTable &mSymbolTable;
+ int mShaderVersion;
+
+ // 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;
+};
+
+#endif // COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.cpp
new file mode 100644
index 000000000..994ae313a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -0,0 +1,508 @@
+//
+// 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 vectors and matrices,
+// replacing them with calls to functions that choose which component to return or write.
+//
+
+#include "compiler/translator/RemoveDynamicIndexing.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+TName 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();
+ }
+ TString nameString = TFunction::mangleName(nameSink.c_str());
+ TName name(nameString);
+ name.setInternal(true);
+ return name;
+}
+
+TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier)
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "base", type);
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(qualifier);
+ return symbol;
+}
+
+TIntermSymbol *CreateIndexSymbol()
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "index", TType(EbtInt, EbpHigh));
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(EvqIn);
+ return symbol;
+}
+
+TIntermSymbol *CreateValueSymbol(const TType &type)
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "value", type);
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(EvqIn);
+ return symbol;
+}
+
+TIntermConstantUnion *CreateIntConstantNode(int i)
+{
+ TConstantUnion *constant = new TConstantUnion();
+ constant->setIConst(i);
+ return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh));
+}
+
+TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType,
+ const TType &fieldType,
+ const int index,
+ TQualifier baseQualifier)
+{
+ TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
+ TIntermBinary *indexNode =
+ new TIntermBinary(EOpIndexDirect, baseSymbol, TIntermTyped::CreateIndexNode(index));
+ return indexNode;
+}
+
+TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
+{
+ return new TIntermBinary(EOpAssign, targetNode, CreateValueSymbol(assignedValueType));
+}
+
+TIntermTyped *EnsureSignedInt(TIntermTyped *node)
+{
+ if (node->getBasicType() == EbtInt)
+ return node;
+
+ TIntermAggregate *convertedNode = new TIntermAggregate(EOpConstructInt);
+ convertedNode->setType(TType(EbtInt));
+ convertedNode->getSequence()->push_back(node);
+ convertedNode->setPrecisionFromChildren();
+ return convertedNode;
+}
+
+TType GetFieldType(const TType &indexedType)
+{
+ if (indexedType.isMatrix())
+ {
+ TType fieldType = TType(indexedType.getBasicType(), indexedType.getPrecision());
+ fieldType.setPrimarySize(static_cast<unsigned char>(indexedType.getRows()));
+ return fieldType;
+ }
+ else
+ {
+ return TType(indexedType.getBasicType(), indexedType.getPrecision());
+ }
+}
+
+// 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(TType type, bool write)
+{
+ ASSERT(!type.isArray());
+ // 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.
+ type.setPrecision(EbpHigh);
+
+ TType fieldType = GetFieldType(type);
+ int numCases = 0;
+ if (type.isMatrix())
+ {
+ numCases = type.getCols();
+ }
+ else
+ {
+ numCases = type.getNominalSize();
+ }
+
+ TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
+ TQualifier baseQualifier = EvqInOut;
+ if (!write)
+ baseQualifier = EvqIn;
+ TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier);
+ paramsNode->getSequence()->push_back(baseParam);
+ TIntermSymbol *indexParam = CreateIndexSymbol();
+ paramsNode->getSequence()->push_back(indexParam);
+ if (write)
+ {
+ TIntermSymbol *valueParam = CreateValueSymbol(fieldType);
+ paramsNode->getSequence()->push_back(valueParam);
+ }
+
+ TIntermBlock *statementList = new TIntermBlock();
+ for (int i = 0; i < numCases; ++i)
+ {
+ TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i));
+ statementList->getSequence()->push_back(caseNode);
+
+ TIntermBinary *indexNode =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, i, baseQualifier);
+ if (write)
+ {
+ TIntermBinary *assignNode = CreateAssignValueSymbolNode(indexNode, fieldType);
+ 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(CreateIndexSymbol(), statementList);
+
+ TIntermBlock *bodyNode = new TIntermBlock();
+ bodyNode->getSequence()->push_back(switchNode);
+
+ TIntermBinary *cond =
+ new TIntermBinary(EOpLessThan, CreateIndexSymbol(), CreateIntConstantNode(0));
+ cond->setType(TType(EbtBool, EbpUndefined));
+
+ // 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 =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier);
+ TIntermBinary *indexLastNode =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1, baseQualifier);
+ if (write)
+ {
+ TIntermBinary *assignFirstNode = CreateAssignValueSymbolNode(indexFirstNode, fieldType);
+ useFirstBlock->getSequence()->push_back(assignFirstNode);
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
+ useFirstBlock->getSequence()->push_back(returnNode);
+
+ TIntermBinary *assignLastNode = CreateAssignValueSymbolNode(indexLastNode, fieldType);
+ 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 = nullptr;
+ if (write)
+ {
+ indexingFunction = new TIntermFunctionDefinition(TType(EbtVoid), paramsNode, bodyNode);
+ }
+ else
+ {
+ indexingFunction = new TIntermFunctionDefinition(fieldType, paramsNode, bodyNode);
+ }
+ indexingFunction->getFunctionSymbolInfo()->setNameObj(GetIndexFunctionName(type, write));
+ return indexingFunction;
+}
+
+class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser
+{
+ public:
+ RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, int shaderVersion);
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ void insertHelperDefinitions(TIntermNode *root);
+
+ void nextIteration();
+
+ bool usedTreeInsertion() const { return mUsedTreeInsertion; }
+
+ protected:
+ // Sets of types that are indexed. Note that these can not store multiple variants
+ // of the same type with different precisions - only one precision gets stored.
+ std::set<TType> mIndexedVecAndMatrixTypes;
+ std::set<TType> 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;
+};
+
+RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
+ mUsedTreeInsertion(false),
+ mRemoveIndexSideEffectsInSubtree(false)
+{
+}
+
+void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root)
+{
+ TIntermBlock *rootBlock = root->getAsBlock();
+ ASSERT(rootBlock != nullptr);
+ TIntermSequence insertions;
+ for (TType type : mIndexedVecAndMatrixTypes)
+ {
+ insertions.push_back(GetIndexFunctionDefinition(type, false));
+ }
+ for (TType type : mWrittenVecAndMatrixTypes)
+ {
+ insertions.push_back(GetIndexFunctionDefinition(type, true));
+ }
+ mInsertions.push_back(NodeInsertMultipleEntry(rootBlock, 0, insertions, TIntermSequence()));
+}
+
+// Create a call to dyn_index_*() based on an indirect indexing op node
+TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node,
+ TIntermTyped *indexedNode,
+ TIntermTyped *index)
+{
+ ASSERT(node->getOp() == EOpIndexIndirect);
+ TIntermAggregate *indexingCall = new TIntermAggregate(EOpFunctionCall);
+ indexingCall->setLine(node->getLine());
+ indexingCall->setUserDefined();
+ indexingCall->getFunctionSymbolInfo()->setNameObj(
+ GetIndexFunctionName(indexedNode->getType(), false));
+ indexingCall->getSequence()->push_back(indexedNode);
+ indexingCall->getSequence()->push_back(index);
+
+ TType fieldType = GetFieldType(indexedNode->getType());
+ indexingCall->setType(fieldType);
+ return indexingCall;
+}
+
+TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node,
+ TIntermTyped *index,
+ TIntermTyped *writtenValue)
+{
+ // Deep copy the left node so that two pointers to the same node don't end up in the tree.
+ TIntermNode *leftCopy = node->getLeft()->deepCopy();
+ ASSERT(leftCopy != nullptr && leftCopy->getAsTyped() != nullptr);
+ TIntermAggregate *indexedWriteCall =
+ CreateIndexFunctionCall(node, leftCopy->getAsTyped(), index);
+ indexedWriteCall->getFunctionSymbolInfo()->setNameObj(
+ GetIndexFunctionName(node->getLeft()->getType(), true));
+ indexedWriteCall->setType(TType(EbtVoid));
+ indexedWriteCall->getSequence()->push_back(writtenValue);
+ 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.
+
+ // Init the temp variable holding the index
+ TIntermAggregate *initIndex = createTempInitDeclaration(node->getRight());
+ insertStatementInParentBlock(initIndex);
+ mUsedTreeInsertion = true;
+
+ // Replace the index with the temp variable
+ TIntermSymbol *tempIndex = createTempSymbol(node->getRight()->getType());
+ queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED);
+ }
+ else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node))
+ {
+ 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
+
+ TType type = node->getLeft()->getType();
+ mIndexedVecAndMatrixTypes.insert(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;
+ }
+ // 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
+
+ mWrittenVecAndMatrixTypes.insert(type);
+ TType fieldType = GetFieldType(type);
+
+ TIntermSequence insertionsBefore;
+ TIntermSequence insertionsAfter;
+
+ // Store the index in a temporary signed int variable.
+ TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight());
+ TIntermAggregate *initIndex = createTempInitDeclaration(indexInitializer);
+ initIndex->setLine(node->getLine());
+ insertionsBefore.push_back(initIndex);
+
+ TIntermAggregate *indexingCall = CreateIndexFunctionCall(
+ node, node->getLeft(), createTempSymbol(indexInitializer->getType()));
+
+ // Create a node for referring to the index after the nextTemporaryIndex() call
+ // below.
+ TIntermSymbol *tempIndex = createTempSymbol(indexInitializer->getType());
+
+ nextTemporaryIndex(); // From now on, creating temporary symbols that refer to the
+ // field value.
+ insertionsBefore.push_back(createTempInitDeclaration(indexingCall));
+
+ TIntermAggregate *indexedWriteCall =
+ CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType));
+ insertionsAfter.push_back(indexedWriteCall);
+ insertStatementsInParentBlock(insertionsBefore, insertionsAfter);
+ queueReplacement(node, createTempSymbol(fieldType), 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, node->getLeft(), EnsureSignedInt(node->getRight()));
+ queueReplacement(node, indexingCall, OriginalNode::IS_DROPPED);
+ }
+ }
+ }
+ return !mUsedTreeInsertion;
+}
+
+void RemoveDynamicIndexingTraverser::nextIteration()
+{
+ mUsedTreeInsertion = false;
+ mRemoveIndexSideEffectsInSubtree = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion);
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.usedTreeInsertion());
+ traverser.insertHelperDefinitions(root);
+ traverser.updateTree();
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.h
new file mode 100644
index 000000000..ae3a93c9b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveDynamicIndexing.h
@@ -0,0 +1,21 @@
+//
+// 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 vectors and matrices,
+// replacing them with calls to functions that choose which component to return or write.
+//
+
+#ifndef COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
+#define COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+#endif // COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.cpp
new file mode 100644
index 000000000..4b0fe6948
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.cpp
@@ -0,0 +1,94 @@
+//
+// 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/RemovePow.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+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();
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ void nextIteration() { mNeedAnotherIteration = false; }
+ bool needAnotherIteration() const { return mNeedAnotherIteration; }
+
+ protected:
+ bool mNeedAnotherIteration;
+};
+
+RemovePowTraverser::RemovePowTraverser()
+ : TIntermTraverser(true, false, false),
+ 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();
+
+ TIntermUnary *log = new TIntermUnary(EOpLog2, x);
+ log->setLine(node->getLine());
+
+ TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
+ TIntermBinary *mul = new TIntermBinary(op, y, log);
+ mul->setLine(node->getLine());
+
+ TIntermUnary *exp = new TIntermUnary(EOpExp2, mul);
+ exp->setLine(node->getLine());
+
+ queueReplacement(node, 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)
+{
+ RemovePowTraverser traverser;
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ }
+ while (traverser.needAnotherIteration());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.h
new file mode 100644
index 000000000..40f9d672b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemovePow.h
@@ -0,0 +1,18 @@
+//
+// 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_REMOVEPOW_H_
+#define COMPILER_TRANSLATOR_REMOVEPOW_H_
+
+class TIntermNode;
+
+void RemovePow(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_REMOVEPOW_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.cpp
new file mode 100644
index 000000000..df8ce1e1f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.cpp
@@ -0,0 +1,169 @@
+//
+// 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/RemoveSwitchFallThrough.h"
+
+TIntermBlock *RemoveSwitchFallThrough::removeFallThrough(TIntermBlock *statementList)
+{
+ RemoveSwitchFallThrough rm(statementList);
+ ASSERT(statementList);
+ statementList->traverse(&rm);
+ bool lastStatementWasBreak = rm.mLastStatementWasBreak;
+ rm.mLastStatementWasBreak = true;
+ rm.handlePreviousCase();
+ if (!lastStatementWasBreak)
+ {
+ TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
+ rm.mStatementListOut->getSequence()->push_back(finalBreak);
+ }
+ return rm.mStatementListOut;
+}
+
+RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermBlock *statementList)
+ : TIntermTraverser(true, false, false),
+ mStatementList(statementList),
+ mLastStatementWasBreak(false),
+ mPreviousCase(nullptr)
+{
+ mStatementListOut = new TIntermBlock();
+}
+
+void RemoveSwitchFallThrough::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 RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node)
+{
+ // Conditions of case labels are not traversed, so this is some other constant
+ // Could be just a statement like "0;"
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+}
+
+bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitIfElse(Visit, TIntermIfElse *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ // Don't go into nested switch statements
+ return false;
+}
+
+void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex)
+{
+ for (size_t i = startIndex; i < sequence->size(); ++i)
+ {
+ mStatementListOut->getSequence()->push_back(sequence->at(i));
+ }
+}
+
+void RemoveSwitchFallThrough::handlePreviousCase()
+{
+ if (mPreviousCase)
+ mCasesSharingBreak.push_back(mPreviousCase);
+ if (mLastStatementWasBreak)
+ {
+ bool labelsWithNoStatements = true;
+ for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
+ {
+ if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
+ {
+ labelsWithNoStatements = false;
+ }
+ if (labelsWithNoStatements)
+ {
+ // 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.
+ 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 RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node)
+{
+ handlePreviousCase();
+ mPreviousCase = new TIntermBlock();
+ mPreviousCase->getSequence()->push_back(node);
+ // Don't traverse the condition of the case statement
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitBlock(Visit, TIntermBlock *node)
+{
+ if (node != mStatementList)
+ {
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+ }
+ return true;
+}
+
+bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.h
new file mode 100644
index 000000000..171c51bf3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RemoveSwitchFallThrough.h
@@ -0,0 +1,45 @@
+//
+// 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_REMOVESWITCHFALLTHROUGH_H_
+#define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
+
+#include "compiler/translator/IntermNode.h"
+
+class RemoveSwitchFallThrough : public TIntermTraverser
+{
+ public:
+ // When given a statementList from a switch AST node, return an updated
+ // statementList that has fall-through removed.
+ static TIntermBlock *removeFallThrough(TIntermBlock *statementList);
+
+ private:
+ RemoveSwitchFallThrough(TIntermBlock *statementList);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitBinary(Visit, TIntermBinary *node) override;
+ bool visitUnary(Visit, TIntermUnary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *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;
+};
+
+#endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.cpp
new file mode 100644
index 000000000..9cc551bb7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.cpp
@@ -0,0 +1,154 @@
+//
+// 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/RewriteDoWhile.h"
+
+#include "compiler/translator/IntermNode.h"
+
+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() : TIntermTraverser(true, false, false) {}
+
+ 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;
+ }
+
+ TType boolType = TType(EbtBool);
+
+ // bool temp = false;
+ TIntermAggregate *tempDeclaration = nullptr;
+ {
+ TConstantUnion *falseConstant = new TConstantUnion();
+ falseConstant->setBConst(false);
+ TIntermTyped *falseValue = new TIntermConstantUnion(falseConstant, boolType);
+
+ tempDeclaration = createTempInitDeclaration(falseValue);
+ }
+
+ // temp = true;
+ TIntermBinary *assignTrue = nullptr;
+ {
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
+
+ assignTrue = createTempAssignment(trueValue);
+ }
+
+ // 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());
+
+ TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr);
+
+ TIntermBlock *innerIfBlock = new TIntermBlock();
+ innerIfBlock->getSequence()->push_back(innerIf);
+
+ breakIf = new TIntermIfElse(createTempSymbol(boolType), innerIfBlock, nullptr);
+ }
+
+ // Assemble the replacement loops, reusing the do-while loop's body and inserting our
+ // statements at the front.
+ TIntermLoop *newLoop = nullptr;
+ {
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
+
+ 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, trueValue, nullptr, body);
+ }
+
+ TIntermSequence replacement;
+ replacement.push_back(tempDeclaration);
+ replacement.push_back(newLoop);
+
+ node->replaceChildNodeWithMultiple(loop, replacement);
+
+ nextTemporaryIndex();
+ }
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ASSERT(temporaryIndex != 0);
+
+ DoWhileRewriter rewriter;
+ rewriter.useTemporaryIndex(temporaryIndex);
+
+ root->traverse(&rewriter);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.h
new file mode 100644
index 000000000..f6ec1caf0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteDoWhile.h
@@ -0,0 +1,16 @@
+//
+// 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_REWRITEDOWHILE_H_
+#define COMPILER_TRANSLATOR_REWRITEDOWHILE_H_
+
+class TIntermNode;
+void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_REWRITEDOWHILE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.cpp
new file mode 100644
index 000000000..aafb86f1c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.cpp
@@ -0,0 +1,124 @@
+//
+// 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/RewriteElseBlocks.h"
+
+#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/NodeSearch.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class ElseBlockRewriter : public TIntermTraverser
+{
+ public:
+ ElseBlockRewriter();
+
+ protected:
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override;
+ bool visitBlock(Visit visit, TIntermBlock *block) override;
+
+ private:
+ const TType *mFunctionType;
+
+ TIntermNode *rewriteIfElse(TIntermIfElse *ifElse);
+};
+
+ElseBlockRewriter::ElseBlockRewriter()
+ : TIntermTraverser(true, false, true),
+ mFunctionType(NULL)
+{}
+
+bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ // Store the current function context (see comment below)
+ mFunctionType = ((visit == PreVisit) ? &node->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);
+
+ nextTemporaryIndex();
+
+ TIntermTyped *typedCondition = ifElse->getCondition()->getAsTyped();
+ TIntermAggregate *storeCondition = createTempInitDeclaration(typedCondition);
+
+ 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)
+ {
+ TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
+ mFunctionType->getBasicString();
+ TString rawText = "return (" + typeString + ")0";
+ TIntermRaw *returnNode = new TIntermRaw(*mFunctionType, rawText);
+ negatedElse = new TIntermBlock();
+ negatedElse->getSequence()->push_back(returnNode);
+ }
+
+ TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType);
+ TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse);
+ TIntermIfElse *falseIfElse =
+ new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse);
+ falseBlock = TIntermediate::EnsureBlock(falseIfElse);
+ }
+
+ TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType);
+ TIntermIfElse *newIfElse =
+ new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock);
+
+ TIntermBlock *block = new TIntermBlock();
+ block->getSequence()->push_back(storeCondition);
+ block->getSequence()->push_back(newIfElse);
+
+ return block;
+}
+
+}
+
+void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex)
+{
+ ElseBlockRewriter rewriter;
+ rewriter.useTemporaryIndex(temporaryIndex);
+ node->traverse(&rewriter);
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteElseBlocks.h
new file mode 100644
index 000000000..24a425e66
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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_REWRITEELSEBLOCKS_H_
+#define COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex);
+
+}
+
+#endif // COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.cpp
new file mode 100644
index 000000000..6d0c866f8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.cpp
@@ -0,0 +1,170 @@
+//
+// 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/RewriteTexelFetchOffset.h"
+
+#include "common/angleutils.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.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() != EOpFunctionCall || node->isUserDefined())
+ {
+ return true;
+ }
+
+ if (node->getFunctionSymbolInfo()->getName().compare(0, 16, "texelFetchOffset") != 0)
+ {
+ return true;
+ }
+
+ // Potential problem case detected, apply workaround.
+ const TIntermSequence *sequence = node->getSequence();
+ ASSERT(sequence->size() == 4u);
+
+ // Decide if there is a 2DArray sampler.
+ bool is2DArray = node->getFunctionSymbolInfo()->getName().find("s2a1") != TString::npos;
+
+ // Create new argument list from node->getName().
+ // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
+ TString newArgs = node->getFunctionSymbolInfo()->getName().substr(
+ 16, node->getFunctionSymbolInfo()->getName().length() - 20);
+ TString newName = "texelFetch" + newArgs;
+ TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
+ ASSERT(texelFetchSymbol);
+ int uniqueId = texelFetchSymbol->getUniqueId();
+
+ // Create new node that represents the call of function texelFetch.
+ // Its argument list will be: texelFetch(sampler, Position+offset, lod).
+ TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
+ texelFetchNode->getFunctionSymbolInfo()->setName(newName);
+ texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
+ texelFetchNode->setType(node->getType());
+ texelFetchNode->setLine(node->getLine());
+
+ // sampler
+ texelFetchNode->getSequence()->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.
+ TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3);
+ constructIVec3Node->setLine(texCoordNode->getLine());
+ constructIVec3Node->setType(texCoordNode->getType());
+
+ constructIVec3Node->getSequence()->push_back(sequence->at(3)->getAsTyped());
+
+ TConstantUnion *zero = new TConstantUnion();
+ zero->setIConst(0);
+ TType *intType = new TType(EbtInt);
+
+ TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
+ constructIVec3Node->getSequence()->push_back(zeroNode);
+
+ offsetNode = constructIVec3Node;
+ }
+ else
+ {
+ offsetNode = sequence->at(3)->getAsTyped();
+ }
+
+ // Position+offset
+ TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
+ add->setLine(texCoordNode->getLine());
+ texelFetchNode->getSequence()->push_back(add);
+
+ // lod
+ texelFetchNode->getSequence()->push_back(sequence->at(2));
+
+ ASSERT(texelFetchNode->getSequence()->size() == 3u);
+
+ // Replace the old node by this new node.
+ queueReplacement(node, 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
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.h
new file mode 100644
index 000000000..c6db66457
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteTexelFetchOffset.h
@@ -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.
+//
+// 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_REWRITE_TEXELFETCHOFFSET_H_
+#define COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+namespace sh
+{
+
+void RewriteTexelFetchOffset(TIntermNode *root,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp
new file mode 100644
index 000000000..d20580507
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp
@@ -0,0 +1,112 @@
+//
+// 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/RewriteUnaryMinusOperatorInt.h"
+
+#include "compiler/translator/IntermNode.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);
+ 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, opr->getType());
+ oneNode->getTypePointer()->setQualifier(EvqConst);
+ oneNode->setLine(opr->getLine());
+
+ // ~(int) + 1
+ TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode);
+ add->setLine(opr->getLine());
+
+ queueReplacement(node, add, OriginalNode::IS_DROPPED);
+
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void RewriteUnaryMinusOperatorInt(TIntermNode *root)
+{
+ Traverser::Apply(root);
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.h b/Source/ThirdParty/ANGLE/src/compiler/translator/RewriteUnaryMinusOperatorInt.h
new file mode 100644
index 000000000..802ed5748
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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_REWRITEUNARYMINUSOPERATORINT_H_
+#define COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void RewriteUnaryMinusOperatorInt(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
new file mode 100644
index 000000000..96789bdcf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
@@ -0,0 +1,276 @@
+//
+// 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 "common/debug.h"
+#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
+
+#include <algorithm>
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+
+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;
+}
+
+TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
+{
+ return new TIntermBinary(EOpIndexDirect, symbolNode, TIntermTyped::CreateIndexNode(index));
+}
+
+TIntermBinary *ConstructMatrixIndexBinaryNode(
+ TIntermSymbol *symbolNode, int colIndex, int rowIndex)
+{
+ TIntermBinary *colVectorNode =
+ ConstructVectorIndexBinaryNode(symbolNode, colIndex);
+
+ return new TIntermBinary(EOpIndexDirect, colVectorNode,
+ TIntermTyped::CreateIndexNode(rowIndex));
+}
+
+} // namespace anonymous
+
+bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit == PreVisit)
+ {
+ switch (node->getOp())
+ {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ if (ContainsMatrixNode(*(node->getSequence())))
+ scalarizeArgs(node, false, true);
+ break;
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ if (ContainsVectorNode(*(node->getSequence())))
+ scalarizeArgs(node, true, false);
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+bool ScalarizeVecAndMatConstructorArgs::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 ScalarizeVecAndMatConstructorArgs::scalarizeArgs(
+ TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix)
+{
+ ASSERT(aggregate);
+ int size = 0;
+ switch (aggregate->getOp())
+ {
+ case EOpConstructVec2:
+ case EOpConstructBVec2:
+ case EOpConstructIVec2:
+ size = 2;
+ break;
+ case EOpConstructVec3:
+ case EOpConstructBVec3:
+ case EOpConstructIVec3:
+ size = 3;
+ break;
+ case EOpConstructVec4:
+ case EOpConstructBVec4:
+ case EOpConstructIVec4:
+ case EOpConstructMat2:
+ size = 4;
+ break;
+ case EOpConstructMat2x3:
+ case EOpConstructMat3x2:
+ size = 6;
+ break;
+ case EOpConstructMat2x4:
+ case EOpConstructMat4x2:
+ size = 8;
+ break;
+ case EOpConstructMat3:
+ size = 9;
+ break;
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x3:
+ size = 12;
+ break;
+ case EOpConstructMat4:
+ size = 16;
+ break;
+ default:
+ break;
+ }
+ TIntermSequence *sequence = aggregate->getSequence();
+ TIntermSequence original(*sequence);
+ sequence->clear();
+ for (size_t ii = 0; ii < original.size(); ++ii)
+ {
+ ASSERT(size > 0);
+ TIntermTyped *node = original[ii]->getAsTyped();
+ ASSERT(node);
+ TString varName = createTempVariable(node);
+ if (node->isScalar())
+ {
+ TIntermSymbol *symbolNode =
+ new TIntermSymbol(-1, varName, node->getType());
+ sequence->push_back(symbolNode);
+ size--;
+ }
+ else if (node->isVector())
+ {
+ if (scalarizeVector)
+ {
+ int repeat = std::min(size, node->getNominalSize());
+ size -= repeat;
+ for (int index = 0; index < repeat; ++index)
+ {
+ TIntermSymbol *symbolNode =
+ new TIntermSymbol(-1, varName, node->getType());
+ TIntermBinary *newNode = ConstructVectorIndexBinaryNode(
+ symbolNode, index);
+ sequence->push_back(newNode);
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbolNode =
+ new TIntermSymbol(-1, varName, node->getType());
+ sequence->push_back(symbolNode);
+ size -= node->getNominalSize();
+ }
+ }
+ else
+ {
+ ASSERT(node->isMatrix());
+ if (scalarizeMatrix)
+ {
+ int colIndex = 0, rowIndex = 0;
+ int repeat = std::min(size, node->getCols() * node->getRows());
+ size -= repeat;
+ while (repeat > 0)
+ {
+ TIntermSymbol *symbolNode =
+ new TIntermSymbol(-1, varName, node->getType());
+ TIntermBinary *newNode = ConstructMatrixIndexBinaryNode(
+ symbolNode, colIndex, rowIndex);
+ sequence->push_back(newNode);
+ rowIndex++;
+ if (rowIndex >= node->getRows())
+ {
+ rowIndex = 0;
+ colIndex++;
+ }
+ repeat--;
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbolNode =
+ new TIntermSymbol(-1, varName, node->getType());
+ sequence->push_back(symbolNode);
+ size -= node->getCols() * node->getRows();
+ }
+ }
+ }
+}
+
+TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original)
+{
+ TString tempVarName = "_webgl_tmp_";
+ if (original->isScalar())
+ {
+ tempVarName += "scalar_";
+ }
+ else if (original->isVector())
+ {
+ tempVarName += "vec_";
+ }
+ else
+ {
+ ASSERT(original->isMatrix());
+ tempVarName += "mat_";
+ }
+ tempVarName += Str(mTempVarCount).c_str();
+ mTempVarCount++;
+
+ ASSERT(original);
+ TType type = 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);
+ }
+
+ TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
+ TIntermBinary *init = new TIntermBinary(EOpInitialize, symbolNode, original);
+
+ TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
+ decl->getSequence()->push_back(init);
+
+ ASSERT(mBlockStack.size() > 0);
+ TIntermSequence &sequence = mBlockStack.back();
+ sequence.push_back(decl);
+
+ return tempVarName;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
new file mode 100644
index 000000000..eac6125a6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
@@ -0,0 +1,49 @@
+//
+// 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_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
+#define COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
+
+#include "compiler/translator/IntermNode.h"
+
+class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser
+{
+ public:
+ ScalarizeVecAndMatConstructorArgs(sh::GLenum shaderType,
+ bool fragmentPrecisionHigh)
+ : TIntermTraverser(true, false, false),
+ mTempVarCount(0),
+ mShaderType(shaderType),
+ mFragmentPrecisionHigh(fragmentPrecisionHigh) {}
+
+ 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 _webgl_tmp_mat_0 = m;
+ // vec4 v(1, _webgl_tmp_mat_0[0][0], _webgl_tmp_mat_0[0][1], _webgl_tmp_mat_0[0][2]);
+ // This function is to create nodes for "mat4 _webgl_tmp_mat_0 = m;" and insert it to
+ // the code sequence.
+ // Return the temporary variable name.
+ TString createTempVariable(TIntermTyped *original);
+
+ std::vector<TIntermSequence> mBlockStack;
+ int mTempVarCount;
+
+ sh::GLenum mShaderType;
+ bool mFragmentPrecisionHigh;
+};
+
+#endif // COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.cpp
index 9368f1a4f..cccd4d3ff 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.cpp
@@ -6,14 +6,15 @@
// SearchSymbol is an AST traverser to detect the use of a given symbol name
//
-#include "compiler/SearchSymbol.h"
+#include "compiler/translator/SearchSymbol.h"
-#include "compiler/InfoSink.h"
-#include "compiler/OutputHLSL.h"
+#include "compiler/translator/InfoSink.h"
namespace sh
{
-SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+SearchSymbol::SearchSymbol(const TString &symbol)
+ : TIntermTraverser(true, false, false),
+ mSymbol(symbol)
{
match = false;
}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.h
index 224bc77c6..1e5e1700d 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SearchSymbol.h
@@ -6,11 +6,11 @@
// SearchSymbol is an AST traverser to detect the use of a given symbol name
//
-#ifndef COMPILER_SEARCHSYMBOL_H_
-#define COMPILER_SEARCHSYMBOL_H_
+#ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
+#define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
-#include "compiler/intermediate.h"
-#include "compiler/ParseContext.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/ParseContext.h"
namespace sh
{
@@ -20,7 +20,7 @@ class SearchSymbol : public TIntermTraverser
SearchSymbol(const TString &symbol);
void traverse(TIntermNode *node);
- void visitSymbol(TIntermSymbol *symbolNode);
+ void visitSymbol(TIntermSymbol *symbolNode) override;
bool foundMatch() const;
@@ -30,4 +30,4 @@ class SearchSymbol : public TIntermTraverser
};
}
-#endif // COMPILER_SEARCHSYMBOL_H_
+#endif // COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.cpp
new file mode 100644
index 000000000..8cd1fa109
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.cpp
@@ -0,0 +1,91 @@
+//
+// 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/SeparateArrayInitialization.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/OutputHLSL.h"
+
+namespace
+{
+
+class SeparateArrayInitTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ SeparateArrayInitTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void SeparateArrayInitTraverser::apply(TIntermNode *root)
+{
+ SeparateArrayInitTraverser separateInit;
+ root->traverse(&separateInit);
+ separateInit.updateTree();
+}
+
+SeparateArrayInitTraverser::SeparateArrayInitTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
+ if (initNode != nullptr && initNode->getOp() == EOpInitialize)
+ {
+ TIntermTyped *initializer = initNode->getRight();
+ if (initializer->isArray() && !sh::OutputHLSL::canWriteAsHLSLLiteral(initializer))
+ {
+ // 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;
+
+ TIntermAggregate *replacementDeclaration = new TIntermAggregate;
+ replacementDeclaration->setOp(EOpDeclaration);
+ replacementDeclaration->getSequence()->push_back(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;
+ }
+ return true;
+}
+
+} // namespace
+
+void SeparateArrayInitialization(TIntermNode *root)
+{
+ SeparateArrayInitTraverser::apply(root);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.h
new file mode 100644
index 000000000..d16357a3a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateArrayInitialization.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.
+//
+// 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_SEPARATEARRAYINITIALIZATION_H_
+#define COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
+
+class TIntermNode;
+
+void SeparateArrayInitialization(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.cpp
new file mode 100644
index 000000000..cc339ea64
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/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/SeparateDeclarations.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class SeparateDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ SeparateDeclarationsTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void SeparateDeclarationsTraverser::apply(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser separateDecl;
+ root->traverse(&separateDecl);
+ separateDecl.updateTree();
+}
+
+SeparateDeclarationsTraverser::SeparateDeclarationsTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool SeparateDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ 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)
+ {
+ TIntermAggregate *replacementDeclaration = new TIntermAggregate;
+
+ replacementDeclaration->setOp(EOpDeclaration);
+ replacementDeclaration->getSequence()->push_back(sequence->at(ii));
+ replacementDeclaration->setLine(sequence->at(ii)->getLine());
+ replacementDeclarations.push_back(replacementDeclaration);
+ }
+
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacementDeclarations));
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void SeparateDeclarations(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser::apply(root);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.h
new file mode 100644
index 000000000..77913ab8b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateDeclarations.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.
+//
+// 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_SEPARATEDECLARATIONS_H_
+#define COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
+
+class TIntermNode;
+
+void SeparateDeclarations(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
new file mode 100644
index 000000000..44bf554e4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
@@ -0,0 +1,139 @@
+//
+// 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/SeparateExpressionsReturningArrays.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+
+namespace
+{
+
+// Traverser that separates one array expression into a statement at a time.
+class SeparateExpressionsTraverser : public TIntermTraverser
+{
+ public:
+ SeparateExpressionsTraverser();
+
+ 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()
+ : TIntermTraverser(true, false, false),
+ 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());
+}
+
+// Performs a shallow copy of a constructor/function call node.
+TIntermAggregate *CopyAggregateNode(TIntermAggregate *node)
+{
+ TIntermAggregate *copyNode = new TIntermAggregate(node->getOp());
+ TIntermSequence *copySeq = copyNode->getSequence();
+ copySeq->insert(copySeq->begin(), node->getSequence()->begin(), node->getSequence()->end());
+ copyNode->setType(node->getType());
+ *copyNode->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
+ if (node->isUserDefined())
+ {
+ copyNode->setUserDefined();
+ }
+ return copyNode;
+}
+
+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.
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(node, createTempSymbol(node->getType()), 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() == EOpFunctionCall);
+
+ mFoundArrayExpression = true;
+
+ TIntermSequence insertions;
+ insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node)));
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
+
+ return false;
+}
+
+void SeparateExpressionsTraverser::nextIteration()
+{
+ mFoundArrayExpression = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ SeparateExpressionsTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // 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());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.h
new file mode 100644
index 000000000..b178ebb3e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SeparateExpressionsReturningArrays.h
@@ -0,0 +1,19 @@
+//
+// 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_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+#define COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+
+class TIntermNode;
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderLang.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderLang.cpp
new file mode 100644
index 000000000..37b1114a2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderLang.cpp
@@ -0,0 +1,410 @@
+//
+// 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 "compiler/translator/VariablePacker.h"
+#include "angle_gl.h"
+
+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<sh::Uniform> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getUniforms();
+}
+
+template <>
+const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getVaryings();
+}
+
+template <>
+const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getAttributes();
+}
+
+template <>
+const std::vector<sh::OutputVariable> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getOutputVariables();
+}
+
+template <>
+const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getInterfaceBlocks();
+}
+
+template <typename VarT>
+const std::vector<VarT> *GetShaderVariables(const ShHandle handle)
+{
+ if (!handle)
+ {
+ return NULL;
+ }
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler)
+ {
+ return NULL;
+ }
+
+ return GetVariableList<VarT>(compiler);
+}
+
+TCompiler *GetCompilerFromHandle(ShHandle handle)
+{
+ if (!handle)
+ return NULL;
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ return base->getAsCompiler();
+}
+
+#ifdef ANGLE_ENABLE_HLSL
+TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle)
+{
+ if (!handle)
+ return NULL;
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ return base->getAsTranslatorHLSL();
+}
+#endif // ANGLE_ENABLE_HLSL
+
+} // anonymous namespace
+
+//
+// Driver must call this first, once, before doing any other compiler operations.
+// Subsequent calls to this function are no-op.
+//
+bool ShInitialize()
+{
+ if (!isInitialized)
+ {
+ isInitialized = InitProcess();
+ }
+ return isInitialized;
+}
+
+//
+// Cleanup symbol tables
+//
+bool ShFinalize()
+{
+ if (isInitialized)
+ {
+ DetachProcess();
+ isInitialized = false;
+ }
+ return true;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(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->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;
+
+ // Disable name hashing by default.
+ resources->HashFunction = NULL;
+
+ 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
+ resources->MaxImageUnits = 4;
+ resources->MaxVertexImageUniforms = 0;
+ resources->MaxFragmentImageUniforms = 0;
+ resources->MaxComputeImageUniforms = 4;
+ resources->MaxCombinedImageUniforms = 4;
+
+ 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;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ShConstructCompiler(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)) {
+ ShDestruct(base);
+ return 0;
+ }
+
+ return reinterpret_cast<void*>(base);
+}
+
+void ShDestruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+const std::string &ShGetBuiltInResourcesString(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 ShCompile(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 ShClearResults(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ compiler->clearResults();
+}
+
+int ShGetShaderVersion(const ShHandle handle)
+{
+ TCompiler* compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return compiler->getShaderVersion();
+}
+
+ShShaderOutput ShGetShaderOutputType(const ShHandle handle)
+{
+ TCompiler* compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return compiler->getOutputType();
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+const std::string &ShGetInfoLog(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+
+ TInfoSink &infoSink = compiler->getInfoSink();
+ return infoSink.info.str();
+}
+
+//
+// Return any object code.
+//
+const std::string &ShGetObjectCode(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+
+ TInfoSink &infoSink = compiler->getInfoSink();
+ return infoSink.obj.str();
+}
+
+const std::map<std::string, std::string> *ShGetNameHashingMap(
+ const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return &(compiler->getNameMap());
+}
+
+const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
+{
+ return GetShaderVariables<sh::Uniform>(handle);
+}
+
+const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle)
+{
+ return GetShaderVariables<sh::Varying>(handle);
+}
+
+const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle)
+{
+ return GetShaderVariables<sh::Attribute>(handle);
+}
+
+const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle)
+{
+ return GetShaderVariables<sh::OutputVariable>(handle);
+}
+
+const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle)
+{
+ return GetShaderVariables<sh::InterfaceBlock>(handle);
+}
+
+sh::WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getComputeShaderLocalSize();
+}
+
+bool ShCheckVariablesWithinPackingLimits(int maxVectors,
+ const std::vector<sh::ShaderVariable> &variables)
+{
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxVectors, variables);
+}
+
+bool ShGetInterfaceBlockRegister(const ShHandle handle,
+ const std::string &interfaceBlockName,
+ unsigned int *indexOut)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ ASSERT(indexOut);
+
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ if (!translator->hasInterfaceBlock(interfaceBlockName))
+ {
+ return false;
+ }
+
+ *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName);
+ return true;
+#else
+ return false;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(const ShHandle handle)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ return translator->getUniformRegisterMap();
+#else
+ return nullptr;
+#endif // ANGLE_ENABLE_HLSL
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderVars.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderVars.cpp
new file mode 100644
index 000000000..8e217f1c0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ShaderVars.cpp
@@ -0,0 +1,488 @@
+//
+// 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"
+
+namespace sh
+{
+
+namespace
+{
+
+InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation)
+{
+ return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation);
+}
+
+}
+// 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()
+ : type(0),
+ precision(0),
+ arraySize(0),
+ staticUse(false)
+{}
+
+ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn)
+ : type(typeIn),
+ precision(0),
+ arraySize(arraySizeIn),
+ staticUse(false)
+{}
+
+ShaderVariable::~ShaderVariable()
+{}
+
+ShaderVariable::ShaderVariable(const ShaderVariable &other)
+ : type(other.type),
+ precision(other.precision),
+ name(other.name),
+ mappedName(other.mappedName),
+ arraySize(other.arraySize),
+ staticUse(other.staticUse),
+ fields(other.fields),
+ structName(other.structName)
+{}
+
+ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
+{
+ type = other.type;
+ precision = other.precision;
+ name = other.name;
+ mappedName = other.mappedName;
+ arraySize = other.arraySize;
+ staticUse = other.staticUse;
+ fields = other.fields;
+ structName = other.structName;
+ return *this;
+}
+
+bool ShaderVariable::operator==(const ShaderVariable &other) const
+{
+ if (type != other.type ||
+ precision != other.precision ||
+ name != other.name ||
+ mappedName != other.mappedName ||
+ arraySize != other.arraySize ||
+ staticUse != other.staticUse ||
+ fields.size() != other.fields.size() ||
+ structName != other.structName)
+ {
+ return false;
+ }
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (fields[ii] != other.fields[ii])
+ return false;
+ }
+ return true;
+}
+
+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 = NULL;
+ std::string originalFieldName;
+ bool found = fields[ii].findInfoByMappedName(
+ remaining, &fieldVar, &originalFieldName);
+ if (found)
+ {
+ *originalFullName = originalName + "." + originalFieldName;
+ *leafVar = fieldVar;
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+bool ShaderVariable::isSameVariableAtLinkTime(
+ const ShaderVariable &other, bool matchPrecision) const
+{
+ if (type != other.type)
+ return false;
+ if (matchPrecision && precision != other.precision)
+ return false;
+ if (name != other.name)
+ return false;
+ ASSERT(mappedName == other.mappedName);
+ if (arraySize != other.arraySize)
+ return false;
+ if (fields.size() != other.fields.size())
+ return false;
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii],
+ matchPrecision))
+ {
+ return false;
+ }
+ }
+ if (structName != other.structName)
+ return false;
+ return true;
+}
+
+Uniform::Uniform()
+{}
+
+Uniform::~Uniform()
+{}
+
+Uniform::Uniform(const Uniform &other)
+ : ShaderVariable(other)
+{}
+
+Uniform &Uniform::operator=(const Uniform &other)
+{
+ ShaderVariable::operator=(other);
+ return *this;
+}
+
+bool Uniform::operator==(const Uniform &other) const
+{
+ return ShaderVariable::operator==(other);
+}
+
+bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
+{
+ return ShaderVariable::isSameVariableAtLinkTime(other, true);
+}
+
+InterfaceVariable::InterfaceVariable() : location(-1)
+{}
+
+InterfaceVariable::~InterfaceVariable()
+{}
+
+InterfaceVariable::InterfaceVariable(const InterfaceVariable &other)
+ : ShaderVariable(other), location(other.location)
+{}
+
+InterfaceVariable &InterfaceVariable::operator=(const InterfaceVariable &other)
+{
+ ShaderVariable::operator=(other);
+ location = other.location;
+ return *this;
+}
+
+bool InterfaceVariable::operator==(const InterfaceVariable &other) const
+{
+ return (ShaderVariable::operator==(other) &&
+ location == other.location);
+}
+
+Attribute::Attribute()
+{
+}
+
+Attribute::~Attribute()
+{
+}
+
+Attribute::Attribute(const Attribute &other) : InterfaceVariable(other)
+{
+}
+
+Attribute &Attribute::operator=(const Attribute &other)
+{
+ InterfaceVariable::operator=(other);
+ return *this;
+}
+
+bool Attribute::operator==(const Attribute &other) const
+{
+ return InterfaceVariable::operator==(other);
+}
+
+OutputVariable::OutputVariable()
+{
+}
+
+OutputVariable::~OutputVariable()
+{
+}
+
+OutputVariable::OutputVariable(const OutputVariable &other) : InterfaceVariable(other)
+{
+}
+
+OutputVariable &OutputVariable::operator=(const OutputVariable &other)
+{
+ InterfaceVariable::operator=(other);
+ return *this;
+}
+
+bool OutputVariable::operator==(const OutputVariable &other) const
+{
+ return InterfaceVariable::operator==(other);
+}
+
+InterfaceBlockField::InterfaceBlockField()
+ : isRowMajorLayout(false)
+{}
+
+InterfaceBlockField::~InterfaceBlockField()
+{}
+
+InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other)
+ : ShaderVariable(other),
+ isRowMajorLayout(other.isRowMajorLayout)
+{}
+
+InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
+{
+ ShaderVariable::operator=(other);
+ isRowMajorLayout = other.isRowMajorLayout;
+ return *this;
+}
+
+bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
+{
+ return (ShaderVariable::operator==(other) &&
+ isRowMajorLayout == other.isRowMajorLayout);
+}
+
+bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
+ const InterfaceBlockField &other) const
+{
+ return (ShaderVariable::isSameVariableAtLinkTime(other, true) &&
+ isRowMajorLayout == other.isRowMajorLayout);
+}
+
+Varying::Varying()
+ : interpolation(INTERPOLATION_SMOOTH),
+ isInvariant(false)
+{}
+
+Varying::~Varying()
+{}
+
+Varying::Varying(const Varying &other)
+ : ShaderVariable(other),
+ interpolation(other.interpolation),
+ isInvariant(other.isInvariant)
+{}
+
+Varying &Varying::operator=(const Varying &other)
+{
+ ShaderVariable::operator=(other);
+ interpolation = other.interpolation;
+ isInvariant = other.isInvariant;
+ return *this;
+}
+
+bool Varying::operator==(const Varying &other) const
+{
+ return (ShaderVariable::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) &&
+ InterpolationTypesMatch(interpolation, other.interpolation) &&
+ (shaderVersion >= 300 || isInvariant == other.isInvariant));
+}
+
+InterfaceBlock::InterfaceBlock()
+ : arraySize(0),
+ layout(BLOCKLAYOUT_PACKED),
+ isRowMajorLayout(false),
+ staticUse(false)
+{}
+
+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),
+ staticUse(other.staticUse),
+ 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;
+ staticUse = other.staticUse;
+ fields = other.fields;
+ return *this;
+}
+
+std::string InterfaceBlock::fieldPrefix() const
+{
+ return instanceName.empty() ? "" : name;
+}
+
+bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
+{
+ if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
+ layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
+ 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;
+}
+
+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/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.cpp
new file mode 100644
index 000000000..b8cc976ea
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.cpp
@@ -0,0 +1,280 @@
+//
+// 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/SimplifyLoopConditions.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+
+namespace
+{
+
+TIntermConstantUnion *CreateBoolConstantNode(bool value)
+{
+ TConstantUnion *u = new TConstantUnion;
+ u->setBConst(value);
+ TIntermConstantUnion *node =
+ new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1));
+ return node;
+}
+
+class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
+{
+ public:
+ SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+ void traverseLoop(TIntermLoop *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 foundLoopToChange() const { return mFoundLoopToChange; }
+
+ 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 mFoundLoopToChange;
+ bool mInsideLoopConditionOrExpression;
+ IntermNodePatternMatcher mConditionsToSimplify;
+};
+
+SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
+ unsigned int conditionsToSimplifyMask,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
+ mFoundLoopToChange(false),
+ mInsideLoopConditionOrExpression(false),
+ mConditionsToSimplify(conditionsToSimplifyMask)
+{
+}
+
+void SimplifyLoopConditionsTraverser::nextIteration()
+{
+ mFoundLoopToChange = false;
+ mInsideLoopConditionOrExpression = false;
+ nextTemporaryIndex();
+}
+
+bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ // The visit functions operate in three modes:
+ // 1. If a matching expression has already been found, we return early since only one loop can
+ // be transformed on one traversal.
+ // 2. We try to find loops. In case a node is not inside a loop and can not contain loops, we
+ // stop traversing the subtree.
+ // 3. If we're inside a loop 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 processed.
+
+ if (mFoundLoopToChange)
+ return false;
+
+ if (!mInsideLoopConditionOrExpression)
+ return false;
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFoundLoopToChange)
+ return false;
+
+ // If we're outside a loop condition, we only need to traverse nodes that may contain loops.
+ if (!mInsideLoopConditionOrExpression)
+ return false;
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ if (mFoundLoopToChange)
+ return false;
+
+ // Don't traverse ternary operators outside loop conditions.
+ if (!mInsideLoopConditionOrExpression)
+ return false;
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node);
+ return !mFoundLoopToChange;
+}
+
+void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
+{
+ if (mFoundLoopToChange)
+ return;
+
+ // Mark that we're inside a loop condition or expression, and transform the loop if needed.
+
+ incrementDepth(node);
+
+ // Note: No need to traverse the loop init node.
+
+ mInsideLoopConditionOrExpression = true;
+ TLoopType loopType = node->getType();
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+
+ if (mFoundLoopToChange)
+ {
+ // Replace the loop condition with a boolean variable that's updated on each iteration.
+ if (loopType == ELoopWhile)
+ {
+ // Transform:
+ // while (expr) { body; }
+ // into
+ // bool s0 = expr;
+ // while (s0) { { body; } s0 = expr; }
+ TIntermSequence tempInitSeq;
+ tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy()));
+ insertStatementsInParentBlock(tempInitSeq);
+
+ TIntermBlock *newBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ newBody->getSequence()->push_back(node->getBody());
+ }
+ newBody->getSequence()->push_back(
+ createTempAssignment(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 - this node won't be traversed
+ // further.
+ node->setBody(newBody);
+ node->setCondition(createTempSymbol(node->getCondition()->getType()));
+ }
+ else if (loopType == ELoopDoWhile)
+ {
+ // Transform:
+ // do {
+ // body;
+ // } while (expr);
+ // into
+ // bool s0 = true;
+ // do {
+ // { body; }
+ // s0 = expr;
+ // while (s0);
+ TIntermSequence tempInitSeq;
+ tempInitSeq.push_back(createTempInitDeclaration(CreateBoolConstantNode(true)));
+ insertStatementsInParentBlock(tempInitSeq);
+
+ TIntermBlock *newBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ newBody->getSequence()->push_back(node->getBody());
+ }
+ newBody->getSequence()->push_back(
+ createTempAssignment(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 - this node won't be traversed
+ // further.
+ node->setBody(newBody);
+ node->setCondition(createTempSymbol(node->getCondition()->getType()));
+ }
+ 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();
+ if (node->getInit())
+ {
+ loopScope->getSequence()->push_back(node->getInit());
+ }
+ loopScope->getSequence()->push_back(
+ createTempInitDeclaration(node->getCondition()->deepCopy()));
+
+ TIntermBlock *whileLoopBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ whileLoopBody->getSequence()->push_back(node->getBody());
+ }
+ whileLoopBody->getSequence()->push_back(node->getExpression());
+ whileLoopBody->getSequence()->push_back(
+ createTempAssignment(node->getCondition()->deepCopy()));
+ TIntermLoop *whileLoop = new TIntermLoop(
+ ELoopWhile, nullptr, createTempSymbol(node->getCondition()->getType()), nullptr,
+ whileLoopBody);
+ loopScope->getSequence()->push_back(whileLoop);
+ queueReplacementWithParent(getAncestorNode(1), node, loopScope,
+ OriginalNode::IS_DROPPED);
+ }
+ }
+ }
+
+ if (!mFoundLoopToChange && node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+
+ if (mFoundLoopToChange)
+ {
+ ASSERT(loopType == ELoopFor);
+ // Move the loop expression to inside the loop.
+ // Transform:
+ // for (init; expr; exprB) { body; }
+ // into
+ // for (init; expr; ) { { body; } exprB; }
+ TIntermTyped *loopExpression = node->getExpression();
+ node->setExpression(nullptr);
+ TIntermBlock *oldBody = node->getBody();
+ node->setBody(new TIntermBlock());
+ if (oldBody != nullptr)
+ {
+ node->getBody()->getSequence()->push_back(oldBody);
+ }
+ node->getBody()->getSequence()->push_back(loopExpression);
+ }
+ }
+
+ mInsideLoopConditionOrExpression = false;
+
+ if (!mFoundLoopToChange && node->getBody())
+ node->getBody()->traverse(this);
+
+ decrementDepth();
+}
+
+} // namespace
+
+void SimplifyLoopConditions(TIntermNode *root,
+ unsigned int conditionsToSimplifyMask,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable, shaderVersion);
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // Process one loop at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundLoopToChange())
+ traverser.updateTree();
+ } while (traverser.foundLoopToChange());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.h
new file mode 100644
index 000000000..b8802aa11
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SimplifyLoopConditions.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.
+//
+// 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_SIMPLIFYLOOPCONDITIONS_H_
+#define COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+void SimplifyLoopConditions(TIntermNode *root,
+ unsigned int conditionsToSimplify,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+#endif // COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.cpp
new file mode 100644
index 000000000..e0d28b9cd
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.cpp
@@ -0,0 +1,153 @@
+//
+// 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/SplitSequenceOperator.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+
+namespace
+{
+
+class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser
+{
+ public:
+ SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+ 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,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TLValueTrackingTraverser(true, false, true, symbolTable, shaderVersion),
+ mFoundExpressionToSplit(false),
+ mInsideSequenceOperator(0),
+ mPatternToSplitMatcher(patternsToSplitMask)
+{
+}
+
+void SplitSequenceOperatorTraverser::nextIteration()
+{
+ mFoundExpressionToSplit = false;
+ mInsideSequenceOperator = 0;
+ nextTemporaryIndex();
+}
+
+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::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, 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,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable, shaderVersion);
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // 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());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.h
new file mode 100644
index 000000000..4a46fe36c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SplitSequenceOperator.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.
+//
+// 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_SPLITSEQUENCEOPERATOR_H_
+#define COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+void SplitSequenceOperator(TIntermNode *root,
+ int patternsToSplitMask,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+#endif // COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.cpp
new file mode 100644
index 000000000..93e0ba573
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.cpp
@@ -0,0 +1,539 @@
+//
+// 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:
+// Definitions of methods for HLSL translation of GLSL structures.
+//
+
+#include "compiler/translator/StructureHLSL.h"
+#include "common/utilities.h"
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/Types.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+
+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;
+ 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, NULL);
+ }
+}
+
+TString StructureHLSL::defineNameless(const TStructure &structure)
+{
+ return define(structure, false, false, NULL);
+}
+
+TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
+ bool useStd140Packing, Std140PaddingHelper *padHelper)
+{
+ const TFieldList &fields = structure.fields();
+ const bool isNameless = (structure.name() == "");
+ 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) + ";\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 StructureHLSL::addConstructor(const TType &type,
+ const TString &name,
+ const TIntermSequence *parameters)
+{
+ if (name == "")
+ {
+ return TString(); // Nameless structures don't have constructors
+ }
+
+ if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
+ {
+ return TString(name); // Already added
+ }
+
+ TType ctorType = type;
+ ctorType.clearArrayness();
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ typedef std::vector<TType> ParameterArray;
+ ParameterArray ctorParameters;
+
+ TString constructorFunctionName;
+
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ mStructNames.insert(name);
+
+ // Add element index
+ storeStd140ElementIndex(*structure, false);
+ storeStd140ElementIndex(*structure, true);
+
+ const TString &structString = defineQualified(*structure, false, false);
+
+ if (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);
+ }
+
+ const TFieldList &fields = structure->fields();
+ for (const TField *field : fields)
+ {
+ const TType *fieldType = field->type();
+ if (!IsSampler(fieldType->getBasicType()))
+ {
+ ctorParameters.push_back(*fieldType);
+ }
+ }
+ constructorFunctionName = TString(name);
+ }
+ else if (parameters)
+ {
+ for (auto parameter : *parameters)
+ {
+ const TType &paramType = parameter->getAsTyped()->getType();
+ ctorParameters.push_back(paramType);
+ }
+ constructorFunctionName = TString(name) + DisambiguateFunctionName(parameters);
+ }
+ else UNREACHABLE();
+
+ TString constructor;
+
+ if (ctorType.getStruct())
+ {
+ constructor += name + " " + name + "_ctor(";
+ }
+ else // Built-in type
+ {
+ constructor += TypeString(ctorType) + " " + constructorFunctionName + "(";
+ }
+
+ for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+ {
+ const TType &paramType = ctorParameters[parameter];
+
+ constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
+
+ if (parameter < ctorParameters.size() - 1)
+ {
+ constructor += ", ";
+ }
+ }
+
+ constructor += ")\n"
+ "{\n";
+
+ if (ctorType.getStruct())
+ {
+ constructor += " " + name + " structure";
+ if (ctorParameters.empty())
+ {
+ constructor += ";\n";
+ }
+ else
+ {
+ constructor += " = { ";
+ }
+ }
+ else
+ {
+ constructor += " 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 = 0;
+ if (ctorType.getStruct())
+ {
+ remainingComponents = ctorParameters.size();
+ }
+ else
+ {
+ 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 (ctorType.getStruct())
+ {
+ ASSERT(remainingComponents == 1 || moreParameters);
+
+ --remainingComponents;
+ }
+ else 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 += ", ";
+ }
+ }
+ }
+
+ if (ctorType.getStruct())
+ {
+ if (!ctorParameters.empty())
+ {
+ constructor += "};\n";
+ }
+ constructor +=
+ " return structure;\n"
+ "}\n";
+ }
+ else
+ {
+ constructor += ");\n"
+ "}\n";
+ }
+
+ mConstructors.insert(constructor);
+
+ return constructorFunctionName;
+}
+
+std::string StructureHLSL::structsHeader() const
+{
+ TInfoSinkBase out;
+
+ for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
+ {
+ out << mStructDeclarations[structIndex];
+ }
+
+ for (Constructors::const_iterator constructor = mConstructors.begin();
+ constructor != mConstructors.end();
+ constructor++)
+ {
+ out << *constructor;
+ }
+
+ return out.str();
+}
+
+void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
+{
+ Std140PaddingHelper padHelper = getPaddingHelper();
+ const TFieldList &fields = structure.fields();
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ padHelper.prePadding(*fields[i]->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();
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.h
new file mode 100644
index 000000000..96139ec9a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/StructureHLSL.h
@@ -0,0 +1,85 @@
+//
+// 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:
+// Interfaces of methods for HLSL translation of GLSL 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. "name" parameter is the name of the type being
+ // constructed.
+ TString addConstructor(const TType &type,
+ const TString &name,
+ const TIntermSequence *parameters);
+ std::string structsHeader() const;
+
+ TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
+ static TString defineNameless(const TStructure &structure);
+
+ Std140PaddingHelper getPaddingHelper();
+
+ private:
+ unsigned mUniquePaddingCounter;
+
+ std::map<TString, int> mStd140StructElementIndexes;
+
+ typedef std::set<TString> StructNames;
+ StructNames mStructNames;
+
+ typedef std::set<TString> Constructors;
+ Constructors mConstructors;
+
+ typedef std::vector<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
+ static TString define(const TStructure &structure, bool useHLSLRowMajorPacking,
+ bool useStd140Packing, Std140PaddingHelper *padHelper);
+};
+
+}
+
+#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.cpp
new file mode 100644
index 000000000..aa23776b9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.cpp
@@ -0,0 +1,323 @@
+//
+// 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. Most functionaliy and main ideas
+// are documented in the header file.
+//
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4718)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/Cache.h"
+
+#include <stdio.h>
+#include <algorithm>
+
+int TSymbolTable::uniqueIdCounter = 0;
+
+TSymbol::TSymbol(const TString *n) : uniqueId(TSymbolTable::nextUniqueId()), name(n)
+{
+}
+
+//
+// Functions have buried pointers to delete.
+//
+TFunction::~TFunction()
+{
+ clearParameters();
+}
+
+void TFunction::clearParameters()
+{
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
+ parameters.clear();
+ mangledName = nullptr;
+}
+
+void TFunction::swapParameters(const TFunction &parametersSource)
+{
+ clearParameters();
+ for (auto parameter : parametersSource.parameters)
+ {
+ addParameter(parameter);
+ }
+}
+
+const TString *TFunction::buildMangledName() const
+{
+ std::string newName = mangleName(getName()).c_str();
+
+ for (const auto &p : parameters)
+ {
+ newName += p.type->getMangledName().c_str();
+ }
+
+ return NewPoolTString(newName.c_str());
+}
+
+//
+// Symbol table levels are a map of pointers to symbols that have to be deleted.
+//
+TSymbolTableLevel::~TSymbolTableLevel()
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
+}
+
+bool TSymbolTableLevel::insert(TSymbol *symbol)
+{
+ // returning true means symbol was added to the table
+ tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
+
+ return result.second;
+}
+
+bool TSymbolTableLevel::insertUnmangled(TFunction *function)
+{
+ // returning true means symbol was added to the table
+ tInsertResult result = level.insert(tLevelPair(function->getName(), function));
+
+ return result.second;
+}
+
+TSymbol *TSymbolTableLevel::find(const TString &name) const
+{
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return 0;
+ else
+ return (*it).second;
+}
+
+TSymbol *TSymbolTable::find(const TString &name, int shaderVersion,
+ bool *builtIn, bool *sameScope) const
+{
+ int level = currentLevel();
+ TSymbol *symbol;
+
+ do
+ {
+ if (level == ESSL3_1_BUILTINS && shaderVersion != 310)
+ level--;
+ if (level == ESSL3_BUILTINS && shaderVersion < 300)
+ level--;
+ if (level == ESSL1_BUILTINS && shaderVersion != 100)
+ level--;
+
+ symbol = table[level]->find(name);
+ }
+ while (symbol == 0 && --level >= 0);
+
+ if (builtIn)
+ *builtIn = (level <= LAST_BUILTIN_LEVEL);
+ if (sameScope)
+ *sameScope = (level == currentLevel());
+
+ return symbol;
+}
+
+TSymbol *TSymbolTable::findBuiltIn(
+ const TString &name, int shaderVersion) const
+{
+ for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--)
+ {
+ if (level == ESSL3_1_BUILTINS && shaderVersion != 310)
+ level--;
+ if (level == ESSL3_BUILTINS && shaderVersion < 300)
+ level--;
+ if (level == ESSL1_BUILTINS && shaderVersion != 100)
+ level--;
+
+ TSymbol *symbol = table[level]->find(name);
+
+ if (symbol)
+ return symbol;
+ }
+
+ return 0;
+}
+
+TSymbolTable::~TSymbolTable()
+{
+ while (table.size() > 0)
+ pop();
+}
+
+bool IsGenType(const TType *type)
+{
+ if (type)
+ {
+ TBasicType basicType = type->getBasicType();
+ return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType || basicType == EbtGenBType;
+ }
+
+ return false;
+}
+
+bool IsVecType(const TType *type)
+{
+ if (type)
+ {
+ TBasicType basicType = type->getBasicType();
+ return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec || basicType == EbtBVec;
+ }
+
+ return false;
+}
+
+const TType *SpecificType(const TType *type, int size)
+{
+ ASSERT(size >= 1 && size <= 4);
+
+ if (!type)
+ {
+ return nullptr;
+ }
+
+ ASSERT(!IsVecType(type));
+
+ switch(type->getBasicType())
+ {
+ case EbtGenType: return TCache::getType(EbtFloat, static_cast<unsigned char>(size));
+ case EbtGenIType: return TCache::getType(EbtInt, static_cast<unsigned char>(size));
+ case EbtGenUType: return TCache::getType(EbtUInt, static_cast<unsigned char>(size));
+ case EbtGenBType: return TCache::getType(EbtBool, static_cast<unsigned char>(size));
+ default: return type;
+ }
+}
+
+const TType *VectorType(const TType *type, int size)
+{
+ ASSERT(size >= 2 && size <= 4);
+
+ if (!type)
+ {
+ return nullptr;
+ }
+
+ ASSERT(!IsGenType(type));
+
+ switch(type->getBasicType())
+ {
+ case EbtVec: return TCache::getType(EbtFloat, static_cast<unsigned char>(size));
+ case EbtIVec: return TCache::getType(EbtInt, static_cast<unsigned char>(size));
+ case EbtUVec: return TCache::getType(EbtUInt, static_cast<unsigned char>(size));
+ case EbtBVec: return TCache::getType(EbtBool, static_cast<unsigned char>(size));
+ default: return type;
+ }
+}
+
+void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2, const TType *ptype3, const TType *ptype4, const TType *ptype5)
+{
+ if (ptype1->getBasicType() == EbtGSampler2D)
+ {
+ insertUnmangledBuiltIn(name);
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5);
+ }
+ else if (ptype1->getBasicType() == EbtGSampler3D)
+ {
+ insertUnmangledBuiltIn(name);
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5);
+ }
+ else if (ptype1->getBasicType() == EbtGSamplerCube)
+ {
+ insertUnmangledBuiltIn(name);
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ }
+ else if (ptype1->getBasicType() == EbtGSampler2DArray)
+ {
+ insertUnmangledBuiltIn(name);
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ }
+ else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
+ {
+ ASSERT(!ptype4 && !ptype5);
+ insertUnmangledBuiltIn(name);
+ insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1));
+ insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2));
+ insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3));
+ insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4));
+ }
+ else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
+ {
+ ASSERT(!ptype4 && !ptype5);
+ insertUnmangledBuiltIn(name);
+ insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2));
+ insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3));
+ insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4));
+ }
+ else
+ {
+ TFunction *function = new TFunction(NewPoolTString(name), rvalue, op, ext);
+
+ function->addParameter(TConstParameter(ptype1));
+
+ if (ptype2)
+ {
+ function->addParameter(TConstParameter(ptype2));
+ }
+
+ if (ptype3)
+ {
+ function->addParameter(TConstParameter(ptype3));
+ }
+
+ if (ptype4)
+ {
+ function->addParameter(TConstParameter(ptype4));
+ }
+
+ if (ptype5)
+ {
+ function->addParameter(TConstParameter(ptype5));
+ }
+
+ ASSERT(hasUnmangledBuiltIn(name));
+ insert(level, function);
+ }
+}
+
+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>(precisionStack.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 = precisionStack[level]->find(baseType);
+ if (it != precisionStack[level]->end())
+ {
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.h b/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.h
new file mode 100644
index 000000000..51a82f724
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable.h
@@ -0,0 +1,541 @@
+//
+// 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 <array>
+#include <assert.h>
+#include <set>
+
+#include "common/angleutils.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+// Symbol base class. (Can build functions or variables out of these...)
+class TSymbol : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TSymbol(const TString *n);
+
+ virtual ~TSymbol()
+ {
+ // don't delete name, it's from the pool
+ }
+
+ const TString &getName() const
+ {
+ return *name;
+ }
+ virtual const TString &getMangledName() const
+ {
+ return getName();
+ }
+ virtual bool isFunction() const
+ {
+ return false;
+ }
+ virtual bool isVariable() const
+ {
+ return false;
+ }
+ int getUniqueId() const
+ {
+ return uniqueId;
+ }
+ void relateToExtension(const TString &ext)
+ {
+ extension = ext;
+ }
+ const TString &getExtension() const
+ {
+ return extension;
+ }
+
+ private:
+ const int uniqueId;
+ const TString *name;
+ TString extension;
+};
+
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class heirarchy for Constant variables;
+// Only one of int, bool, or float, (or none) is correct for
+// any particular use, but it's easy to do this way, and doesn't
+// seem worth having separate classes, and "getConst" can't simply return
+// different values for different types polymorphically, so this is
+// just simple and pragmatic.
+class TVariable : public TSymbol
+{
+ public:
+ TVariable(const TString *name, const TType &t, bool uT = false)
+ : TSymbol(name),
+ type(t),
+ userType(uT),
+ unionArray(0)
+ {
+ }
+ ~TVariable() override {}
+ bool isVariable() const override { return true; }
+ TType &getType()
+ {
+ return type;
+ }
+ const TType &getType() const
+ {
+ return type;
+ }
+ bool isUserType() const
+ {
+ return userType;
+ }
+ void setQualifier(TQualifier qualifier)
+ {
+ type.setQualifier(qualifier);
+ }
+
+ const TConstantUnion *getConstPointer() const { return unionArray; }
+
+ void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; }
+
+ private:
+ TType type;
+ bool userType;
+ // we are assuming that Pool Allocator will free the memory
+ // allocated to unionArray when this object is destroyed.
+ const TConstantUnion *unionArray;
+};
+
+// Immutable version of TParameter.
+struct TConstParameter
+{
+ TConstParameter()
+ : name(nullptr),
+ type(nullptr)
+ {
+ }
+ explicit TConstParameter(const TString *n)
+ : name(n),
+ type(nullptr)
+ {
+ }
+ explicit TConstParameter(const TType *t)
+ : name(nullptr),
+ type(t)
+ {
+ }
+ TConstParameter(const TString *n, const TType *t)
+ : name(n),
+ type(t)
+ {
+ }
+
+ // Both constructor arguments must be const.
+ TConstParameter(TString *n, TType *t) = delete;
+ TConstParameter(const TString *n, TType *t) = delete;
+ TConstParameter(TString *n, const TType *t) = delete;
+
+ const TString *name;
+ const TType *type;
+};
+
+// The function sub-class of symbols and the parser will need to
+// share this definition of a function parameter.
+struct TParameter
+{
+ // Destructively converts to TConstParameter.
+ // This method resets name and type to nullptrs to make sure
+ // their content cannot be modified after the call.
+ TConstParameter turnToConst()
+ {
+ const TString *constName = name;
+ const TType *constType = type;
+ name = nullptr;
+ type = nullptr;
+ return TConstParameter(constName, constType);
+ }
+
+ TString *name;
+ TType *type;
+};
+
+// The function sub-class of a symbol.
+class TFunction : public TSymbol
+{
+ public:
+ TFunction(const TString *name,
+ const TType *retType,
+ TOperator tOp = EOpNull,
+ const char *ext = "")
+ : TSymbol(name),
+ returnType(retType),
+ mangledName(nullptr),
+ op(tOp),
+ defined(false),
+ mHasPrototypeDeclaration(false)
+ {
+ relateToExtension(ext);
+ }
+ ~TFunction() override;
+ bool isFunction() const override { return true; }
+
+ static TString mangleName(const TString &name)
+ {
+ return name + '(';
+ }
+ static TString unmangleName(const TString &mangledName)
+ {
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+ }
+
+ void addParameter(const TConstParameter &p)
+ {
+ parameters.push_back(p);
+ mangledName = nullptr;
+ }
+
+ void swapParameters(const TFunction &parametersSource);
+
+ const TString &getMangledName() const override
+ {
+ if (mangledName == nullptr)
+ {
+ mangledName = buildMangledName();
+ }
+ return *mangledName;
+ }
+ const TType &getReturnType() const
+ {
+ return *returnType;
+ }
+
+ TOperator getBuiltInOp() const
+ {
+ return op;
+ }
+
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+ void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
+ bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
+
+ size_t getParamCount() const
+ {
+ return parameters.size();
+ }
+ const TConstParameter &getParam(size_t i) const
+ {
+ return parameters[i];
+ }
+
+ private:
+ void clearParameters();
+
+ const TString *buildMangledName() const;
+
+ typedef TVector<TConstParameter> TParamList;
+ TParamList parameters;
+ const TType *returnType;
+ mutable const TString *mangledName;
+ TOperator op;
+ bool defined;
+ bool mHasPrototypeDeclaration;
+};
+
+// Interface block name sub-symbol
+class TInterfaceBlockName : public TSymbol
+{
+ public:
+ TInterfaceBlockName(const TString *name)
+ : TSymbol(name)
+ {
+ }
+
+ virtual ~TInterfaceBlockName()
+ {
+ }
+};
+
+class TSymbolTableLevel
+{
+ public:
+ typedef TMap<TString, TSymbol *> tLevel;
+ typedef tLevel::const_iterator const_iterator;
+ typedef const tLevel::value_type tLevelPair;
+ typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+ TSymbolTableLevel()
+ : mGlobalInvariant(false)
+ {
+ }
+ ~TSymbolTableLevel();
+
+ bool insert(TSymbol *symbol);
+
+ // Insert a function using its unmangled name as the key.
+ bool insertUnmangled(TFunction *function);
+
+ TSymbol *find(const TString &name) const;
+
+ void addInvariantVarying(const std::string &name)
+ {
+ mInvariantVaryings.insert(name);
+ }
+
+ bool isVaryingInvariant(const std::string &name)
+ {
+ return (mGlobalInvariant || mInvariantVaryings.count(name) > 0);
+ }
+
+ void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; }
+
+ protected:
+ tLevel level;
+ std::set<std::string> mInvariantVaryings;
+ bool mGlobalInvariant;
+};
+
+// Define ESymbolLevel as int rather than an enum since level can go
+// above GLOBAL_LEVEL and cause atBuiltInLevel() to fail if the
+// compiler optimizes the >= of the last element to ==.
+typedef int ESymbolLevel;
+const int COMMON_BUILTINS = 0;
+const int ESSL1_BUILTINS = 1;
+const int ESSL3_BUILTINS = 2;
+const int ESSL3_1_BUILTINS = 3;
+const int LAST_BUILTIN_LEVEL = ESSL3_1_BUILTINS;
+const int GLOBAL_LEVEL = 4;
+
+class TSymbolTable : angle::NonCopyable
+{
+ public:
+ TSymbolTable()
+ {
+ // The symbol table cannot be used until push() is called, but
+ // the lack of an initial call to push() can be used to detect
+ // that the symbol table has not been preloaded with built-ins.
+ }
+
+ ~TSymbolTable();
+
+ // When the symbol table is initialized with the built-ins, there should
+ // 'push' calls, so that built-ins are at level 0 and the shader
+ // globals are at level 1.
+ bool isEmpty() const
+ {
+ return table.empty();
+ }
+ bool atBuiltInLevel() const
+ {
+ return currentLevel() <= LAST_BUILTIN_LEVEL;
+ }
+ bool atGlobalLevel() const
+ {
+ return currentLevel() == GLOBAL_LEVEL;
+ }
+ void push()
+ {
+ table.push_back(new TSymbolTableLevel);
+ precisionStack.push_back(new PrecisionStackLevel);
+ }
+
+ void pop()
+ {
+ delete table.back();
+ table.pop_back();
+
+ delete precisionStack.back();
+ precisionStack.pop_back();
+ }
+
+ bool declare(TSymbol *symbol)
+ {
+ return insert(currentLevel(), symbol);
+ }
+
+ bool insert(ESymbolLevel level, TSymbol *symbol)
+ {
+ return table[level]->insert(symbol);
+ }
+
+ bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol)
+ {
+ symbol->relateToExtension(ext);
+ return table[level]->insert(symbol);
+ }
+
+ bool insertConstInt(ESymbolLevel level, const char *name, int value, TPrecision precision)
+ {
+ TVariable *constant =
+ new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 1));
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(value);
+ constant->shareConstPointer(unionArray);
+ return insert(level, constant);
+ }
+
+ bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
+ {
+ TVariable *constant =
+ new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(value);
+ constant->shareConstPointer(unionArray);
+ return insert(level, ext, constant);
+ }
+
+ bool insertConstIvec3(ESymbolLevel level,
+ const char *name,
+ const std::array<int, 3> &values,
+ TPrecision precision)
+ {
+ TVariable *constantIvec3 =
+ new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 3));
+
+ TConstantUnion *unionArray = new TConstantUnion[3];
+ for (size_t index = 0u; index < 3u; ++index)
+ {
+ unionArray[index].setIConst(values[index]);
+ }
+ constantIvec3->shareConstPointer(unionArray);
+
+ return insert(level, constantIvec3);
+ }
+
+ void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0);
+
+ void insertBuiltIn(ESymbolLevel level, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
+ {
+ insertUnmangledBuiltIn(name);
+ insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
+ }
+
+ void insertBuiltIn(ESymbolLevel level, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
+ {
+ insertUnmangledBuiltIn(name);
+ insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
+ }
+
+ void insertBuiltIn(ESymbolLevel level, TOperator op, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
+ {
+ insertUnmangledBuiltIn(name);
+ insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
+ }
+
+ TSymbol *find(const TString &name, int shaderVersion,
+ bool *builtIn = NULL, bool *sameScope = NULL) const;
+ TSymbol *findBuiltIn(const TString &name, int shaderVersion) const;
+
+ TSymbolTableLevel *getOuterLevel()
+ {
+ assert(currentLevel() >= 1);
+ return table[currentLevel() - 1];
+ }
+
+ void dump(TInfoSink &infoSink) const;
+
+ bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
+ {
+ if (!SupportsPrecision(type.getBasicType()))
+ return false;
+ if (type.getBasicType() == EbtUInt)
+ return false; // ESSL 3.00.4 section 4.5.4
+ if (type.isAggregate())
+ return false; // Not allowed to set for aggregate types
+ int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
+ // Uses map operator [], overwrites the current value
+ (*precisionStack[indexOfLastElement])[type.getBasicType()] = prec;
+ return true;
+ }
+
+ // 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 std::string &originalName)
+ {
+ ASSERT(atGlobalLevel());
+ table[currentLevel()]->addInvariantVarying(originalName);
+ }
+ // 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 std::string &originalName) const
+ {
+ ASSERT(atGlobalLevel());
+ return table[currentLevel()]->isVaryingInvariant(originalName);
+ }
+
+ void setGlobalInvariant(bool invariant)
+ {
+ ASSERT(atGlobalLevel());
+ table[currentLevel()]->setGlobalInvariant(invariant);
+ }
+
+ static int nextUniqueId()
+ {
+ return ++uniqueIdCounter;
+ }
+
+ bool hasUnmangledBuiltIn(const char *name)
+ {
+ return mUnmangledBuiltinNames.count(std::string(name)) > 0;
+ }
+
+ private:
+ ESymbolLevel currentLevel() const
+ {
+ return static_cast<ESymbolLevel>(table.size() - 1);
+ }
+
+ // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00.
+ void insertUnmangledBuiltIn(const char *name)
+ {
+ mUnmangledBuiltinNames.insert(std::string(name));
+ }
+
+ std::vector<TSymbolTableLevel *> table;
+ typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
+ std::vector< PrecisionStackLevel *> precisionStack;
+
+ std::set<std::string> mUnmangledBuiltinNames;
+
+ static int uniqueIdCounter;
+};
+
+#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.cpp
new file mode 100644
index 000000000..33d098531
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -0,0 +1,1274 @@
+//
+// 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/UtilsHLSL.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void OutputIntTexCoordWrap(TInfoSinkBase &out,
+ const char *wrapMode,
+ const char *size,
+ const TString &texCoord,
+ const TString &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";
+
+ // CLAMP_TO_EDGE
+ out << "if (" << wrapMode << " == 1)\n";
+ out << "{\n";
+ out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
+ << "Offset)), 0, int(" << size << ") - 1);\n";
+ out << "}\n";
+
+ // MIRRORED_REPEAT
+ out << "else if (" << wrapMode << " == 3)\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,
+ TString *texCoordX,
+ TString *texCoordY,
+ TString *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 = "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 = "tiy";
+
+ if (IsSamplerArray(textureFunction.sampler))
+ {
+ *texCoordZ = "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 = "tiz";
+ }
+}
+
+void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const TString &textureReference,
+ const TString &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)
+{
+ if (IsIntegerSampler(textureFunction.sampler) ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ switch (hlslCoords)
+ {
+ case 2:
+ return "int3";
+ case 3:
+ 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:
+ hlslCoords = 2;
+ break;
+ case EbtSamplerCube:
+ hlslCoords = 3;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ return hlslCoords;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler2D:
+ return 2;
+ case EbtSampler3D:
+ return 3;
+ case EbtSamplerCube:
+ return 3;
+ case EbtSampler2DArray:
+ return 3;
+ case EbtSamplerExternalOES:
+ return 2;
+ case EbtISampler2D:
+ return 2;
+ case EbtISampler3D:
+ return 3;
+ case EbtISamplerCube:
+ return 3;
+ case EbtISampler2DArray:
+ return 3;
+ case EbtUSampler2D:
+ return 2;
+ case EbtUSampler3D:
+ return 3;
+ case EbtUSamplerCube:
+ return 3;
+ case EbtUSampler2DArray:
+ return 3;
+ case EbtSampler2DShadow:
+ return 2;
+ case EbtSamplerCubeShadow:
+ return 3;
+ case EbtSampler2DArrayShadow:
+ return 3;
+ default:
+ UNREACHABLE();
+ }
+ }
+ 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);
+ 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 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:
+ out << ", int mip";
+ break;
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ 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:
+ UNREACHABLE();
+ }
+ }
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
+ {
+ out << ", float bias";
+ }
+}
+
+void GetTextureReference(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ TString *textureReference,
+ TString *samplerReference)
+{
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ TString suffix = TextureGroupSuffix(textureFunction.sampler);
+ if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
+ {
+ *textureReference = TString("textures") + suffix + "[samplerIndex]";
+ *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
+ }
+ else
+ {
+ out << " const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
+ << ";\n";
+ *textureReference = TString("textures") + suffix + "[textureIndex]";
+ out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
+ << ";\n";
+ *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
+ }
+ }
+ else
+ {
+ *textureReference = "x";
+ *samplerReference = "s";
+ }
+}
+
+void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const TString &textureReference,
+ bool getDimensionsIgnoresBaseLevel)
+{
+ 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);";
+ }
+ else
+ {
+ out << " return int2(width, height);";
+ }
+}
+
+void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
+ TString *texCoordX,
+ TString *texCoordY,
+ TString *texCoordZ)
+{
+ if (textureFunction.proj)
+ {
+ TString proj("");
+ switch (textureFunction.coords)
+ {
+ case 3:
+ proj = " / t.z";
+ break;
+ case 4:
+ proj = " / t.w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ *texCoordX = "(" + *texCoordX + proj + ")";
+ *texCoordY = "(" + *texCoordY + proj + ")";
+ *texCoordZ = "(" + *texCoordZ + proj + ")";
+ }
+}
+
+void OutputIntegerTextureSampleFunctionComputations(
+ TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ const TString &textureReference,
+ TString *texCoordX,
+ TString *texCoordY,
+ TString *texCoordZ)
+{
+ if (!IsIntegerSampler(textureFunction.sampler))
+ {
+ return;
+ }
+ if (IsSamplerCube(textureFunction.sampler))
+ {
+ out << " float width; float height; float layers; float levels;\n";
+
+ out << " uint mip = 0;\n";
+
+ out << " " << textureReference
+ << ".GetDimensions(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 << " 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)
+ {
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float2 dx = ddx(tSized);\n"
+ " float2 dy = ddy(tSized);\n"
+ " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\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(mip, width, height, layers, levels);\n";
+ }
+
+ // Convert from normalized floating-point to integer
+ *texCoordX = "int(floor(width * frac(" + *texCoordX + ")))";
+ *texCoordY = "int(floor(height * frac(" + *texCoordY + ")))";
+ *texCoordZ = "face";
+ }
+ else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ if (IsSampler2D(textureFunction.sampler))
+ {
+ 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(0, 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(mip, width, height, layers, levels);\n";
+ }
+ else
+ {
+ 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(0, 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(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(0, 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(mip, width, height, depth, levels);\n";
+ }
+ else
+ UNREACHABLE();
+
+ OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
+ }
+}
+
+void OutputTextureSampleFunctionReturnStatement(
+ TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ const TString &textureReference,
+ const TString &samplerReference,
+ const TString &texCoordX,
+ const TString &texCoordY,
+ const TString &texCoordZ)
+{
+ out << " return ";
+
+ // 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;
+ 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)
+ {
+ 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
+
+TString TextureFunctionHLSL::TextureFunction::name() const
+{
+ TString name = "gl_texture";
+
+ // 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 += TextureTypeSuffix(this->sampler);
+
+ 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;
+ 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:
+ return "int2";
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DArrayShadow:
+ return "int3";
+ default:
+ UNREACHABLE();
+ }
+ }
+ else // Sampling function
+ {
+ switch (sampler)
+ {
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSampler2DArray:
+ case EbtSamplerExternalOES:
+ return "float4";
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ return "int4";
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ return "uint4";
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ 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);
+}
+
+TString TextureFunctionHLSL::useTextureFunction(const TString &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
+ 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)
+ {
+ 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.
+ TString textureReference;
+ TString samplerReference;
+ GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
+
+ if (textureFunction.method == TextureFunction::SIZE)
+ {
+ OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
+ getDimensionsIgnoresBaseLevel);
+ }
+ else
+ {
+ TString texCoordX("t.x");
+ TString texCoordY("t.y");
+ TString texCoordZ("t.z");
+ ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
+ OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
+ textureReference, &texCoordX, &texCoordY,
+ &texCoordZ);
+ OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
+ textureReference, samplerReference,
+ texCoordX, texCoordY, texCoordZ);
+ }
+
+ out << "}\n"
+ "\n";
+ }
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.h
new file mode 100644
index 000000000..68bf8c089
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TextureFunctionHLSL.h
@@ -0,0 +1,76 @@
+//
+// 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 "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/InfoSink.h"
+#include "GLSLANG/ShaderLang.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
+ };
+
+ TString 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.
+ TString useTextureFunction(const TString &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/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.cpp
new file mode 100644
index 000000000..109b1700d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.cpp
@@ -0,0 +1,109 @@
+//
+// 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 "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/RecordConstantPrecision.h"
+#include "compiler/translator/OutputESSL.h"
+#include "angle_gl.h"
+
+TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
+ : TCompiler(type, spec, SH_ESSL_OUTPUT)
+{
+}
+
+void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
+{
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ int shaderVer = getShaderVersion();
+ if (shaderVer > 100)
+ {
+ sink << "#version " << shaderVer << " es\n";
+ }
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior();
+
+ // 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(), shaderVer);
+ root->traverse(&emulatePrecision);
+ emulatePrecision.updateTree();
+ emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT);
+ }
+
+ RecordConstantPrecision(root, getTemporaryIndex());
+
+ // 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 webgl_emu_precision highp\n"
+ << "#else\n"
+ << "#define webgl_emu_precision mediump\n"
+ << "#endif\n\n";
+ }
+ else
+ {
+ sink << "#define webgl_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 && isComputeShaderLocalSizeDeclared())
+ {
+ const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
+ sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
+ << ", local_size_z=" << localSize[2] << ") in;\n";
+ }
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
+ getSymbolTable(), shaderVer, precisionEmulation);
+ root->traverse(&outputESSL);
+}
+
+bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not necessary when translating to ESSL.
+ return false;
+}
+
+void TranslatorESSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ if (iter->second != EBhUndefined) {
+ if (getResources().NV_shader_framebuffer_fetch && iter->first == "GL_EXT_shader_framebuffer_fetch") {
+ sink << "#extension GL_NV_shader_framebuffer_fetch : "
+ << getBehaviorString(iter->second) << "\n";
+ } else if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") {
+ sink << "#extension GL_NV_draw_buffers : "
+ << getBehaviorString(iter->second) << "\n";
+ } else {
+ sink << "#extension " << iter->first << " : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+ }
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.h
new file mode 100644
index 000000000..f147ca066
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorESSL.h
@@ -0,0 +1,25 @@
+//
+// 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"
+
+class TranslatorESSL : public TCompiler
+{
+ public:
+ TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
+
+ protected:
+ void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+
+ private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.cpp
new file mode 100644
index 000000000..a0ee01f55
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.cpp
@@ -0,0 +1,291 @@
+//
+// 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/EmulatePrecision.h"
+#include "compiler/translator/ExtensionGLSL.h"
+#include "compiler/translator/OutputGLSL.h"
+#include "compiler/translator/RewriteTexelFetchOffset.h"
+#include "compiler/translator/VersionGLSL.h"
+
+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());
+ }
+
+ int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
+ InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
+}
+
+void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
+{
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(root);
+
+ // Write extension behaviour as needed
+ writeExtensionBehavior(root);
+
+ // 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) && getPragma().stdgl.invariantAll)
+ {
+ collectVariables(root);
+
+ 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());
+ }
+
+ bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
+
+ if (precisionEmulation)
+ {
+ EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
+ 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 webgl_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(), "GL_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 : outputVariables)
+ {
+ 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 && isComputeShaderLocalSizeDeclared())
+ {
+ const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
+ sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
+ << ", local_size_z=" << localSize[2] << ") in;\n";
+ }
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink,
+ getArrayIndexClampingStrategy(),
+ getHashFunction(),
+ getNameMap(),
+ getSymbolTable(),
+ getShaderVersion(),
+ getOutputType());
+ 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());
+}
+
+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)
+{
+ 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 == "GL_EXT_shader_texture_lod")
+ {
+ sink << "#extension GL_ARB_shader_texture_lod : " << getBehaviorString(iter.second)
+ << "\n";
+ }
+
+ if (iter.first == "GL_EXT_draw_buffers")
+ {
+ sink << "#extension GL_ARB_draw_buffers : " << 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)
+ {
+ 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)
+ {
+ sink << "#extension GL_ARB_gpu_shader5 : ";
+
+ // Don't use "require" on WebGL 1 to avoid breaking WebGL on drivers that silently
+ // support index constant sampler array indexing, but don't have the extension.
+ if (getShaderVersion() >= 300)
+ {
+ sink << "require\n";
+ }
+ else
+ {
+ sink << "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";
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.h
new file mode 100644
index 000000000..f234c18ec
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorGLSL.h
@@ -0,0 +1,30 @@
+//
+// 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"
+
+class TranslatorGLSL : public TCompiler
+{
+ public:
+ TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+
+ protected:
+ void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions) override;
+
+ void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+
+ private:
+ void writeVersion(TIntermNode *root);
+ void writeExtensionBehavior(TIntermNode *root);
+ void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName);
+};
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.cpp
new file mode 100644
index 000000000..fb011da76
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.cpp
@@ -0,0 +1,143 @@
+//
+// 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/AddDefaultReturnStatements.h"
+#include "compiler/translator/ArrayReturnValueToOutParameter.h"
+#include "compiler/translator/BreakVariableAliasingInInnerLoops.h"
+#include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/ExpandIntegerPowExpressions.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/RemoveDynamicIndexing.h"
+#include "compiler/translator/RewriteElseBlocks.h"
+#include "compiler/translator/RewriteTexelFetchOffset.h"
+#include "compiler/translator/RewriteUnaryMinusOperatorInt.h"
+#include "compiler/translator/SeparateArrayInitialization.h"
+#include "compiler/translator/SeparateDeclarations.h"
+#include "compiler/translator/SeparateExpressionsReturningArrays.h"
+#include "compiler/translator/SimplifyLoopConditions.h"
+#include "compiler/translator/SplitSequenceOperator.h"
+#include "compiler/translator/UnfoldShortCircuitToIf.h"
+
+TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{
+}
+
+void TranslatorHLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
+{
+ const ShBuiltInResources &resources = getResources();
+ int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
+
+ sh::AddDefaultReturnStatements(root);
+
+ SeparateDeclarations(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.
+ SimplifyLoopConditions(root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ getTemporaryIndex(), getSymbolTable(), getShaderVersion());
+
+ SplitSequenceOperator(root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ getTemporaryIndex(), getSymbolTable(), getShaderVersion());
+
+ // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
+ UnfoldShortCircuitToIf(root, getTemporaryIndex());
+
+ SeparateExpressionsReturningArrays(root, getTemporaryIndex());
+
+ // 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, getTemporaryIndex());
+
+ if (!shouldRunLoopAndIndexingValidation(compileOptions))
+ {
+ // HLSL doesn't support dynamic indexing of vectors and matrices.
+ RemoveDynamicIndexing(root, getTemporaryIndex(), getSymbolTable(), getShaderVersion());
+ }
+
+ // 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, getTemporaryIndex());
+ }
+
+ // 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);
+
+ bool precisionEmulation =
+ getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
+
+ if (precisionEmulation)
+ {
+ EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
+ root->traverse(&emulatePrecision);
+ emulatePrecision.updateTree();
+ emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(),
+ getOutputType());
+ }
+
+ if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0)
+ {
+ sh::ExpandIntegerPowExpressions(root, getTemporaryIndex());
+ }
+
+ 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);
+ }
+
+ sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
+ getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions);
+
+ outputHLSL.output(root, getInfoSink().obj);
+
+ mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap();
+ mUniformRegisterMap = outputHLSL.getUniformRegisterMap();
+}
+
+bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not necessary when translating to HLSL.
+ return false;
+}
+
+bool TranslatorHLSL::hasInterfaceBlock(const std::string &interfaceBlockName) const
+{
+ return (mInterfaceBlockRegisterMap.count(interfaceBlockName) > 0);
+}
+
+unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interfaceBlockName) const
+{
+ ASSERT(hasInterfaceBlock(interfaceBlockName));
+ return mInterfaceBlockRegisterMap.find(interfaceBlockName)->second;
+}
+
+const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
+{
+ return &mUniformRegisterMap;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.h
new file mode 100644
index 000000000..d2add14e3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorHLSL.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_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATOR_TRANSLATORHLSL_H_
+
+#include "compiler/translator/Compiler.h"
+
+class TranslatorHLSL : public TCompiler
+{
+ public:
+ TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *getAsTranslatorHLSL() override { return this; }
+#endif // ANGLE_ENABLE_HLSL
+
+ bool hasInterfaceBlock(const std::string &interfaceBlockName) const;
+ unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const;
+
+ const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
+
+ protected:
+ void translate(TIntermNode *root, ShCompileOptions compileOptions) 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> mInterfaceBlockRegisterMap;
+ std::map<std::string, unsigned int> mUniformRegisterMap;
+};
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Types.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/Types.cpp
new file mode 100644
index 000000000..598be2871
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Types.cpp
@@ -0,0 +1,487 @@
+//
+// 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/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+
+#include <algorithm>
+#include <climits>
+
+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 EbtSampler2D: return "sampler2D";
+ case EbtSampler3D: return "sampler3D";
+ case EbtSamplerCube: return "samplerCube";
+ case EbtSamplerExternalOES: return "samplerExternalOES";
+ case EbtSampler2DRect: return "sampler2DRect";
+ case EbtSampler2DArray: return "sampler2DArray";
+ case EbtISampler2D: return "isampler2D";
+ case EbtISampler3D: return "isampler3D";
+ case EbtISamplerCube: return "isamplerCube";
+ case EbtISampler2DArray: return "isampler2DArray";
+ case EbtUSampler2D: return "usampler2D";
+ case EbtUSampler3D: return "usampler3D";
+ case EbtUSamplerCube: return "usamplerCube";
+ case EbtUSampler2DArray: return "usampler2DArray";
+ case EbtSampler2DShadow: return "sampler2DShadow";
+ case EbtSamplerCubeShadow: return "samplerCubeShadow";
+ case EbtSampler2DArrayShadow: return "sampler2DArrayShadow";
+ case EbtStruct: return "structure";
+ case EbtInterfaceBlock: return "interface block";
+ default: UNREACHABLE(); return "unknown type";
+ }
+}
+
+TType::TType(const TPublicType &p)
+ : type(p.getBasicType()),
+ precision(p.precision),
+ qualifier(p.qualifier),
+ invariant(p.invariant),
+ layoutQualifier(p.layoutQualifier),
+ primarySize(p.getPrimarySize()),
+ secondarySize(p.getSecondarySize()),
+ array(p.array),
+ arraySize(p.arraySize),
+ interfaceBlock(0),
+ structure(0)
+{
+ if (p.getUserDef())
+ structure = p.getUserDef()->getStruct();
+}
+
+bool TStructure::equals(const TStructure &other) const
+{
+ return (uniqueId() == other.uniqueId());
+}
+
+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();
+}
+
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (invariant)
+ stream << "invariant ";
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " ";
+ if (precision != EbpUndefined)
+ stream << getPrecisionString() << " ";
+ if (array)
+ stream << "array[" << getArraySize() << "] of ";
+ if (isMatrix())
+ stream << getCols() << "X" << getRows() << " matrix of ";
+ else if (isVector())
+ stream << getNominalSize() << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
+//
+// Recursively generate mangled names.
+//
+TString TType::buildMangledName() const
+{
+ TString mangledName;
+ if (isMatrix())
+ mangledName += 'm';
+ else if (isVector())
+ mangledName += 'v';
+
+ switch (type)
+ {
+ case EbtFloat:
+ mangledName += 'f';
+ break;
+ case EbtInt:
+ mangledName += 'i';
+ break;
+ case EbtUInt:
+ mangledName += 'u';
+ break;
+ case EbtBool:
+ mangledName += 'b';
+ break;
+ case EbtSampler2D:
+ mangledName += "s2";
+ break;
+ case EbtSampler3D:
+ mangledName += "s3";
+ break;
+ case EbtSamplerCube:
+ mangledName += "sC";
+ break;
+ case EbtSampler2DArray:
+ mangledName += "s2a";
+ break;
+ case EbtSamplerExternalOES:
+ mangledName += "sext";
+ break;
+ case EbtSampler2DRect:
+ mangledName += "s2r";
+ break;
+ case EbtISampler2D:
+ mangledName += "is2";
+ break;
+ case EbtISampler3D:
+ mangledName += "is3";
+ break;
+ case EbtISamplerCube:
+ mangledName += "isC";
+ break;
+ case EbtISampler2DArray:
+ mangledName += "is2a";
+ break;
+ case EbtUSampler2D:
+ mangledName += "us2";
+ break;
+ case EbtUSampler3D:
+ mangledName += "us3";
+ break;
+ case EbtUSamplerCube:
+ mangledName += "usC";
+ break;
+ case EbtUSampler2DArray:
+ mangledName += "us2a";
+ break;
+ case EbtSampler2DShadow:
+ mangledName += "s2s";
+ break;
+ case EbtSamplerCubeShadow:
+ mangledName += "sCs";
+ break;
+ case EbtSampler2DArrayShadow:
+ mangledName += "s2as";
+ break;
+ case EbtStruct:
+ mangledName += structure->mangledName();
+ break;
+ case EbtInterfaceBlock:
+ mangledName += interfaceBlock->mangledName();
+ break;
+ default:
+ // EbtVoid, EbtAddress and non types
+ break;
+ }
+
+ if (isMatrix())
+ {
+ mangledName += static_cast<char>('0' + getCols());
+ mangledName += static_cast<char>('x');
+ mangledName += static_cast<char>('0' + getRows());
+ }
+ else
+ {
+ mangledName += static_cast<char>('0' + getNominalSize());
+ }
+
+ if (isArray())
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+ return mangledName;
+}
+
+size_t TType::getObjectSize() const
+{
+ size_t totalSize;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = structure->objectSize();
+ else
+ totalSize = primarySize * secondarySize;
+
+ if (isArray())
+ {
+ if (totalSize == 0)
+ return 0;
+
+ size_t currentArraySize = getArraySize();
+ if (currentArraySize > INT_MAX / totalSize)
+ totalSize = INT_MAX;
+ else
+ totalSize *= currentArraySize;
+ }
+
+ return totalSize;
+}
+
+TStructure::TStructure(const TString *name, TFieldList *fields)
+ : TFieldListCollection(name, fields),
+ mDeepestNesting(0),
+ mUniqueId(TSymbolTable::nextUniqueId()),
+ mAtGlobalScope(false)
+{
+}
+
+bool TStructure::containsArrays() const
+{
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ const TType *fieldType = (*mFields)[i]->type();
+ if (fieldType->isArray() || fieldType->isStructureContainingArrays())
+ return true;
+ }
+ return false;
+}
+
+bool TStructure::containsType(TBasicType type) const
+{
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ const TType *fieldType = (*mFields)[i]->type();
+ if (fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
+ return true;
+ }
+ return false;
+}
+
+bool TStructure::containsSamplers() const
+{
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ const TType *fieldType = (*mFields)[i]->type();
+ if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers())
+ return true;
+ }
+ return false;
+}
+
+void TStructure::createSamplerSymbols(const TString &structName,
+ const TString &structAPIName,
+ const unsigned int arrayOfStructsSize,
+ TVector<TIntermSymbol *> *outputSymbols,
+ TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
+{
+ for (auto &field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (IsSampler(fieldType->getBasicType()))
+ {
+ if (arrayOfStructsSize > 0u)
+ {
+ for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex)
+ {
+ TStringStream name;
+ name << structName << "_" << arrayIndex << "_" << field->name();
+ TIntermSymbol *symbol = new TIntermSymbol(0, name.str(), *fieldType);
+ outputSymbols->push_back(symbol);
+
+ if (outputSymbolsToAPINames)
+ {
+ TStringStream apiName;
+ apiName << structAPIName << "[" << arrayIndex << "]." << field->name();
+ (*outputSymbolsToAPINames)[symbol] = apiName.str();
+ }
+ }
+ }
+ else
+ {
+ TString symbolName = structName + "_" + field->name();
+ TIntermSymbol *symbol = new TIntermSymbol(0, symbolName, *fieldType);
+ outputSymbols->push_back(symbol);
+
+ if (outputSymbolsToAPINames)
+ {
+ TString apiName = structAPIName + "." + field->name();
+ (*outputSymbolsToAPINames)[symbol] = apiName;
+ }
+ }
+ }
+ else if (fieldType->isStructureContainingSamplers())
+ {
+ unsigned int nestedArrayOfStructsSize =
+ fieldType->isArray() ? fieldType->getArraySize() : 0u;
+ if (arrayOfStructsSize > 0)
+ {
+ for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex)
+ {
+ TStringStream fieldName;
+ fieldName << structName << "_" << arrayIndex << "_" << field->name();
+ TStringStream fieldAPIName;
+ if (outputSymbolsToAPINames)
+ {
+ fieldAPIName << structAPIName << "[" << arrayIndex << "]." << field->name();
+ }
+ fieldType->createSamplerSymbols(fieldName.str(), fieldAPIName.str(),
+ nestedArrayOfStructsSize, outputSymbols,
+ outputSymbolsToAPINames);
+ }
+ }
+ else
+ {
+ fieldType->createSamplerSymbols(
+ structName + "_" + field->name(), structAPIName + "." + field->name(),
+ nestedArrayOfStructsSize, outputSymbols, outputSymbolsToAPINames);
+ }
+ }
+ }
+}
+
+TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const
+{
+ TString mangledName(mangledNamePrefix);
+ mangledName += *mName;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ mangledName += '-';
+ mangledName += (*mFields)[i]->type()->getMangledName();
+ }
+ return mangledName;
+}
+
+size_t TFieldListCollection::calculateObjectSize() const
+{
+ size_t size = 0;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
+ if (fieldSize > INT_MAX - size)
+ size = INT_MAX;
+ else
+ size += fieldSize;
+ }
+ return size;
+}
+
+int TStructure::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;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/Types.h b/Source/ThirdParty/ANGLE/src/compiler/translator/Types.h
new file mode 100644
index 000000000..ab1b6c3ff
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/Types.h
@@ -0,0 +1,715 @@
+//
+// 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"
+
+struct TPublicType;
+class TType;
+class TSymbol;
+class TIntermSymbol;
+
+class TField : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TField(TType *type, TString *name, const TSourceLoc &line)
+ : mType(type),
+ mName(name),
+ mLine(line)
+ {
+ }
+
+ // TODO(alokp): We should only return const type.
+ // Fix it by tweaking grammar.
+ TType *type()
+ {
+ return mType;
+ }
+ const TType *type() const
+ {
+ return mType;
+ }
+
+ const TString &name() const
+ {
+ return *mName;
+ }
+ const TSourceLoc &line() const
+ {
+ return mLine;
+ }
+
+ private:
+ TType *mType;
+ TString *mName;
+ TSourceLoc mLine;
+};
+
+typedef TVector<TField *> TFieldList;
+inline TFieldList *NewPoolTFieldList()
+{
+ void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList));
+ return new(memory) TFieldList;
+}
+
+class TFieldListCollection : angle::NonCopyable
+{
+ public:
+ const TString &name() const
+ {
+ return *mName;
+ }
+ const TFieldList &fields() const
+ {
+ return *mFields;
+ }
+
+ size_t objectSize() const
+ {
+ if (mObjectSize == 0)
+ mObjectSize = calculateObjectSize();
+ return mObjectSize;
+ };
+
+ protected:
+ TFieldListCollection(const TString *name, TFieldList *fields)
+ : mName(name),
+ mFields(fields),
+ mObjectSize(0)
+ {
+ }
+ TString buildMangledName(const TString &mangledNamePrefix) const;
+ size_t calculateObjectSize() const;
+
+ const TString *mName;
+ TFieldList *mFields;
+
+ mutable TString mMangledName;
+ mutable size_t mObjectSize;
+};
+
+// May also represent interface blocks
+class TStructure : public TFieldListCollection
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TStructure(const TString *name, TFieldList *fields);
+
+ int deepestNesting() const
+ {
+ if (mDeepestNesting == 0)
+ mDeepestNesting = calculateDeepestNesting();
+ return mDeepestNesting;
+ }
+ bool containsArrays() const;
+ bool containsType(TBasicType t) const;
+ bool containsSamplers() const;
+
+ void createSamplerSymbols(const TString &structName,
+ const TString &structAPIName,
+ const unsigned int arrayOfStructsSize,
+ TVector<TIntermSymbol *> *outputSymbols,
+ TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const;
+
+ bool equals(const TStructure &other) const;
+
+ void setUniqueId(int uniqueId)
+ {
+ mUniqueId = uniqueId;
+ }
+
+ int uniqueId() const
+ {
+ ASSERT(mUniqueId != 0);
+ return mUniqueId;
+ }
+
+ void setAtGlobalScope(bool atGlobalScope)
+ {
+ mAtGlobalScope = atGlobalScope;
+ }
+
+ bool atGlobalScope() const
+ {
+ return mAtGlobalScope;
+ }
+
+ const TString &mangledName() const
+ {
+ if (mMangledName.empty())
+ mMangledName = buildMangledName("struct-");
+ return mMangledName;
+ }
+
+ private:
+ // 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 TString &name)
+ {
+ TString *mutableName = const_cast<TString *>(mName);
+ *mutableName = name;
+ }
+
+ int calculateDeepestNesting() const;
+
+ mutable int mDeepestNesting;
+ int mUniqueId;
+ bool mAtGlobalScope;
+};
+
+class TInterfaceBlock : public TFieldListCollection
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName,
+ int arraySize, const TLayoutQualifier &layoutQualifier)
+ : TFieldListCollection(name, fields),
+ mInstanceName(instanceName),
+ mArraySize(arraySize),
+ mBlockStorage(layoutQualifier.blockStorage),
+ mMatrixPacking(layoutQualifier.matrixPacking)
+ {
+ }
+
+ const TString &instanceName() const
+ {
+ return *mInstanceName;
+ }
+ bool hasInstanceName() const
+ {
+ return mInstanceName != NULL;
+ }
+ bool isArray() const
+ {
+ return mArraySize > 0;
+ }
+ int arraySize() const
+ {
+ return mArraySize;
+ }
+ TLayoutBlockStorage blockStorage() const
+ {
+ return mBlockStorage;
+ }
+ TLayoutMatrixPacking matrixPacking() const
+ {
+ return mMatrixPacking;
+ }
+ const TString &mangledName() const
+ {
+ if (mMangledName.empty())
+ mMangledName = buildMangledName("iblock-");
+ return mMangledName;
+ }
+
+ private:
+ const TString *mInstanceName; // for interface block instance names
+ int mArraySize; // 0 if not an array
+ TLayoutBlockStorage mBlockStorage;
+ TLayoutMatrixPacking mMatrixPacking;
+};
+
+//
+// Base class for things that have a type.
+//
+class TType
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TType()
+ : type(EbtVoid), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(0), secondarySize(0), array(false), arraySize(0),
+ interfaceBlock(nullptr), structure(nullptr)
+ {
+ }
+ explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1)
+ : type(t),
+ precision(EbpUndefined),
+ qualifier(EvqGlobal),
+ invariant(false),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(ps),
+ secondarySize(ss),
+ array(false),
+ arraySize(0),
+ interfaceBlock(0),
+ structure(0)
+ {
+ }
+ TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary,
+ unsigned char ps = 1, unsigned char ss = 1, bool a = false)
+ : type(t), precision(p), qualifier(q), invariant(false),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(ps), secondarySize(ss), array(a), arraySize(0),
+ interfaceBlock(0), structure(0)
+ {
+ }
+ explicit TType(const TPublicType &p);
+ explicit TType(TStructure *userDef, TPrecision p = EbpUndefined)
+ : type(EbtStruct),
+ precision(p),
+ qualifier(EvqTemporary),
+ invariant(false),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(1),
+ secondarySize(1),
+ array(false),
+ arraySize(0),
+ interfaceBlock(0),
+ structure(userDef)
+ {
+ }
+ TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
+ TLayoutQualifier layoutQualifierIn, int arraySizeIn)
+ : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
+ invariant(false), layoutQualifier(layoutQualifierIn),
+ primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn),
+ interfaceBlock(interfaceBlockIn), structure(0)
+ {
+ }
+
+ TType(const TType &) = default;
+ TType &operator=(const TType &) = default;
+
+ TBasicType getBasicType() const
+ {
+ return type;
+ }
+ void setBasicType(TBasicType t)
+ {
+ if (type != t)
+ {
+ type = t;
+ invalidateMangledName();
+ }
+ }
+
+ TPrecision getPrecision() const
+ {
+ return precision;
+ }
+ void setPrecision(TPrecision p)
+ {
+ precision = p;
+ }
+
+ TQualifier getQualifier() const
+ {
+ return qualifier;
+ }
+ void setQualifier(TQualifier q)
+ {
+ qualifier = q;
+ }
+
+ bool isInvariant() const
+ {
+ return invariant;
+ }
+
+ void setInvariant(bool i) { invariant = i; }
+
+ 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)
+ {
+ if (primarySize != ps)
+ {
+ primarySize = ps;
+ invalidateMangledName();
+ }
+ }
+ void setSecondarySize(unsigned char ss)
+ {
+ if (secondarySize != ss)
+ {
+ secondarySize = ss;
+ invalidateMangledName();
+ }
+ }
+
+ // Full size of single instance of type
+ size_t getObjectSize() const;
+
+ bool isMatrix() const
+ {
+ return primarySize > 1 && secondarySize > 1;
+ }
+ bool isNonSquareMatrix() const
+ {
+ return isMatrix() && primarySize != secondarySize;
+ }
+ bool isArray() const
+ {
+ return array;
+ }
+ bool isUnsizedArray() const
+ {
+ return array && arraySize == 0u;
+ }
+ unsigned int getArraySize() const { return arraySize; }
+ void setArraySize(unsigned int s)
+ {
+ if (!array || arraySize != s)
+ {
+ array = true;
+ arraySize = s;
+ invalidateMangledName();
+ }
+ }
+ void clearArrayness()
+ {
+ if (array)
+ {
+ array = false;
+ arraySize = 0u;
+ invalidateMangledName();
+ }
+ }
+
+ TInterfaceBlock *getInterfaceBlock() const
+ {
+ return interfaceBlock;
+ }
+ void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn)
+ {
+ if (interfaceBlock != interfaceBlockIn)
+ {
+ interfaceBlock = interfaceBlockIn;
+ invalidateMangledName();
+ }
+ }
+ bool isInterfaceBlock() const
+ {
+ return type == EbtInterfaceBlock;
+ }
+
+ bool isVector() const
+ {
+ return primarySize > 1 && secondarySize == 1;
+ }
+ bool isScalar() const
+ {
+ return primarySize == 1 && secondarySize == 1 && !structure;
+ }
+ bool isScalarInt() const
+ {
+ return isScalar() && (type == EbtInt || type == EbtUInt);
+ }
+
+ TStructure *getStruct() const
+ {
+ return structure;
+ }
+ void setStruct(TStructure *s)
+ {
+ if (structure != s)
+ {
+ structure = s;
+ invalidateMangledName();
+ }
+ }
+
+ const TString &getMangledName() const
+ {
+ if (mangled.empty())
+ {
+ mangled = buildMangledName();
+ mangled += ';';
+ }
+
+ return mangled;
+ }
+
+ bool sameElementType(const TType &right) const
+ {
+ return type == right.type &&
+ primarySize == right.primarySize &&
+ secondarySize == right.secondarySize &&
+ structure == right.structure;
+ }
+ bool operator==(const TType &right) const
+ {
+ return type == right.type &&
+ primarySize == right.primarySize &&
+ secondarySize == right.secondarySize &&
+ array == right.array && (!array || arraySize == right.arraySize) &&
+ structure == right.structure;
+ // 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;
+ if (array != right.array)
+ return array < right.array;
+ if (arraySize != right.arraySize)
+ return arraySize < right.arraySize;
+ if (structure != right.structure)
+ return structure < right.structure;
+
+ return false;
+ }
+
+ const char *getBasicString() const
+ {
+ return ::getBasicString(type);
+ }
+
+ const char *getPrecisionString() const
+ {
+ return ::getPrecisionString(precision);
+ }
+ const char *getQualifierString() const
+ {
+ return ::getQualifierString(qualifier);
+ }
+
+ const char *getBuiltInTypeNameString() const;
+
+ TString getCompleteString() 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
+ {
+ return structure ? structure->deepestNesting() : 0;
+ }
+
+ bool isStructureContainingArrays() const
+ {
+ return structure ? structure->containsArrays() : false;
+ }
+
+ bool isStructureContainingType(TBasicType t) const
+ {
+ return structure ? structure->containsType(t) : false;
+ }
+
+ bool isStructureContainingSamplers() const
+ {
+ return structure ? structure->containsSamplers() : false;
+ }
+
+ void createSamplerSymbols(const TString &structName,
+ const TString &structAPIName,
+ const unsigned int arrayOfStructsSize,
+ TVector<TIntermSymbol *> *outputSymbols,
+ TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
+ {
+ ASSERT(structure != nullptr && structure->containsSamplers());
+ structure->createSamplerSymbols(structName, structAPIName, arrayOfStructsSize,
+ outputSymbols, outputSymbolsToAPINames);
+ }
+
+ // Initializes all lazily-initialized members.
+ void realize()
+ {
+ getMangledName();
+ }
+
+ private:
+ void invalidateMangledName() { mangled = ""; }
+ TString buildMangledName() const;
+ size_t getStructSize() const;
+
+ TBasicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ bool invariant;
+ TLayoutQualifier layoutQualifier;
+ unsigned char primarySize; // size of vector or cols matrix
+ unsigned char secondarySize; // rows of a matrix
+ bool array;
+ unsigned int arraySize;
+
+ // 0 unless this is an interface block, or interface block member variable
+ TInterfaceBlock *interfaceBlock;
+
+ // 0 unless this is a struct
+ TStructure *structure;
+
+ mutable TString mangled;
+};
+
+// 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
+ TType *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 bt, const TSourceLoc &ln)
+ {
+ type = bt;
+ primarySize = 1;
+ secondarySize = 1;
+ userDef = nullptr;
+ line = ln;
+ isStructSpecifier = false;
+ }
+
+ 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
+{
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ bool invariant;
+ TPrecision precision;
+ bool array;
+ int arraySize;
+
+ void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q)
+ {
+ typeSpecifierNonArray = typeSpecifier;
+ layoutQualifier = TLayoutQualifier::create();
+ qualifier = q;
+ invariant = false;
+ precision = EbpUndefined;
+ array = false;
+ arraySize = 0;
+ }
+
+ 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; }
+ void initializeSizeForScalarTypes()
+ {
+ typeSpecifierNonArray.primarySize = 1;
+ typeSpecifierNonArray.secondarySize = 1;
+ }
+
+ const TType *getUserDef() const { return typeSpecifierNonArray.userDef; }
+ const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
+
+ bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
+
+ bool isStructureContainingArrays() const
+ {
+ if (!typeSpecifierNonArray.userDef)
+ {
+ return false;
+ }
+
+ return typeSpecifierNonArray.userDef->isStructureContainingArrays();
+ }
+
+ bool isStructureContainingType(TBasicType t) const
+ {
+ if (!typeSpecifierNonArray.userDef)
+ {
+ return false;
+ }
+
+ return typeSpecifierNonArray.userDef->isStructureContainingType(t);
+ }
+
+ bool isUnsizedArray() const { return array && arraySize == 0; }
+ void setArraySize(int s)
+ {
+ array = true;
+ arraySize = s;
+ }
+ void clearArrayness()
+ {
+ array = false;
+ arraySize = 0;
+ }
+
+ bool isAggregate() const
+ {
+ return array || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector();
+ }
+};
+
+#endif // COMPILER_TRANSLATOR_TYPES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.cpp
new file mode 100644
index 000000000..e57681eda
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.cpp
@@ -0,0 +1,54 @@
+//
+// 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/UnfoldShortCircuitAST.h"
+
+namespace
+{
+
+// "x || y" is equivalent to "x ? true : y".
+TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
+{
+ TConstantUnion *u = new TConstantUnion;
+ u->setBConst(true);
+ TIntermConstantUnion *trueNode = new TIntermConstantUnion(
+ u, TType(EbtBool, EbpUndefined, EvqConst, 1));
+ return new TIntermTernary(x, trueNode, y);
+}
+
+// "x && y" is equivalent to "x ? y : false".
+TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
+{
+ TConstantUnion *u = new TConstantUnion;
+ u->setBConst(false);
+ TIntermConstantUnion *falseNode = new TIntermConstantUnion(
+ u, TType(EbtBool, EbpUndefined, EvqConst, 1));
+ return new TIntermTernary(x, y, falseNode);
+}
+
+} // namespace anonymous
+
+bool UnfoldShortCircuitAST::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(node, replacement, OriginalNode::IS_DROPPED);
+ }
+ return true;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.h b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.h
new file mode 100644
index 000000000..b92a4e915
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitAST.h
@@ -0,0 +1,31 @@
+//
+// 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_UNFOLDSHORTCIRCUITAST_H_
+#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_
+
+#include "common/angleutils.h"
+#include "compiler/translator/IntermNode.h"
+
+// 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 UnfoldShortCircuitAST : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitAST()
+ : TIntermTraverser(true, false, false)
+ {
+ }
+
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+};
+
+#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.cpp
new file mode 100644
index 000000000..712f59aaf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.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.
+//
+// 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/UnfoldShortCircuitToIf.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+
+namespace
+{
+
+// Traverser that unfolds one short-circuiting operation at a time.
+class UnfoldShortCircuitTraverser : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitTraverser();
+
+ 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()
+ : TIntermTraverser(true, false, true),
+ 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;
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
+
+ ASSERT(node->getLeft()->getType() == boolType);
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+
+ TIntermBlock *assignRightBlock = new TIntermBlock();
+ ASSERT(node->getRight()->getType() == boolType);
+ assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
+
+ TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType));
+ TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(node, createTempSymbol(boolType), 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;
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
+
+ ASSERT(node->getLeft()->getType() == boolType);
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+
+ TIntermBlock *assignRightBlock = new TIntermBlock();
+ ASSERT(node->getRight()->getType() == boolType);
+ assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
+
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(createTempSymbol(boolType), assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(node, createTempSymbol(boolType), 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;
+
+ TIntermSymbol *tempSymbol = createTempSymbol(node->getType());
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ tempDeclaration->getSequence()->push_back(tempSymbol);
+ insertions.push_back(tempDeclaration);
+
+ TIntermBlock *trueBlock = new TIntermBlock();
+ TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
+ trueBlock->getSequence()->push_back(trueAssignment);
+
+ TIntermBlock *falseBlock = new TIntermBlock();
+ TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
+ falseBlock->getSequence()->push_back(falseAssignment);
+
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
+ queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED);
+
+ return false;
+}
+
+void UnfoldShortCircuitTraverser::nextIteration()
+{
+ mFoundShortCircuit = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ UnfoldShortCircuitTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // 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());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.h b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.h
new file mode 100644
index 000000000..0fe37b714
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UnfoldShortCircuitToIf.h
@@ -0,0 +1,18 @@
+//
+// 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_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_
+
+class TIntermNode;
+
+void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.cpp
new file mode 100644
index 000000000..3a85c60fc
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.cpp
@@ -0,0 +1,473 @@
+//
+// 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.
+//
+// UniformHLSL.cpp:
+// Methods for GLSL to HLSL translation for uniforms and interface blocks.
+//
+
+#include "compiler/translator/UniformHLSL.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+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);
+ 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";
+}
+
+UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector<Uniform> &uniforms)
+ : mUniformRegister(0),
+ mInterfaceBlockRegister(0),
+ mSamplerRegister(0),
+ mStructureHLSL(structureHLSL),
+ mOutputType(outputType),
+ mUniforms(uniforms)
+{}
+
+void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
+{
+ mUniformRegister = registerCount;
+}
+
+void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount)
+{
+ mInterfaceBlockRegister = registerCount;
+}
+
+const Uniform *UniformHLSL::findUniformByName(const TString &name) const
+{
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+ {
+ if (mUniforms[uniformIndex].name == name.c_str())
+ {
+ return &mUniforms[uniformIndex];
+ }
+ }
+
+ return nullptr;
+}
+
+unsigned int UniformHLSL::assignUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount)
+{
+ unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
+
+ const Uniform *uniform = findUniformByName(name);
+ ASSERT(uniform);
+
+ mUniformRegisterMap[uniform->name] = registerIndex;
+
+ unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
+
+ if (gl::IsSamplerType(uniform->type))
+ {
+ mSamplerRegister += registerCount;
+ }
+ else
+ {
+ mUniformRegister += registerCount;
+ }
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+unsigned int UniformHLSL::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 = mSamplerRegister;
+ mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
+ unsigned int registerCount = type.isArray() ? type.getArraySize() : 1u;
+ mSamplerRegister += registerCount;
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+void UniformHLSL::outputHLSLSamplerUniformGroup(
+ TInfoSinkBase &out,
+ const HLSLTextureSamplerGroup textureGroup,
+ const TVector<const TIntermSymbol *> &group,
+ const TMap<const TIntermSymbol *, TString> &samplerInStructSymbolsToAPINames,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+ unsigned int groupRegisterCount = 0;
+ for (const TIntermSymbol *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const TString &name = uniform->getSymbol();
+ 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 " << DecorateIfNeeded(uniform->getName()) << ArrayString(type)
+ << " = {";
+ for (unsigned int i = 0u; i < type.getArraySize(); ++i)
+ {
+ if (i > 0u)
+ out << ", ";
+ out << (samplerArrayIndex + i);
+ }
+ out << "};\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateIfNeeded(uniform->getName()) << " = "
+ << 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 UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
+ const TType &type,
+ const TName &name,
+ const unsigned int registerIndex)
+{
+ out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
+ << DecorateUniform(name, type) << ArrayString(type) << " : register(s" << str(registerIndex)
+ << ");\n";
+ out << "uniform " << TextureString(type.getBasicType()) << " texture_"
+ << DecorateUniform(name, type) << ArrayString(type) << " : register(t" << str(registerIndex)
+ << ");\n";
+}
+
+void UniformHLSL::outputUniform(TInfoSinkBase &out,
+ const TType &type,
+ const TName &name,
+ 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->name().empty())
+ ? QualifiedStructNameString(*structure, false, false)
+ : TypeString(type));
+
+ const TString &registerString =
+ TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
+
+ out << "uniform " << typeName << " ";
+
+ out << DecorateUniform(name, type);
+
+ out << ArrayString(type) << " : " << registerString << ";\n";
+}
+
+void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedSymbols &referencedUniforms)
+{
+ 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 TIntermSymbol *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
+ TMap<const TIntermSymbol *, TString> samplerInStructSymbolsToAPINames;
+ for (auto &uniformIt : referencedUniforms)
+ {
+ // Output regular uniforms. Group sampler uniforms by type.
+ const TIntermSymbol &uniform = *uniformIt.second;
+ const TType &type = uniform.getType();
+ const TName &name = uniform.getName();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ HLSLTextureSamplerGroup group = TextureGroup(type.getBasicType());
+ groupedSamplerUniforms[group].push_back(&uniform);
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
+ outputHLSL4_0_FL9_3Sampler(out, type, name, registerIndex);
+ }
+ else
+ {
+ if (type.isStructureContainingSamplers())
+ {
+ TVector<TIntermSymbol *> samplerSymbols;
+ TMap<TIntermSymbol *, TString> symbolsToAPINames;
+ unsigned int arrayOfStructsSize = type.isArray() ? type.getArraySize() : 0u;
+ type.createSamplerSymbols("angle_" + name.getString(), name.getString(),
+ arrayOfStructsSize, &samplerSymbols, &symbolsToAPINames);
+ for (TIntermSymbol *sampler : samplerSymbols)
+ {
+ const TType &samplerType = sampler->getType();
+
+ // Will use angle_ prefix instead of regular prefix.
+ sampler->setInternal(true);
+ const TName &samplerName = sampler->getName();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ HLSLTextureSamplerGroup 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, samplerName, registerIndex);
+ }
+ else
+ {
+ ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
+ unsigned int registerIndex = assignSamplerInStructUniformRegister(
+ samplerType, symbolsToAPINames[sampler], nullptr);
+ outputUniform(out, samplerType, samplerName, registerIndex);
+ }
+ }
+ }
+ unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
+ outputUniform(out, type, name, registerIndex);
+ }
+ }
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ unsigned int groupTextureRegisterIndex = 0;
+ // 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, HLSLTextureSamplerGroup(groupId), groupedSamplerUniforms[groupId],
+ samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
+ }
+ }
+}
+
+void UniformHLSL::samplerMetadataUniforms(TInfoSinkBase &out, const char *reg)
+{
+ // If mSamplerRegister is 0 the shader doesn't use any textures.
+ if (mSamplerRegister > 0)
+ {
+ out << " struct SamplerMetadata\n"
+ " {\n"
+ " int baseLevel;\n"
+ " int internalFormatBits;\n"
+ " int wrapModes;\n"
+ " int padding;\n"
+ " };\n"
+ " SamplerMetadata samplerMetadata["
+ << mSamplerRegister << "] : packoffset(" << reg << ");\n";
+ }
+}
+
+TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
+{
+ TString interfaceBlocks;
+
+ for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin();
+ interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++)
+ {
+ const TType &nodeType = interfaceBlockIt->second->getType();
+ const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
+
+ unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
+ unsigned int activeRegister = mInterfaceBlockRegister;
+
+ mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister;
+ mInterfaceBlockRegister += std::max(1u, arraySize);
+
+ // FIXME: interface block field names
+
+ if (interfaceBlock.hasInstanceName())
+ {
+ interfaceBlocks += interfaceBlockStructString(interfaceBlock);
+ }
+
+ if (arraySize > 0)
+ {
+ for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
+ {
+ interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex);
+ }
+ }
+ else
+ {
+ interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX);
+ }
+ }
+
+ return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks));
+}
+
+TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
+{
+ const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
+ const TString &blockName = interfaceBlock.name() + arrayIndexString;
+ TString hlsl;
+
+ hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
+ "{\n";
+
+ if (interfaceBlock.hasInstanceName())
+ {
+ hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
+ interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
+ }
+ else
+ {
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+ hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage);
+ }
+
+ hlsl += "};\n\n";
+
+ return hlsl;
+}
+
+TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
+{
+ if (!interfaceBlock.hasInstanceName())
+ {
+ return "";
+ }
+ else if (interfaceBlock.isArray())
+ {
+ return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
+ }
+ else
+ {
+ return Decorate(interfaceBlock.instanceName());
+ }
+}
+
+TString UniformHLSL::interfaceBlockMembersString(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) + ";\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 UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
+{
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+
+ return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n"
+ "{\n" +
+ interfaceBlockMembersString(interfaceBlock, blockStorage) +
+ "};\n\n";
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.h
new file mode 100644
index 000000000..c01b90fe0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UniformHLSL.h
@@ -0,0 +1,92 @@
+//
+// 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.
+//
+// UniformHLSL.h:
+// Methods for GLSL to HLSL translation for uniforms and interface blocks.
+//
+
+#ifndef COMPILER_TRANSLATOR_UNIFORMHLSL_H_
+#define COMPILER_TRANSLATOR_UNIFORMHLSL_H_
+
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+class StructureHLSL;
+
+class UniformHLSL : angle::NonCopyable
+{
+ public:
+ UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector<Uniform> &uniforms);
+
+ void reserveUniformRegisters(unsigned int registerCount);
+ void reserveInterfaceBlockRegisters(unsigned int registerCount);
+ void uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedSymbols &referencedUniforms);
+
+ // Must be called after uniformsHeader
+ void samplerMetadataUniforms(TInfoSinkBase &out, const char *reg);
+
+ TString interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks);
+
+ // Used for direct index references
+ static TString interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex);
+
+ const std::map<std::string, unsigned int> &getInterfaceBlockRegisterMap() const
+ {
+ return mInterfaceBlockRegisterMap;
+ }
+ const std::map<std::string, unsigned int> &getUniformRegisterMap() const
+ {
+ return mUniformRegisterMap;
+ }
+
+ private:
+ TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex);
+ TString interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage);
+ TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock);
+ const Uniform *findUniformByName(const TString &name) const;
+
+ void outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
+ const TType &type,
+ const TName &name,
+ const unsigned int registerIndex);
+
+ void outputUniform(TInfoSinkBase &out,
+ const TType &type,
+ const TName &name,
+ const unsigned int registerIndex);
+
+ // Returns the uniform's register index
+ unsigned int assignUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount);
+ unsigned int assignSamplerInStructUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount);
+
+ void outputHLSLSamplerUniformGroup(
+ TInfoSinkBase &out,
+ const HLSLTextureSamplerGroup textureGroup,
+ const TVector<const TIntermSymbol *> &group,
+ const TMap<const TIntermSymbol *, TString> &samplerInStructSymbolsToAPINames,
+ unsigned int *groupTextureRegisterIndex);
+
+ unsigned int mUniformRegister;
+ unsigned int mInterfaceBlockRegister;
+ unsigned int mSamplerRegister;
+ StructureHLSL *mStructureHLSL;
+ ShShaderOutput mOutputType;
+
+ const std::vector<Uniform> &mUniforms;
+ std::map<std::string, unsigned int> mInterfaceBlockRegisterMap;
+ std::map<std::string, unsigned int> mUniformRegisterMap;
+};
+
+}
+
+#endif // COMPILER_TRANSLATOR_UNIFORMHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.cpp
new file mode 100644
index 000000000..2a1a812e2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.cpp
@@ -0,0 +1,153 @@
+//
+// 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/UseInterfaceBlockFields.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class UseUniformBlockMembers : public TIntermTraverser
+{
+ public:
+ UseUniformBlockMembers(const InterfaceBlockList &blocks)
+ : TIntermTraverser(true, false, false), mBlocks(blocks), mCodeInserted(false)
+ {
+ }
+
+ protected:
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override { return !mCodeInserted; }
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+
+ private:
+ void insertUseCode(TIntermSequence *sequence);
+ void AddFieldUseStatements(const ShaderVariable &var, TIntermSequence *sequence);
+
+ const InterfaceBlockList &mBlocks;
+ bool mCodeInserted;
+};
+
+bool UseUniformBlockMembers::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ ASSERT(visit == PreVisit);
+ if (node->getFunctionSymbolInfo()->isMain())
+ {
+ TIntermBlock *body = node->getBody();
+ ASSERT(body);
+ insertUseCode(body->getSequence());
+ mCodeInserted = true;
+ return false;
+ }
+ return !mCodeInserted;
+}
+
+void UseUniformBlockMembers::AddFieldUseStatements(const ShaderVariable &var,
+ TIntermSequence *sequence)
+{
+ TString name = TString(var.name.c_str());
+ TType type = GetShaderVariableType(var);
+
+ if (var.isArray())
+ {
+ size_t pos = name.find_last_of('[');
+ if (pos != TString::npos)
+ {
+ name = name.substr(0, pos);
+ }
+ TType elementType = type;
+ elementType.clearArrayness();
+
+ TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+ for (unsigned int i = 0; i < var.arraySize; ++i)
+ {
+ TIntermBinary *element =
+ new TIntermBinary(EOpIndexDirect, arraySymbol, TIntermTyped::CreateIndexNode(i));
+
+ sequence->insert(sequence->begin(), element);
+ }
+ }
+ else if (var.isStruct())
+ {
+ TIntermSymbol *structSymbol = new TIntermSymbol(0, name, type);
+ for (unsigned int i = 0; i < var.fields.size(); ++i)
+ {
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, structSymbol,
+ TIntermTyped::CreateIndexNode(i));
+
+ sequence->insert(sequence->begin(), element);
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
+
+ sequence->insert(sequence->begin(), symbol);
+ }
+}
+
+void UseUniformBlockMembers::insertUseCode(TIntermSequence *sequence)
+{
+ for (const auto &block : mBlocks)
+ {
+ if (block.instanceName.empty())
+ {
+ for (const auto &var : block.fields)
+ {
+ AddFieldUseStatements(var, sequence);
+ }
+ }
+ else if (block.arraySize > 0)
+ {
+ TType type = GetInterfaceBlockType(block);
+ TString name = TString(block.instanceName.c_str());
+ TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+ for (unsigned int i = 0; i < block.arraySize; ++i)
+ {
+ TIntermBinary *instanceSymbol = new TIntermBinary(EOpIndexDirect, arraySymbol,
+ TIntermTyped::CreateIndexNode(i));
+ for (unsigned int j = 0; j < block.fields.size(); ++j)
+ {
+ TIntermBinary *element =
+ new TIntermBinary(EOpIndexDirectInterfaceBlock, instanceSymbol,
+ TIntermTyped::CreateIndexNode(j));
+ sequence->insert(sequence->begin(), element);
+ }
+ }
+ }
+ else
+ {
+ TType type = GetInterfaceBlockType(block);
+ TString name = TString(block.instanceName.c_str());
+ TIntermSymbol *blockSymbol = new TIntermSymbol(0, name, type);
+ for (unsigned int i = 0; i < block.fields.size(); ++i)
+ {
+ TIntermBinary *element = new TIntermBinary(
+ EOpIndexDirectInterfaceBlock, blockSymbol, TIntermTyped::CreateIndexNode(i));
+
+ sequence->insert(sequence->begin(), element);
+ }
+ }
+ }
+}
+
+} // namespace anonymous
+
+void UseInterfaceBlockFields(TIntermNode *root, const InterfaceBlockList &blocks)
+{
+ UseUniformBlockMembers useUniformBlock(blocks);
+ root->traverse(&useUniformBlock);
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.h b/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.h
new file mode 100644
index 000000000..024bfd4b1
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UseInterfaceBlockFields.h
@@ -0,0 +1,25 @@
+//
+// 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_USEINTERFACEBLOCKFIELDS_H_
+#define COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+class TIntermNode;
+namespace sh
+{
+
+using InterfaceBlockList = std::vector<sh::InterfaceBlock>;
+
+void UseInterfaceBlockFields(TIntermNode *root, const InterfaceBlockList &blocks);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.cpp
new file mode 100644
index 000000000..221d5d9b5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.cpp
@@ -0,0 +1,414 @@
+//
+// 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"
+
+namespace sh
+{
+
+TString SamplerString(const TBasicType type)
+{
+ if (IsShadowSampler(type))
+ {
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+TString SamplerString(HLSLTextureSamplerGroup type)
+{
+ if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END)
+ {
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+HLSLTextureSamplerGroup TextureGroup(const TBasicType type)
+{
+ 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 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 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 EbtSampler2DShadow:
+ return HLSL_TEXTURE_2D_COMPARISON;
+ case EbtSamplerCubeShadow:
+ return HLSL_TEXTURE_CUBE_COMPARISON;
+ case EbtSampler2DArrayShadow:
+ return HLSL_TEXTURE_2D_ARRAY_COMPARISON;
+ default:
+ UNREACHABLE();
+ }
+ return HLSL_TEXTURE_UNKNOWN;
+}
+
+TString TextureString(const HLSLTextureSamplerGroup type)
+{
+ switch (type)
+ {
+ case HLSL_TEXTURE_2D:
+ return "Texture2D";
+ case HLSL_TEXTURE_CUBE:
+ return "TextureCube";
+ case HLSL_TEXTURE_2D_ARRAY:
+ return "Texture2DArray";
+ case HLSL_TEXTURE_3D:
+ return "Texture3D";
+ 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_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_COMPARISON:
+ return "Texture2D";
+ case HLSL_TEXTURE_CUBE_COMPARISON:
+ return "TextureCube";
+ case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
+ return "Texture2DArray";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown texture type>";
+}
+
+TString TextureString(const TBasicType type)
+{
+ return TextureString(TextureGroup(type));
+}
+
+TString TextureGroupSuffix(const HLSLTextureSamplerGroup 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_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_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_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>";
+}
+
+TString TextureGroupSuffix(const TBasicType type)
+{
+ return TextureGroupSuffix(TextureGroup(type));
+}
+
+TString TextureTypeSuffix(const TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISamplerCube:
+ return "Cube_int4_";
+ case EbtUSamplerCube:
+ return "Cube_uint4_";
+ case EbtSamplerExternalOES:
+ return "_External";
+ default:
+ // All other types are identified by their group suffix
+ return TextureGroupSuffix(type);
+ }
+}
+
+TString DecorateUniform(const TName &name, const TType &type)
+{
+ return DecorateIfNeeded(name);
+}
+
+TString DecorateField(const TString &string, const TStructure &structure)
+{
+ if (structure.name().compare(0, 3, "gl_") != 0)
+ {
+ return Decorate(string);
+ }
+
+ return string;
+}
+
+TString DecoratePrivate(const TString &privateText)
+{
+ return "dx_" + privateText;
+}
+
+TString Decorate(const TString &string)
+{
+ if (string.compare(0, 3, "gl_") != 0)
+ {
+ return "_" + string;
+ }
+
+ return string;
+}
+
+TString DecorateIfNeeded(const TName &name)
+{
+ if (name.isInternal())
+ {
+ return name.getString();
+ }
+ else
+ {
+ return Decorate(name.getString());
+ }
+}
+
+TString DecorateFunctionIfNeeded(const TName &name)
+{
+ if (name.isInternal())
+ {
+ return TFunction::unmangleName(name.getString());
+ }
+ else
+ {
+ return Decorate(TFunction::unmangleName(name.getString()));
+ }
+}
+
+TString TypeString(const TType &type)
+{
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ const TString& typeName = structure->name();
+ if (typeName != "")
+ {
+ 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";
+ default:
+ break;
+ }
+ }
+
+ UNREACHABLE();
+ return "<unknown type>";
+}
+
+TString StructNameString(const TStructure &structure)
+{
+ if (structure.name().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()) + "_" + structure.name();
+}
+
+TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking,
+ bool useStd140Packing)
+{
+ if (structure.name() == "")
+ {
+ 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);
+}
+
+TString 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 "";
+}
+
+TString 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 TIntermSequence *parameters)
+{
+ TString disambiguatingString;
+ for (auto parameter : *parameters)
+ {
+ const TType &paramType = parameter->getAsTyped()->getType();
+ // Disambiguation is needed for float2x2 and float4 parameters. These are the only parameter
+ // types that HLSL thinks are identical. float2x3 and float3x2 are different types, for
+ // example. Other parameter types are not added to function names to avoid making function
+ // names longer.
+ if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat)
+ {
+ disambiguatingString += "_" + TypeString(paramType);
+ }
+ }
+ return disambiguatingString;
+}
+
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.h
new file mode 100644
index 000000000..748b3513e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/UtilsHLSL.h
@@ -0,0 +1,81 @@
+//
+// 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"
+
+class TName;
+
+namespace sh
+{
+
+// Unique combinations of HLSL Texture type and HLSL Sampler type.
+enum HLSLTextureSamplerGroup
+{
+ // Regular samplers
+ HLSL_TEXTURE_2D,
+ HLSL_TEXTURE_MIN = HLSL_TEXTURE_2D,
+
+ HLSL_TEXTURE_CUBE,
+ HLSL_TEXTURE_2D_ARRAY,
+ HLSL_TEXTURE_3D,
+ HLSL_TEXTURE_2D_INT4,
+ HLSL_TEXTURE_3D_INT4,
+ HLSL_TEXTURE_2D_ARRAY_INT4,
+ HLSL_TEXTURE_2D_UINT4,
+ HLSL_TEXTURE_3D_UINT4,
+ HLSL_TEXTURE_2D_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
+};
+
+HLSLTextureSamplerGroup TextureGroup(const TBasicType type);
+TString TextureString(const HLSLTextureSamplerGroup type);
+TString TextureString(const TBasicType type);
+TString TextureGroupSuffix(const HLSLTextureSamplerGroup type);
+TString TextureGroupSuffix(const TBasicType type);
+TString TextureTypeSuffix(const TBasicType type);
+TString SamplerString(const TBasicType type);
+TString SamplerString(HLSLTextureSamplerGroup type);
+// Prepends an underscore to avoid naming clashes
+TString Decorate(const TString &string);
+TString DecorateIfNeeded(const TName &name);
+// Decorates and also unmangles the function name
+TString DecorateFunctionIfNeeded(const TName &name);
+TString DecorateUniform(const TName &name, const TType &type);
+TString DecorateField(const TString &string, const TStructure &structure);
+TString DecoratePrivate(const TString &privateText);
+TString TypeString(const TType &type);
+TString StructNameString(const TStructure &structure);
+TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking,
+ bool useStd140Packing);
+TString InterpolationString(TQualifier qualifier);
+TString QualifierString(TQualifier qualifier);
+// Parameters may need to be included in function names to disambiguate between overloaded
+// functions.
+TString DisambiguateFunctionName(const TIntermSequence *parameters);
+}
+
+#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.cpp
new file mode 100644
index 000000000..2461b6a43
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.cpp
@@ -0,0 +1,112 @@
+//
+// 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/ParseContext.h"
+
+namespace
+{
+
+class ValidateGlobalInitializerTraverser : public TIntermTraverser
+{
+ public:
+ ValidateGlobalInitializerTraverser(const TParseContext *context);
+
+ void visitSymbol(TIntermSymbol *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; }
+ bool issueWarning() const { return mIssueWarning; }
+
+ private:
+ const TParseContext *mContext;
+ bool mIsValid;
+ bool mIssueWarning;
+};
+
+void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
+{
+ const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
+ if (sym->isVariable())
+ {
+ // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
+ // Global initializers must be constant expressions.
+ const TVariable *var = static_cast<const TVariable *>(sym);
+ switch (var->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 (mContext->getShaderVersion() >= 300)
+ {
+ mIsValid = false;
+ }
+ else
+ {
+ mIssueWarning = true;
+ }
+ break;
+ default:
+ mIsValid = false;
+ }
+ }
+}
+
+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 EOpFunctionCall.
+ if (node->getOp() == EOpFunctionCall)
+ {
+ 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(const TParseContext *context)
+ : TIntermTraverser(true, false, false),
+ mContext(context),
+ mIsValid(true),
+ mIssueWarning(false)
+{
+}
+
+} // namespace
+
+bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
+{
+ ValidateGlobalInitializerTraverser validate(context);
+ initializer->traverse(&validate);
+ ASSERT(warning != nullptr);
+ *warning = validate.issueWarning();
+ return validate.isValid();
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.h
new file mode 100644
index 000000000..c3d2a47eb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateGlobalInitializer.h
@@ -0,0 +1,16 @@
+//
+// 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_
+
+class TIntermTyped;
+class TParseContext;
+
+// Returns true if the initializer is valid.
+bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning);
+
+#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.cpp
new file mode 100644
index 000000000..5dcfe69c5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.cpp
@@ -0,0 +1,498 @@
+//
+// 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 "compiler/translator/InfoSink.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/ParseContext.h"
+#include "angle_gl.h"
+
+namespace
+{
+
+// 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(TLoopStack& stack)
+ : TIntermTraverser(true, false, false),
+ mValid(true),
+ mLoopStack(stack)
+ {
+ }
+
+ // 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)
+ {
+ mValid = (symbol->getQualifier() == EvqConst) ||
+ (mLoopStack.findLoop(symbol));
+ }
+ }
+
+ private:
+ bool mValid;
+ TLoopStack& mLoopStack;
+};
+
+} // namespace anonymous
+
+ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
+ : TIntermTraverser(true, false, false),
+ mShaderType(shaderType),
+ mSink(sink),
+ mNumErrors(0),
+ mValidateIndexing(true),
+ mValidateInnerLoops(true)
+{
+}
+
+// static
+bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
+{
+ // The shader type doesn't matter in this case.
+ ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
+ validate.mValidateIndexing = false;
+ validate.mValidateInnerLoops = false;
+ if (!validate.validateLoopType(loop))
+ return false;
+ if (!validate.validateForLoopHeader(loop))
+ return false;
+ TIntermNode *body = loop->getBody();
+ if (body != nullptr)
+ {
+ validate.mLoopStack.push(loop);
+ body->traverse(&validate);
+ validate.mLoopStack.pop();
+ }
+ return (validate.mNumErrors == 0);
+}
+
+bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getLeft());
+
+ // Check indexing.
+ switch (node->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ if (mValidateIndexing)
+ validateIndexing(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getOperand());
+
+ return true;
+}
+
+bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
+{
+ switch (node->getOp()) {
+ case EOpFunctionCall:
+ validateFunctionCall(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
+{
+ if (!mValidateInnerLoops)
+ return true;
+
+ if (!validateLoopType(node))
+ return false;
+
+ if (!validateForLoopHeader(node))
+ return false;
+
+ TIntermNode *body = node->getBody();
+ if (body != NULL)
+ {
+ mLoopStack.push(node);
+ body->traverse(this);
+ mLoopStack.pop();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ValidateLimitations::error(TSourceLoc loc,
+ const char *reason, const char *token)
+{
+ if (mSink)
+ {
+ mSink->prefix(EPrefixError);
+ mSink->location(loc);
+ (*mSink) << "'" << token << "' : " << reason << "\n";
+ }
+ ++mNumErrors;
+}
+
+bool ValidateLimitations::withinLoopBody() const
+{
+ return !mLoopStack.empty();
+}
+
+bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
+{
+ return mLoopStack.findLoop(symbol) != NULL;
+}
+
+bool ValidateLimitations::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 ValidateLimitations::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 ValidateLimitations::validateForLoopInit(TIntermLoop *node)
+{
+ TIntermNode *init = node->getInit();
+ if (init == NULL)
+ {
+ error(node->getLine(), "Missing init declaration", "for");
+ return -1;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermAggregate *decl = init->getAsAggregate();
+ if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
+ {
+ 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 == NULL) || (declInit->getOp() != EOpInitialize))
+ {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == NULL)
+ {
+ 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->getSymbol().c_str());
+ return -1;
+ }
+
+ return symbol->getId();
+}
+
+bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
+ int indexSymbolId)
+{
+ TIntermNode *cond = node->getCondition();
+ if (cond == NULL)
+ {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary *binOp = cond->getAsBinaryNode();
+ if (binOp == NULL)
+ {
+ 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 == NULL)
+ {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->getId() != indexSymbolId)
+ {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ 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->getSymbol().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
+ int indexSymbolId)
+{
+ TIntermNode *expr = node->getExpression();
+ if (expr == NULL)
+ {
+ 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 ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol *symbol = NULL;
+ if (unOp != NULL)
+ {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ }
+ else if (binOp != NULL)
+ {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == NULL)
+ {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->getId() != indexSymbolId)
+ {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", GetOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != NULL)
+ {
+ if (!isConstExpr(binOp->getRight()))
+ {
+ error(binOp->getLine(),
+ "Loop index cannot be modified by non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
+{
+ ASSERT(node->getOp() == EOpFunctionCall);
+
+ // If not within loop body, there is nothing to check.
+ if (!withinLoopBody())
+ return true;
+
+ // List of param indices for which loop indices are used as argument.
+ typedef std::vector<size_t> ParamIndex;
+ ParamIndex pIndex;
+ TIntermSequence *params = node->getSequence();
+ for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
+ {
+ TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ pIndex.push_back(i);
+ }
+ // If none of the loop indices are used as arguments,
+ // there is nothing to check.
+ if (pIndex.empty())
+ return true;
+
+ bool valid = true;
+ TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
+ TSymbol *symbol = symbolTable.find(node->getFunctionSymbolInfo()->getName(),
+ GetGlobalParseContext()->getShaderVersion());
+ ASSERT(symbol && symbol->isFunction());
+ TFunction *function = static_cast<TFunction *>(symbol);
+ for (ParamIndex::const_iterator i = pIndex.begin();
+ i != pIndex.end(); ++i)
+ {
+ const TConstParameter &param = function->getParam(*i);
+ TQualifier qual = param.type->getQualifier();
+ if ((qual == EvqOut) || (qual == EvqInOut))
+ {
+ error((*params)[*i]->getLine(),
+ "Loop index cannot be used as argument to a function out or inout parameter",
+ (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+bool ValidateLimitations::validateOperation(TIntermOperator *node,
+ TIntermNode* operand)
+{
+ // Check if loop index is modified in the loop body.
+ if (!withinLoopBody() || !node->isAssignment())
+ return true;
+
+ TIntermSymbol *symbol = operand->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ symbol->getSymbol().c_str());
+ }
+ return true;
+}
+
+bool ValidateLimitations::isConstExpr(TIntermNode *node)
+{
+ ASSERT(node != nullptr);
+ return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
+}
+
+bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
+{
+ ASSERT(node != NULL);
+
+ ValidateConstIndexExpr validate(mLoopStack);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitations::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;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.h
new file mode 100644
index 000000000..666e38ff5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateLimitations.h
@@ -0,0 +1,63 @@
+//
+// 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"
+#include "compiler/translator/LoopInfo.h"
+
+class TInfoSinkBase;
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitations : public TIntermTraverser
+{
+ public:
+ ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink);
+
+ int numErrors() const { return mNumErrors; }
+
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitUnary(Visit, TIntermUnary *) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
+ bool visitLoop(Visit, TIntermLoop *) override;
+
+ static bool IsLimitedForLoop(TIntermLoop *node);
+
+ private:
+ void error(TSourceLoc loc, const char *reason, const char *token);
+
+ bool withinLoopBody() const;
+ 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 none of the loop indices is used as the argument to
+ // the given function out or inout parameter.
+ bool validateFunctionCall(TIntermAggregate *node);
+ bool validateOperation(TIntermOperator *node, TIntermNode *operand);
+
+ // 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;
+ TInfoSinkBase *mSink;
+ int mNumErrors;
+ TLoopStack mLoopStack;
+ bool mValidateIndexing;
+ bool mValidateInnerLoops;
+};
+
+#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.cpp
new file mode 100644
index 000000000..00b3c9b45
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.cpp
@@ -0,0 +1,35 @@
+//
+// 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"
+
+ValidateMaxParameters::ValidateMaxParameters(unsigned int maxParameters)
+ : TIntermTraverser(true, false, false), mMaxParameters(maxParameters), mValid(true)
+{
+}
+
+bool ValidateMaxParameters::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (!mValid)
+ {
+ return false;
+ }
+
+ if (node->getOp() == EOpParameters && node->getSequence()->size() > mMaxParameters)
+ {
+ mValid = false;
+ }
+
+ return mValid;
+}
+
+bool ValidateMaxParameters::validate(TIntermNode *root, unsigned int maxParameters)
+{
+ ValidateMaxParameters argsTraverser(maxParameters);
+ root->traverse(&argsTraverser);
+ return argsTraverser.mValid;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.h
new file mode 100644
index 000000000..87916afef
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateMaxParameters.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.
+//
+// ValidateMaxParameters checks if function definitions have more than a set number of parameters.
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
+#define COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
+
+#include "compiler/translator/IntermNode.h"
+
+class ValidateMaxParameters : public TIntermTraverser
+{
+ public:
+ // Returns false if maxParameters is exceeded.
+ static bool validate(TIntermNode *root, unsigned int maxParameters);
+
+ protected:
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ private:
+ ValidateMaxParameters(unsigned int maxParameters);
+
+ unsigned int mMaxParameters;
+ bool mValid;
+};
+
+#endif // COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.cpp
new file mode 100644
index 000000000..9f5f8f577
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.cpp
@@ -0,0 +1,108 @@
+//
+// 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.
+//
+
+#include "compiler/translator/ValidateOutputs.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/ParseContext.h"
+
+namespace
+{
+void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason)
+{
+ sink.prefix(EPrefixError);
+ sink.location(symbol.getLine());
+ sink << "'" << symbol.getSymbol() << "' : " << reason << "\n";
+ (*errorCount)++;
+}
+
+} // namespace
+
+ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers)
+ : TIntermTraverser(true, false, false),
+ mMaxDrawBuffers(maxDrawBuffers),
+ mAllowUnspecifiedOutputLocationResolution(
+ IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended"))
+{
+}
+
+void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
+{
+ TString name = symbol->getSymbol();
+ TQualifier qualifier = symbol->getQualifier();
+
+ if (mVisitedSymbols.count(name.c_str()) == 1)
+ return;
+
+ mVisitedSymbols.insert(name.c_str());
+
+ if (qualifier == EvqFragmentOut)
+ {
+ if (symbol->getType().getLayoutQualifier().location == -1)
+ {
+ mUnspecifiedLocationOutputs.push_back(symbol);
+ }
+ else
+ {
+ mOutputs.push_back(symbol);
+ }
+ }
+}
+
+int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
+{
+ OutputVector validOutputs(mMaxDrawBuffers);
+ int errorCount = 0;
+
+ for (const auto &symbol : mOutputs)
+ {
+ const TType &type = symbol->getType();
+ const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1u);
+ const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
+
+ ASSERT(type.getLayoutQualifier().location != -1);
+
+ if (location + elementCount <= validOutputs.size())
+ {
+ for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
+ {
+ const size_t offsetLocation = location + elementIndex;
+ if (validOutputs[offsetLocation])
+ {
+ std::stringstream strstr;
+ strstr << "conflicting output locations with previously defined output '"
+ << validOutputs[offsetLocation]->getSymbol() << "'";
+ error(&errorCount, sink, *symbol, strstr.str().c_str());
+ }
+ else
+ {
+ validOutputs[offsetLocation] = symbol;
+ }
+ }
+ }
+ else
+ {
+ if (elementCount > 0)
+ {
+ error(&errorCount, sink, *symbol,
+ elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
+ : "output location must be < MAX_DRAW_BUFFERS");
+ }
+ }
+ }
+
+ if (!mAllowUnspecifiedOutputLocationResolution &&
+ ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
+ mUnspecifiedLocationOutputs.size() > 1))
+ {
+ for (const auto &symbol : mUnspecifiedLocationOutputs)
+ {
+ error(&errorCount, sink, *symbol,
+ "must explicitly specify all locations when using multiple fragment outputs");
+ }
+ }
+ return errorCount;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.h
new file mode 100644
index 000000000..0122ca25f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateOutputs.h
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/IntermNode.h"
+
+#include <set>
+
+class TInfoSinkBase;
+
+class ValidateOutputs : public TIntermTraverser
+{
+ public:
+ ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
+
+ int validateAndCountErrors(TInfoSinkBase &sink) const;
+
+ void visitSymbol(TIntermSymbol *) override;
+
+ private:
+ int mMaxDrawBuffers;
+ bool mAllowUnspecifiedOutputLocationResolution;
+
+ typedef std::vector<TIntermSymbol *> OutputVector;
+ OutputVector mOutputs;
+ OutputVector mUnspecifiedLocationOutputs;
+ std::set<std::string> mVisitedSymbols;
+};
+
+#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.cpp
new file mode 100644
index 000000000..8fbd8325b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.cpp
@@ -0,0 +1,210 @@
+//
+// 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/ParseContext.h"
+
+bool ValidateSwitch::validate(TBasicType switchType,
+ TParseContext *context,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc)
+{
+ ValidateSwitch validate(switchType, context);
+ ASSERT(statementList);
+ statementList->traverse(&validate);
+ return validate.validateInternal(loc);
+}
+
+ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context)
+ : TIntermTraverser(true, false, true),
+ mSwitchType(switchType),
+ mContext(context),
+ mCaseTypeMismatch(false),
+ mFirstCaseFound(false),
+ mStatementBeforeCase(false),
+ mLastStatementWasCase(false),
+ mControlFlowDepth(0),
+ mCaseInsideControlFlow(false),
+ mDefaultCount(0),
+ mDuplicateCases(false)
+{}
+
+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::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::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)
+ {
+ mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr);
+ mCaseInsideControlFlow = true;
+ }
+ mFirstCaseFound = true;
+ mLastStatementWasCase = true;
+ if (!node->hasCondition())
+ {
+ ++mDefaultCount;
+ if (mDefaultCount > 1)
+ {
+ mContext->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)
+ {
+ mContext->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())
+ {
+ mContext->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())
+ {
+ mContext->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)
+ {
+ mContext->error(loc,
+ "statement before the first label", "switch");
+ }
+ if (mLastStatementWasCase)
+ {
+ mContext->error(loc,
+ "no statement between the last label and the end of the switch statement", "switch");
+ }
+ return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
+ !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.h b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.h
new file mode 100644
index 000000000..9c6dee212
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateSwitch.h
@@ -0,0 +1,55 @@
+//
+// 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/IntermNode.h"
+
+class TParseContext;
+
+class ValidateSwitch : public TIntermTraverser
+{
+ public:
+ // Check for errors and output messages any remaining errors on the context.
+ // Returns true if there are no errors.
+ static bool validate(TBasicType switchType,
+ TParseContext *context,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc);
+
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitUnary(Visit, TIntermUnary *) override;
+ bool visitTernary(Visit, TIntermTernary *) 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, TParseContext *context);
+
+ bool validateInternal(const TSourceLoc &loc);
+
+ TBasicType mSwitchType;
+ TParseContext *mContext;
+ 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;
+};
+
+#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.cpp
new file mode 100644
index 000000000..7e1e5cd82
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.cpp
@@ -0,0 +1,693 @@
+//
+// 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 "angle_gl.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/VariableInfo.h"
+#include "compiler/translator/util.h"
+#include "common/utilities.h"
+
+namespace sh
+{
+
+namespace
+{
+
+BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
+{
+ switch (blockStorage)
+ {
+ case EbsPacked: return BLOCKLAYOUT_PACKED;
+ case EbsShared: return BLOCKLAYOUT_SHARED;
+ case EbsStd140: return BLOCKLAYOUT_STANDARD;
+ default: UNREACHABLE(); return BLOCKLAYOUT_SHARED;
+ }
+}
+
+void ExpandUserDefinedVariable(const ShaderVariable &variable,
+ const std::string &name,
+ const std::string &mappedName,
+ bool markStaticUse,
+ 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,
+ mappedName + "." + field.mappedName,
+ markStaticUse,
+ expanded);
+ }
+}
+
+template <class VarT>
+VarT *FindVariable(const TString &name,
+ std::vector<VarT> *infoList)
+{
+ // TODO(zmo): optimize this function.
+ for (size_t ii = 0; ii < infoList->size(); ++ii)
+ {
+ if ((*infoList)[ii].name.c_str() == name)
+ return &((*infoList)[ii]);
+ }
+
+ return NULL;
+}
+
+}
+
+CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
+ std::vector<sh::OutputVariable> *outputVariables,
+ std::vector<sh::Uniform> *uniforms,
+ std::vector<sh::Varying> *varyings,
+ std::vector<sh::InterfaceBlock> *interfaceBlocks,
+ ShHashFunction64 hashFunction,
+ const TSymbolTable &symbolTable,
+ const TExtensionBehavior &extensionBehavior)
+ : TIntermTraverser(true, false, false),
+ mAttribs(attribs),
+ mOutputVariables(outputVariables),
+ mUniforms(uniforms),
+ mVaryings(varyings),
+ mInterfaceBlocks(interfaceBlocks),
+ mDepthRangeAdded(false),
+ mPointCoordAdded(false),
+ mFrontFacingAdded(false),
+ mFragCoordAdded(false),
+ mInstanceIDAdded(false),
+ mVertexIDAdded(false),
+ mPositionAdded(false),
+ mPointSizeAdded(false),
+ mLastFragDataAdded(false),
+ mFragColorAdded(false),
+ mFragDataAdded(false),
+ mFragDepthEXTAdded(false),
+ mFragDepthAdded(false),
+ mSecondaryFragColorEXTAdded(false),
+ mSecondaryFragDataEXTAdded(false),
+ mHashFunction(hashFunction),
+ mSymbolTable(symbolTable),
+ mExtensionBehavior(extensionBehavior)
+{
+}
+
+// We want to check whether a uniform/varying is statically used
+// because we only count the used ones in packing computing.
+// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
+// toward varying counting if they are statically used in a fragment
+// shader.
+void CollectVariables::visitSymbol(TIntermSymbol *symbol)
+{
+ ASSERT(symbol != NULL);
+ ShaderVariable *var = NULL;
+ const TString &symbolName = symbol->getSymbol();
+
+ if (IsVarying(symbol->getQualifier()))
+ {
+ var = FindVariable(symbolName, mVaryings);
+ }
+ else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
+ {
+ UNREACHABLE();
+ }
+ else if (symbolName == "gl_DepthRange")
+ {
+ ASSERT(symbol->getQualifier() == EvqUniform);
+
+ if (!mDepthRangeAdded)
+ {
+ Uniform info;
+ const char kName[] = "gl_DepthRange";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_STRUCT_ANGLEX;
+ info.arraySize = 0;
+ info.precision = GL_NONE;
+ info.staticUse = true;
+
+ ShaderVariable nearInfo;
+ const char kNearName[] = "near";
+ nearInfo.name = kNearName;
+ nearInfo.mappedName = kNearName;
+ nearInfo.type = GL_FLOAT;
+ nearInfo.arraySize = 0;
+ nearInfo.precision = GL_HIGH_FLOAT;
+ nearInfo.staticUse = true;
+
+ ShaderVariable farInfo;
+ const char kFarName[] = "far";
+ farInfo.name = kFarName;
+ farInfo.mappedName = kFarName;
+ farInfo.type = GL_FLOAT;
+ farInfo.arraySize = 0;
+ farInfo.precision = GL_HIGH_FLOAT;
+ farInfo.staticUse = true;
+
+ ShaderVariable diffInfo;
+ const char kDiffName[] = "diff";
+ diffInfo.name = kDiffName;
+ diffInfo.mappedName = kDiffName;
+ diffInfo.type = GL_FLOAT;
+ diffInfo.arraySize = 0;
+ diffInfo.precision = GL_HIGH_FLOAT;
+ diffInfo.staticUse = true;
+
+ info.fields.push_back(nearInfo);
+ info.fields.push_back(farInfo);
+ info.fields.push_back(diffInfo);
+
+ mUniforms->push_back(info);
+ mDepthRangeAdded = true;
+ }
+ }
+ else
+ {
+ switch (symbol->getQualifier())
+ {
+ 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)
+ {
+ InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
+ ASSERT(namedBlock);
+ var = FindVariable(symbolName, &namedBlock->fields);
+
+ // Set static use on the parent interface block here
+ namedBlock->staticUse = true;
+ }
+ else
+ {
+ var = FindVariable(symbolName, mUniforms);
+ }
+
+ // It's an internal error to reference an undefined user uniform
+ ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
+ }
+ break;
+ case EvqFragCoord:
+ if (!mFragCoordAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_FragCoord";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mFragCoordAdded = true;
+ }
+ return;
+ case EvqFrontFacing:
+ if (!mFrontFacingAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_FrontFacing";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_BOOL;
+ info.arraySize = 0;
+ info.precision = GL_NONE;
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mFrontFacingAdded = true;
+ }
+ return;
+ case EvqPointCoord:
+ if (!mPointCoordAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_PointCoord";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC2;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mPointCoordAdded = true;
+ }
+ return;
+ case EvqInstanceID:
+ if (!mInstanceIDAdded)
+ {
+ Attribute info;
+ const char kName[] = "gl_InstanceID";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_INT;
+ info.arraySize = 0;
+ info.precision = GL_HIGH_INT; // Defined by spec.
+ info.staticUse = true;
+ info.location = -1;
+ mAttribs->push_back(info);
+ mInstanceIDAdded = true;
+ }
+ return;
+ case EvqVertexID:
+ if (!mVertexIDAdded)
+ {
+ Attribute info;
+ const char kName[] = "gl_VertexID";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_INT;
+ info.arraySize = 0;
+ info.precision = GL_HIGH_INT; // Defined by spec.
+ info.staticUse = true;
+ info.location = -1;
+ mAttribs->push_back(info);
+ mVertexIDAdded = true;
+ }
+ return;
+ case EvqPosition:
+ if (!mPositionAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_Position";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_HIGH_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mPositionAdded = true;
+ }
+ return;
+ case EvqPointSize:
+ if (!mPointSizeAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_PointSize";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mPointSizeAdded = true;
+ }
+ return;
+ case EvqLastFragData:
+ if (!mLastFragDataAdded)
+ {
+ Varying info;
+ const char kName[] = "gl_LastFragData";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = static_cast<const TVariable*>(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst();
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
+ mVaryings->push_back(info);
+ mLastFragDataAdded = true;
+ }
+ return;
+ case EvqFragColor:
+ if (!mFragColorAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragColor";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragColorAdded = true;
+ }
+ return;
+ case EvqFragData:
+ if (!mFragDataAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragData";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ if (::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
+ {
+ info.arraySize = static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))
+ ->getConstPointer()
+ ->getIConst();
+ }
+ else
+ {
+ info.arraySize = 1;
+ }
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDataAdded = true;
+ }
+ return;
+ case EvqFragDepthEXT:
+ if (!mFragDepthEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragDepthEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT;
+ info.arraySize = 0;
+ info.precision =
+ GLVariablePrecision(static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_FragDepthEXT", 100))
+ ->getType());
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDepthEXTAdded = true;
+ }
+ return;
+ case EvqFragDepth:
+ if (!mFragDepthAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragDepth";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT;
+ info.arraySize = 0;
+ info.precision = GL_HIGH_FLOAT;
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDepthAdded = true;
+ }
+ return;
+ case EvqSecondaryFragColorEXT:
+ if (!mSecondaryFragColorEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_SecondaryFragColorEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragColorEXTAdded = true;
+ }
+ return;
+ case EvqSecondaryFragDataEXT:
+ if (!mSecondaryFragDataEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_SecondaryFragDataEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+
+ const TVariable *maxDualSourceDrawBuffersVar = static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_MaxDualSourceDrawBuffersEXT", 100));
+ info.arraySize = maxDualSourceDrawBuffersVar->getConstPointer()->getIConst();
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragDataEXTAdded = true;
+ }
+ return;
+ default:
+ break;
+ }
+ }
+ if (var)
+ {
+ var->staticUse = true;
+ }
+}
+
+class NameHashingTraverser : public GetVariableTraverser
+{
+ public:
+ NameHashingTraverser(ShHashFunction64 hashFunction,
+ const TSymbolTable &symbolTable)
+ : GetVariableTraverser(symbolTable),
+ mHashFunction(hashFunction)
+ {}
+
+ private:
+ void visitVariable(ShaderVariable *variable) override
+ {
+ TString stringName = TString(variable->name.c_str());
+ variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
+ }
+
+ ShHashFunction64 mHashFunction;
+};
+
+// Attributes, which cannot have struct fields, are a special case
+template <>
+void CollectVariables::visitVariable(const TIntermSymbol *variable,
+ std::vector<Attribute> *infoList) const
+{
+ ASSERT(variable);
+ const TType &type = variable->getType();
+ ASSERT(!type.getStruct());
+
+ Attribute attribute;
+
+ attribute.type = GLVariableType(type);
+ attribute.precision = GLVariablePrecision(type);
+ attribute.name = variable->getSymbol().c_str();
+ attribute.arraySize = type.getArraySize();
+ attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+ attribute.location = variable->getType().getLayoutQualifier().location;
+
+ infoList->push_back(attribute);
+}
+
+template <>
+void CollectVariables::visitVariable(const TIntermSymbol *variable,
+ std::vector<OutputVariable> *infoList) const
+{
+ ASSERT(variable);
+ const TType &type = variable->getType();
+ ASSERT(!type.getStruct());
+
+ OutputVariable attribute;
+
+ attribute.type = GLVariableType(type);
+ attribute.precision = GLVariablePrecision(type);
+ attribute.name = variable->getSymbol().c_str();
+ attribute.arraySize = type.getArraySize();
+ attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+ attribute.location = variable->getType().getLayoutQualifier().location;
+
+ infoList->push_back(attribute);
+}
+
+template <>
+void CollectVariables::visitVariable(const TIntermSymbol *variable,
+ std::vector<InterfaceBlock> *infoList) const
+{
+ InterfaceBlock interfaceBlock;
+ const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
+ ASSERT(blockType);
+
+ interfaceBlock.name = blockType->name().c_str();
+ interfaceBlock.mappedName =
+ TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
+ interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
+ interfaceBlock.arraySize = variable->getArraySize();
+ interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
+ interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
+
+ // Gather field information
+ for (const TField *field : blockType->fields())
+ {
+ const TType &fieldType = *field->type();
+
+ NameHashingTraverser traverser(mHashFunction, mSymbolTable);
+ traverser.traverse(fieldType, field->name(), &interfaceBlock.fields);
+
+ interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
+ }
+
+ infoList->push_back(interfaceBlock);
+}
+
+template <typename VarT>
+void CollectVariables::visitVariable(const TIntermSymbol *variable,
+ std::vector<VarT> *infoList) const
+{
+ NameHashingTraverser traverser(mHashFunction, mSymbolTable);
+ traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
+}
+
+template <typename VarT>
+void CollectVariables::visitInfoList(const TIntermSequence &sequence,
+ std::vector<VarT> *infoList) const
+{
+ for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
+ {
+ const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
+ // 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,
+ // and varyings cannot be initialized in a shader, we must have
+ // only TIntermSymbol nodes in the sequence.
+ ASSERT(variable != NULL);
+ visitVariable(variable, infoList);
+ }
+}
+
+bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp())
+ {
+ case EOpDeclaration:
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ ASSERT(!sequence.empty());
+
+ const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
+ TQualifier qualifier = typedNode.getQualifier();
+
+ if (typedNode.getBasicType() == EbtInterfaceBlock)
+ {
+ visitInfoList(sequence, mInterfaceBlocks);
+ visitChildren = false;
+ }
+ else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
+ qualifier == EvqFragmentOut || qualifier == EvqUniform ||
+ IsVarying(qualifier))
+ {
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ visitInfoList(sequence, mAttribs);
+ break;
+ case EvqFragmentOut:
+ visitInfoList(sequence, mOutputVariables);
+ break;
+ case EvqUniform:
+ visitInfoList(sequence, mUniforms);
+ break;
+ default:
+ visitInfoList(sequence, mVaryings);
+ break;
+ }
+
+ visitChildren = false;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
+ {
+ // NOTE: we do not determine static use for individual blocks of an array
+ TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
+ ASSERT(blockNode);
+
+ TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
+ ASSERT(constantUnion);
+
+ const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
+ InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
+ ASSERT(namedBlock);
+ namedBlock->staticUse = true;
+
+ unsigned int fieldIndex = constantUnion->getUConst(0);
+ ASSERT(fieldIndex < namedBlock->fields.size());
+ namedBlock->fields[fieldIndex].staticUse = true;
+ return false;
+ }
+
+ return true;
+}
+
+void ExpandVariable(const ShaderVariable &variable,
+ const std::string &name,
+ const std::string &mappedName,
+ bool markStaticUse,
+ std::vector<ShaderVariable> *expanded)
+{
+ if (variable.isStruct())
+ {
+ if (variable.isArray())
+ {
+ for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
+ elementIndex++)
+ {
+ std::string lname = name + ::ArrayString(elementIndex);
+ std::string lmappedName = mappedName + ::ArrayString(elementIndex);
+ ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
+ }
+ }
+ else
+ {
+ ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
+ }
+ }
+ else
+ {
+ ShaderVariable expandedVar = variable;
+
+ expandedVar.name = name;
+ expandedVar.mappedName = mappedName;
+
+ // Mark all expanded fields as used if the parent is used
+ if (markStaticUse)
+ {
+ expandedVar.staticUse = true;
+ }
+
+ if (expandedVar.isArray())
+ {
+ expandedVar.name += "[0]";
+ expandedVar.mappedName += "[0]";
+ }
+
+ expanded->push_back(expandedVar);
+ }
+}
+
+void ExpandUniforms(const std::vector<Uniform> &compact,
+ std::vector<ShaderVariable> *expanded)
+{
+ for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
+ {
+ const ShaderVariable &variable = compact[variableIndex];
+ ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.h b/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.h
new file mode 100644
index 000000000..f79035d38
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VariableInfo.h
@@ -0,0 +1,87 @@
+//
+// 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_VARIABLEINFO_H_
+#define COMPILER_TRANSLATOR_VARIABLEINFO_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/IntermNode.h"
+
+class TSymbolTable;
+
+namespace sh
+{
+
+// Traverses intermediate tree to collect all attributes, uniforms, varyings.
+class CollectVariables : public TIntermTraverser
+{
+ public:
+ CollectVariables(std::vector<Attribute> *attribs,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *varyings,
+ std::vector<InterfaceBlock> *interfaceBlocks,
+ ShHashFunction64 hashFunction,
+ const TSymbolTable &symbolTable,
+ const TExtensionBehavior &extensionBehavior);
+
+ void visitSymbol(TIntermSymbol *symbol) override;
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
+
+ private:
+ template <typename VarT>
+ void visitVariable(const TIntermSymbol *variable, std::vector<VarT> *infoList) const;
+
+ template <typename VarT>
+ void visitInfoList(const TIntermSequence &sequence, std::vector<VarT> *infoList) const;
+
+ std::vector<Attribute> *mAttribs;
+ std::vector<OutputVariable> *mOutputVariables;
+ std::vector<Uniform> *mUniforms;
+ std::vector<Varying> *mVaryings;
+ std::vector<InterfaceBlock> *mInterfaceBlocks;
+
+ std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
+
+ bool mDepthRangeAdded;
+ bool mPointCoordAdded;
+ bool mFrontFacingAdded;
+ bool mFragCoordAdded;
+
+ bool mInstanceIDAdded;
+ bool mVertexIDAdded;
+ bool mPositionAdded;
+ bool mPointSizeAdded;
+ bool mLastFragDataAdded;
+ bool mFragColorAdded;
+ bool mFragDataAdded;
+ bool mFragDepthEXTAdded;
+ bool mFragDepthAdded;
+ bool mSecondaryFragColorEXTAdded;
+ bool mSecondaryFragDataEXTAdded;
+
+ ShHashFunction64 mHashFunction;
+
+ const TSymbolTable &mSymbolTable;
+ const TExtensionBehavior &mExtensionBehavior;
+};
+
+void ExpandVariable(const ShaderVariable &variable,
+ const std::string &name,
+ const std::string &mappedName,
+ bool markStaticUse,
+ std::vector<ShaderVariable> *expanded);
+
+// Expand struct uniforms to flattened lists of split variables
+void ExpandUniforms(const std::vector<Uniform> &compact,
+ std::vector<ShaderVariable> *expanded);
+
+}
+
+#endif // COMPILER_TRANSLATOR_VARIABLEINFO_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariablePacker.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.cpp
index 895728776..a981c8ae0 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/VariablePacker.cpp
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.cpp
@@ -3,122 +3,81 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-#include "compiler/VariablePacker.h"
#include <algorithm>
-#include "compiler/ShHandle.h"
-namespace {
-int GetSortOrder(ShDataType type)
-{
- switch (type) {
- case SH_FLOAT_MAT4:
- return 0;
- case SH_FLOAT_MAT2:
- return 1;
- case SH_FLOAT_VEC4:
- case SH_INT_VEC4:
- case SH_BOOL_VEC4:
- return 2;
- case SH_FLOAT_MAT3:
- return 3;
- case SH_FLOAT_VEC3:
- case SH_INT_VEC3:
- case SH_BOOL_VEC3:
- return 4;
- case SH_FLOAT_VEC2:
- case SH_INT_VEC2:
- case SH_BOOL_VEC2:
- return 5;
- case SH_FLOAT:
- case SH_INT:
- case SH_BOOL:
- case SH_SAMPLER_2D:
- case SH_SAMPLER_CUBE:
- case SH_SAMPLER_EXTERNAL_OES:
- case SH_SAMPLER_2D_RECT_ARB:
- return 6;
- default:
- ASSERT(false);
- return 7;
- }
-}
-} // namespace
+#include "angle_gl.h"
-int VariablePacker::GetNumComponentsPerRow(ShDataType type)
+#include "compiler/translator/VariablePacker.h"
+#include "common/utilities.h"
+
+int VariablePacker::GetNumComponentsPerRow(sh::GLenum type)
{
- switch (type) {
- case SH_FLOAT_MAT4:
- case SH_FLOAT_MAT2:
- case SH_FLOAT_VEC4:
- case SH_INT_VEC4:
- case SH_BOOL_VEC4:
- return 4;
- case SH_FLOAT_MAT3:
- case SH_FLOAT_VEC3:
- case SH_INT_VEC3:
- case SH_BOOL_VEC3:
- return 3;
- case SH_FLOAT_VEC2:
- case SH_INT_VEC2:
- case SH_BOOL_VEC2:
- return 2;
- case SH_FLOAT:
- case SH_INT:
- case SH_BOOL:
- case SH_SAMPLER_2D:
- case SH_SAMPLER_CUBE:
- case SH_SAMPLER_EXTERNAL_OES:
- case SH_SAMPLER_2D_RECT_ARB:
- return 1;
- default:
- ASSERT(false);
- return 5;
+ 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 VariablePacker::GetNumRows(ShDataType type)
+int VariablePacker::GetNumRows(sh::GLenum type)
{
- switch (type) {
- case SH_FLOAT_MAT4:
- return 4;
- case SH_FLOAT_MAT3:
- return 3;
- case SH_FLOAT_MAT2:
- return 2;
- case SH_FLOAT_VEC4:
- case SH_INT_VEC4:
- case SH_BOOL_VEC4:
- case SH_FLOAT_VEC3:
- case SH_INT_VEC3:
- case SH_BOOL_VEC3:
- case SH_FLOAT_VEC2:
- case SH_INT_VEC2:
- case SH_BOOL_VEC2:
- case SH_FLOAT:
- case SH_INT:
- case SH_BOOL:
- case SH_SAMPLER_2D:
- case SH_SAMPLER_CUBE:
- case SH_SAMPLER_EXTERNAL_OES:
- case SH_SAMPLER_2D_RECT_ARB:
- return 1;
- default:
- ASSERT(false);
- return 100000;
+ 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;
}
}
-struct TVariableInfoComparer {
- bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const
+struct TVariableInfoComparer
+{
+ bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
{
- int lhsSortOrder = GetSortOrder(lhs.type);
- int rhsSortOrder = GetSortOrder(rhs.type);
+ int lhsSortOrder = gl::VariableSortOrder(lhs.type);
+ int rhsSortOrder = gl::VariableSortOrder(rhs.type);
if (lhsSortOrder != rhsSortOrder) {
return lhsSortOrder < rhsSortOrder;
}
// Sort by largest first.
- return lhs.size > rhs.size;
+ return lhs.arraySize > rhs.arraySize;
}
};
@@ -189,13 +148,29 @@ bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* de
return true;
}
-bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables)
+bool VariablePacker::CheckVariablesWithinPackingLimits(
+ unsigned int maxVectors,
+ const std::vector<sh::ShaderVariable> &in_variables)
{
ASSERT(maxVectors > 0);
maxRows_ = maxVectors;
topNonFullRow_ = 0;
bottomNonFullRow_ = maxRows_ - 1;
- TVariableInfoList variables(in_variables);
+ std::vector<sh::ShaderVariable> variables;
+
+ for (const auto &variable : in_variables)
+ {
+ ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse,
+ &variables);
+ }
+
+ // Check whether each variable fits in the available vectors.
+ for (size_t i = 0; i < variables.size(); i++) {
+ const sh::ShaderVariable &variable = variables[i];
+ if (variable.elementCount() > maxVectors / GetNumRows(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.
@@ -206,11 +181,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa
// Packs the 4 column variables.
size_t ii = 0;
for (; ii < variables.size(); ++ii) {
- const TVariableInfo& variable = variables[ii];
+ const sh::ShaderVariable &variable = variables[ii];
if (GetNumComponentsPerRow(variable.type) != 4) {
break;
}
- topNonFullRow_ += GetNumRows(variable.type) * variable.size;
+ topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount();
}
if (topNonFullRow_ > maxRows_) {
@@ -220,11 +195,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa
// Packs the 3 column variables.
int num3ColumnRows = 0;
for (; ii < variables.size(); ++ii) {
- const TVariableInfo& variable = variables[ii];
+ const sh::ShaderVariable &variable = variables[ii];
if (GetNumComponentsPerRow(variable.type) != 3) {
break;
}
- num3ColumnRows += GetNumRows(variable.type) * variable.size;
+ num3ColumnRows += GetNumRows(variable.type) * variable.elementCount();
}
if (topNonFullRow_ + num3ColumnRows > maxRows_) {
@@ -239,11 +214,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa
int rowsAvailableInColumns01 = twoColumnRowsAvailable;
int rowsAvailableInColumns23 = twoColumnRowsAvailable;
for (; ii < variables.size(); ++ii) {
- const TVariableInfo& variable = variables[ii];
+ const sh::ShaderVariable &variable = variables[ii];
if (GetNumComponentsPerRow(variable.type) != 2) {
break;
}
- int numRows = GetNumRows(variable.type) * variable.size;
+ int numRows = GetNumRows(variable.type) * variable.elementCount();
if (numRows <= rowsAvailableInColumns01) {
rowsAvailableInColumns01 -= numRows;
} else if (numRows <= rowsAvailableInColumns23) {
@@ -263,9 +238,9 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa
// Packs the 1 column variables.
for (; ii < variables.size(); ++ii) {
- const TVariableInfo& variable = variables[ii];
+ const sh::ShaderVariable &variable = variables[ii];
ASSERT(1 == GetNumComponentsPerRow(variable.type));
- int numRows = GetNumRows(variable.type) * variable.size;
+ int numRows = GetNumRows(variable.type) * variable.elementCount();
int smallestColumn = -1;
int smallestSize = maxRows_ + 1;
int topRow = -1;
@@ -292,6 +267,3 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa
return true;
}
-
-
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.h b/Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.h
new file mode 100644
index 000000000..5f38a0a98
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VariablePacker.h
@@ -0,0 +1,40 @@
+//
+// 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_VARIABLEPACKER_H_
+#define COMPILER_TRANSLATOR_VARIABLEPACKER_H_
+
+#include <vector>
+#include "compiler/translator/VariableInfo.h"
+
+class VariablePacker {
+ public:
+ // Returns true if the passed in variables pack in maxVectors following
+ // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+ bool CheckVariablesWithinPackingLimits(unsigned int maxVectors,
+ const std::vector<sh::ShaderVariable> &in_variables);
+
+ // Gets how many components in a row a data type takes.
+ static int GetNumComponentsPerRow(sh::GLenum type);
+
+ // Gets how many rows a data type takes.
+ static int GetNumRows(sh::GLenum type);
+
+ 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_;
+};
+
+#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.cpp
new file mode 100644
index 000000000..5c0c51914
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.cpp
@@ -0,0 +1,136 @@
+//
+// 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"
+
+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);
+ }
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol *node)
+{
+ if (node->getSymbol() == "gl_PointCoord")
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp())
+ {
+ case EOpDeclaration:
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ if (sequence.front()->getAsTyped()->getType().isInvariant())
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+ break;
+ }
+ case EOpInvariantDeclaration:
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ break;
+ case EOpParameters:
+ {
+ const TIntermSequence &params = *(node->getSequence());
+ for (TIntermSequence::const_iterator iter = params.begin();
+ iter != params.end(); ++iter)
+ {
+ const TIntermTyped *param = (*iter)->getAsTyped();
+ if (param->isArray())
+ {
+ TQualifier qualifier = param->getQualifier();
+ if ((qualifier == EvqOut) || (qualifier == EvqInOut))
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ break;
+ }
+ }
+ }
+ // Fully processed. No need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ if (sequence.size() == 1)
+ {
+ TIntermTyped *typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix())
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return visitChildren;
+}
+
+void TVersionGLSL::ensureVersionIsAtLeast(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.h
new file mode 100644
index 000000000..c41069d42
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/VersionGLSL.h
@@ -0,0 +1,68 @@
+//
+// 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/IntermNode.h"
+
+#include "compiler/translator/Pragma.h"
+
+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 *) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
+
+ private:
+ void ensureVersionIsAtLeast(int version);
+
+ int mVersion;
+};
+
+#endif // COMPILER_TRANSLATOR_VERSIONGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.cpp
new file mode 100644
index 000000000..ba6322848
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.cpp
@@ -0,0 +1,126 @@
+//
+// 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"
+
+namespace sh
+{
+
+BlockLayoutEncoder::BlockLayoutEncoder()
+ : mCurrentOffset(0)
+{
+}
+
+BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
+{
+ int arrayStride;
+ int matrixStride;
+
+ getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
+
+ const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
+ static_cast<int>(arrayStride * BytesPerComponent),
+ static_cast<int>(matrixStride * BytesPerComponent),
+ isRowMajorMatrix);
+
+ advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
+
+ return memberInfo;
+}
+
+// static
+size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
+{
+ return (info.offset / BytesPerComponent) / ComponentsPerRegister;
+}
+
+// static
+size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
+{
+ return (info.offset / BytesPerComponent) % ComponentsPerRegister;
+}
+
+void BlockLayoutEncoder::nextRegister()
+{
+ mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
+}
+
+Std140BlockEncoder::Std140BlockEncoder()
+{
+}
+
+void Std140BlockEncoder::enterAggregateType()
+{
+ nextRegister();
+}
+
+void Std140BlockEncoder::exitAggregateType()
+{
+ nextRegister();
+}
+
+void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, 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)) == BytesPerComponent);
+
+ size_t baseAlignment = 0;
+ int matrixStride = 0;
+ int arrayStride = 0;
+
+ if (gl::IsMatrixType(type))
+ {
+ baseAlignment = ComponentsPerRegister;
+ matrixStride = ComponentsPerRegister;
+
+ if (arraySize > 0)
+ {
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ arrayStride = ComponentsPerRegister * numRegisters;
+ }
+ }
+ else if (arraySize > 0)
+ {
+ baseAlignment = ComponentsPerRegister;
+ arrayStride = ComponentsPerRegister;
+ }
+ else
+ {
+ const int numComponents = gl::VariableComponentCount(type);
+ baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
+ }
+
+ mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
+
+ *matrixStrideOut = matrixStride;
+ *arrayStrideOut = arrayStride;
+}
+
+void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
+{
+ if (arraySize > 0)
+ {
+ mCurrentOffset += arrayStride * arraySize;
+ }
+ else if (gl::IsMatrixType(type))
+ {
+ ASSERT(matrixStride == ComponentsPerRegister);
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ mCurrentOffset += ComponentsPerRegister * numRegisters;
+ }
+ else
+ {
+ mCurrentOffset += gl::VariableComponentCount(type);
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.h b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.h
new file mode 100644
index 000000000..dd5fe0737
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayout.h
@@ -0,0 +1,103 @@
+//
+// 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 <vector>
+
+#include "angle_gl.h"
+#include <GLSLANG/ShaderLang.h>
+
+namespace sh
+{
+struct ShaderVariable;
+struct InterfaceBlockField;
+struct Uniform;
+struct Varying;
+struct InterfaceBlock;
+
+struct COMPILER_EXPORT BlockMemberInfo
+{
+ BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {}
+
+ BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
+ : offset(offset),
+ arrayStride(arrayStride),
+ matrixStride(matrixStride),
+ isRowMajorMatrix(isRowMajorMatrix)
+ {}
+
+ static BlockMemberInfo getDefaultBlockInfo()
+ {
+ return BlockMemberInfo(-1, -1, -1, false);
+ }
+
+ int offset;
+ int arrayStride;
+ int matrixStride;
+ bool isRowMajorMatrix;
+};
+
+class COMPILER_EXPORT BlockLayoutEncoder
+{
+ public:
+ BlockLayoutEncoder();
+ virtual ~BlockLayoutEncoder() {}
+
+ BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
+
+ size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
+
+ virtual void enterAggregateType() = 0;
+ virtual void exitAggregateType() = 0;
+
+ static const size_t BytesPerComponent = 4u;
+ static const unsigned int ComponentsPerRegister = 4u;
+
+ static size_t getBlockRegister(const BlockMemberInfo &info);
+ static size_t getBlockRegisterElement(const BlockMemberInfo &info);
+
+ protected:
+ size_t mCurrentOffset;
+
+ void nextRegister();
+
+ virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0;
+ virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0;
+};
+
+// 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 COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder
+{
+ public:
+ Std140BlockEncoder();
+
+ void enterAggregateType() override;
+ void exitAggregateType() override;
+
+ protected:
+ void getBlockLayoutInfo(GLenum type,
+ unsigned int arraySize,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) override;
+ void advanceOffset(GLenum type,
+ unsigned int arraySize,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) override;
+};
+
+}
+
+#endif // COMMON_BLOCKLAYOUT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.cpp
new file mode 100644
index 000000000..43119248e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.cpp
@@ -0,0 +1,171 @@
+//
+// 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)
+ : mEncoderStrategy(strategy),
+ mTransposeMatrices(false)
+{
+}
+
+void HLSLBlockEncoder::enterAggregateType()
+{
+ nextRegister();
+}
+
+void HLSLBlockEncoder::exitAggregateType()
+{
+}
+
+void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, 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)) == BytesPerComponent);
+
+ 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) ||
+ arraySize > 0)
+ {
+ nextRegister();
+ }
+
+ if (gl::IsMatrixType(type))
+ {
+ matrixStride = ComponentsPerRegister;
+
+ if (arraySize > 0)
+ {
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ arrayStride = ComponentsPerRegister * numRegisters;
+ }
+ }
+ else if (arraySize > 0)
+ {
+ arrayStride = ComponentsPerRegister;
+ }
+ else if (isPacked())
+ {
+ int numComponents = gl::VariableComponentCount(type);
+ if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
+ {
+ nextRegister();
+ }
+ }
+
+ *matrixStrideOut = matrixStride;
+ *arrayStrideOut = arrayStride;
+}
+
+void HLSLBlockEncoder::advanceOffset(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
+{
+ GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
+
+ if (arraySize > 0)
+ {
+ mCurrentOffset += arrayStride * (arraySize - 1);
+ }
+
+ if (gl::IsMatrixType(type))
+ {
+ ASSERT(matrixStride == ComponentsPerRegister);
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
+ mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
+ mCurrentOffset += numComponents;
+ }
+ else if (isPacked())
+ {
+ mCurrentOffset += gl::VariableComponentCount(type);
+ }
+ else
+ {
+ mCurrentOffset += ComponentsPerRegister;
+ }
+}
+
+void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
+{
+ mCurrentOffset += (numRegisters * ComponentsPerRegister);
+}
+
+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.elementCount(); arrayElement++)
+ {
+ encoder->enterAggregateType();
+
+ for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
+ {
+ HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
+ }
+
+ encoder->exitAggregateType();
+ }
+ }
+ else
+ {
+ // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
+ encoder->encodeType(variable.type, variable.arraySize, false);
+ }
+}
+
+unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices)
+{
+ HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED);
+ encoder.setTransposeMatrices(transposeMatrices);
+ HLSLVariableRegisterCount(variable, &encoder);
+
+ const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
+ return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
+}
+
+unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
+{
+ HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType));
+ encoder.setTransposeMatrices(true);
+ HLSLVariableRegisterCount(variable, &encoder);
+
+ const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
+ return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.h
new file mode 100644
index 000000000..c61cb1ae5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/blocklayoutHLSL.h
@@ -0,0 +1,62 @@
+//
+// 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 "angle_gl.h"
+#include "blocklayout.h"
+#include <GLSLANG/ShaderLang.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 COMPILER_EXPORT HLSLBlockEncoder : public BlockLayoutEncoder
+{
+ public:
+ enum HLSLBlockEncoderStrategy
+ {
+ ENCODE_PACKED,
+ ENCODE_LOOSE
+ };
+
+ HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy);
+
+ virtual void enterAggregateType();
+ virtual void exitAggregateType();
+ void skipRegisters(unsigned int numRegisters);
+
+ bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; }
+ void setTransposeMatrices(bool enabled) { mTransposeMatrices = enabled; }
+
+ static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType);
+
+ protected:
+ virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut);
+ virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride);
+
+ 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).
+COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices);
+COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType);
+
+}
+
+#endif // COMMON_BLOCKLAYOUTHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/generate_parser.sh b/Source/ThirdParty/ANGLE/src/compiler/translator/generate_parser.sh
new file mode 100644
index 000000000..61eecce73
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/generate_parser.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# 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.
+
+# Generates GLSL ES parser - glslang_lex.cpp, glslang_tab.h, and glslang_tab.cpp
+
+run_flex()
+{
+input_file=./$1.l
+output_source=./$1_lex.cpp
+flex --noline --nounistd --outfile=$output_source $input_file
+}
+
+run_bison()
+{
+input_file=./$1.y
+output_header=./$1_tab.h
+output_source=./$1_tab.cpp
+bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file
+}
+
+script_dir=$(dirname $0)
+
+# Generate Parser
+cd $script_dir
+run_flex glslang
+run_bison glslang
+patch --silent --forward < 64bit-lexer-safety.patch
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.h b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.h
index f22119909..0555e96d4 100644
--- a/Source/ThirdParty/ANGLE/src/compiler/glslang.h
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.h
@@ -4,7 +4,10 @@
// found in the LICENSE file.
//
-struct TParseContext;
+#ifndef COMPILER_TRANSLATOR_GLSLANG_H_
+#define COMPILER_TRANSLATOR_GLSLANG_H_
+
+class TParseContext;
extern int glslang_initialize(TParseContext* context);
extern int glslang_finalize(TParseContext* context);
@@ -14,3 +17,4 @@ extern int glslang_scan(size_t count,
TParseContext* context);
extern int glslang_parse(TParseContext* context);
+#endif // COMPILER_TRANSLATOR_GLSLANG_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.l b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.l
new file mode 100644
index 000000000..7fe289302
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.l
@@ -0,0 +1,586 @@
+/*
+//
+// 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).
+*/
+
+%top{
+//
+// 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!
+
+// 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: 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
+}
+
+%{
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/length_limits.h"
+#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_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 uint_constant(TParseContext *context);
+static int int_constant(TParseContext *context);
+static int float_constant(yyscan_t yyscanner);
+static int floatsuffix_check(TParseContext* context);
+%}
+
+%option noyywrap nounput never-interactive
+%option yylineno reentrant bison-bridge bison-locations
+%option extra-type="TParseContext*"
+%x FIELDS
+
+D [0-9]
+L [a-zA-Z_]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+O [0-7]
+
+%%
+
+%{
+ TParseContext* context = yyextra;
+%}
+
+"invariant" { return INVARIANT; }
+"highp" { return HIGH_PRECISION; }
+"mediump" { return MEDIUM_PRECISION; }
+"lowp" { return LOW_PRECISION; }
+"precision" { return PRECISION; }
+
+"attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); }
+"const" { return CONST_QUAL; }
+"uniform" { return UNIFORM; }
+"varying" { return ES2_keyword_ES3_reserved(context, VARYING); }
+
+"break" { return BREAK; }
+"continue" { return CONTINUE; }
+"do" { return DO; }
+"for" { return FOR; }
+"while" { return WHILE; }
+
+"if" { return IF; }
+"else" { return ELSE; }
+"switch" { return ES2_reserved_ES3_keyword(context, SWITCH); }
+"case" { return ES2_ident_ES3_keyword(context, CASE); }
+"default" { return ES2_reserved_ES3_keyword(context, DEFAULT); }
+
+"centroid" { return ES2_ident_ES3_keyword(context, CENTROID); }
+"flat" { return ES2_reserved_ES3_keyword(context, FLAT); }
+"smooth" { return ES2_ident_ES3_keyword(context, SMOOTH); }
+
+"in" { return IN_QUAL; }
+"out" { return OUT_QUAL; }
+"inout" { return INOUT_QUAL; }
+
+"float" { return FLOAT_TYPE; }
+"int" { return INT_TYPE; }
+"uint" { return ES2_ident_ES3_keyword(context, UINT_TYPE); }
+"void" { return VOID_TYPE; }
+"bool" { return BOOL_TYPE; }
+"true" { yylval->lex.b = true; return BOOLCONSTANT; }
+"false" { yylval->lex.b = false; return BOOLCONSTANT; }
+
+"discard" { return DISCARD; }
+"return" { return RETURN; }
+
+"mat2" { return MATRIX2; }
+"mat3" { return MATRIX3; }
+"mat4" { return MATRIX4; }
+
+"mat2x2" { return ES2_ident_ES3_keyword(context, MATRIX2); }
+"mat3x3" { return ES2_ident_ES3_keyword(context, MATRIX3); }
+"mat4x4" { return ES2_ident_ES3_keyword(context, MATRIX4); }
+
+"mat2x3" { return ES2_ident_ES3_keyword(context, MATRIX2x3); }
+"mat3x2" { return ES2_ident_ES3_keyword(context, MATRIX3x2); }
+"mat2x4" { return ES2_ident_ES3_keyword(context, MATRIX2x4); }
+"mat4x2" { return ES2_ident_ES3_keyword(context, MATRIX4x2); }
+"mat3x4" { return ES2_ident_ES3_keyword(context, MATRIX3x4); }
+"mat4x3" { return ES2_ident_ES3_keyword(context, MATRIX4x3); }
+
+"vec2" { return VEC2; }
+"vec3" { return VEC3; }
+"vec4" { return VEC4; }
+"ivec2" { return IVEC2; }
+"ivec3" { return IVEC3; }
+"ivec4" { return IVEC4; }
+"bvec2" { return BVEC2; }
+"bvec3" { return BVEC3; }
+"bvec4" { return BVEC4; }
+"uvec2" { return ES2_ident_ES3_keyword(context, UVEC2); }
+"uvec3" { return ES2_ident_ES3_keyword(context, UVEC3); }
+"uvec4" { return ES2_ident_ES3_keyword(context, UVEC4); }
+
+"sampler2D" { return SAMPLER2D; }
+"samplerCube" { return SAMPLERCUBE; }
+"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; }
+"sampler3D" { return ES2_reserved_ES3_keyword(context, SAMPLER3D); }
+"sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+"sampler2DRect" { return SAMPLER2DRECT; }
+"sampler2DArray" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); }
+"isampler2D" { return ES2_ident_ES3_keyword(context, ISAMPLER2D); }
+"isampler3D" { return ES2_ident_ES3_keyword(context, ISAMPLER3D); }
+"isamplerCube" { return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); }
+"isampler2DArray" { return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); }
+"usampler2D" { return ES2_ident_ES3_keyword(context, USAMPLER2D); }
+"usampler3D" { return ES2_ident_ES3_keyword(context, USAMPLER3D); }
+"usamplerCube" { return ES2_ident_ES3_keyword(context, USAMPLERCUBE); }
+"usampler2DArray" { return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); }
+"sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+"samplerCubeShadow" { return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); }
+"sampler2DArrayShadow" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+
+"struct" { return STRUCT; }
+
+"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); }
+
+ /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
+"coherent" |
+"restrict" |
+"readonly" |
+"writeonly" |
+"resource" |
+"atomic_uint" |
+"noperspective" |
+"patch" |
+"sample" |
+"subroutine" |
+"common" |
+"partition" |
+"active" |
+
+"filter" |
+"image1D" |
+"image2D" |
+"image3D" |
+"imageCube" |
+"iimage1D" |
+"iimage2D" |
+"iimage3D" |
+"iimageCube" |
+"uimage1D" |
+"uimage2D" |
+"uimage3D" |
+"uimageCube" |
+"image1DArray" |
+"image2DArray" |
+"iimage1DArray" |
+"iimage2DArray" |
+"uimage1DArray" |
+"uimage2DArray" |
+"image1DShadow" |
+"image2DShadow" |
+"image1DArrayShadow" |
+"image2DArrayShadow" |
+"imageBuffer" |
+"iimageBuffer" |
+"uimageBuffer" |
+
+"sampler1DArray" |
+"sampler1DArrayShadow" |
+"isampler1D" |
+"isampler1DArray" |
+"usampler1D" |
+"usampler1DArray" |
+"isampler2DRect" |
+"usampler2DRect" |
+"samplerBuffer" |
+"isamplerBuffer" |
+"usamplerBuffer" |
+"sampler2DMS" |
+"isampler2DMS" |
+"usampler2DMS" |
+"sampler2DMSArray" |
+"isampler2DMSArray" |
+"usampler2DMSArray" {
+ if (context->getShaderVersion() < 300) {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+ return reserved_word(yyscanner);
+}
+
+ /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
+"packed" {
+ if (context->getShaderVersion() >= 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return reserved_word(yyscanner);
+}
+
+ /* Reserved keywords */
+"asm" |
+
+"class" |
+"union" |
+"enum" |
+"typedef" |
+"template" |
+"this" |
+
+"goto" |
+
+"inline" |
+"noinline" |
+"volatile" |
+"public" |
+"static" |
+"extern" |
+"external" |
+"interface" |
+
+"long" |
+"short" |
+"double" |
+"half" |
+"fixed" |
+"unsigned" |
+"superp" |
+
+"input" |
+"output" |
+
+"hvec2" |
+"hvec3" |
+"hvec4" |
+"dvec2" |
+"dvec3" |
+"dvec4" |
+"fvec2" |
+"fvec3" |
+"fvec4" |
+
+"sampler1D" |
+"sampler1DShadow" |
+"sampler2DRectShadow" |
+
+"sizeof" |
+"cast" |
+
+"namespace" |
+"using" { return reserved_word(yyscanner); }
+
+{L}({L}|{D})* {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+
+0[xX]{H}+ { return int_constant(context); }
+0{O}+ { return int_constant(context); }
+{D}+ { return int_constant(context); }
+
+0[xX]{H}+[uU] { return uint_constant(context); }
+0{O}+[uU] { return uint_constant(context); }
+{D}+[uU] { return uint_constant(context); }
+
+{D}+{E} { return float_constant(yyscanner); }
+{D}+"."{D}*({E})? { return float_constant(yyscanner); }
+"."{D}+({E})? { return float_constant(yyscanner); }
+
+{D}+{E}[fF] { return floatsuffix_check(context); }
+{D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); }
+"."{D}+({E})?[fF] { return floatsuffix_check(context); }
+
+"+=" { return ADD_ASSIGN; }
+"-=" { return SUB_ASSIGN; }
+"*=" { return MUL_ASSIGN; }
+"/=" { return DIV_ASSIGN; }
+"%=" { return MOD_ASSIGN; }
+"<<=" { return LEFT_ASSIGN; }
+">>=" { return RIGHT_ASSIGN; }
+"&=" { return AND_ASSIGN; }
+"^=" { return XOR_ASSIGN; }
+"|=" { return OR_ASSIGN; }
+
+"++" { return INC_OP; }
+"--" { return DEC_OP; }
+"&&" { return AND_OP; }
+"||" { return OR_OP; }
+"^^" { return XOR_OP; }
+"<=" { return LE_OP; }
+">=" { return GE_OP; }
+"==" { return EQ_OP; }
+"!=" { return NE_OP; }
+"<<" { return LEFT_OP; }
+">>" { return RIGHT_OP; }
+";" { return SEMICOLON; }
+("{"|"<%") { return LEFT_BRACE; }
+("}"|"%>") { return RIGHT_BRACE; }
+"," { return COMMA; }
+":" { return COLON; }
+"=" { return EQUAL; }
+"(" { return LEFT_PAREN; }
+")" { return RIGHT_PAREN; }
+("["|"<:") { return LEFT_BRACKET; }
+("]"|":>") { return RIGHT_BRACKET; }
+"." { BEGIN(FIELDS); return DOT; }
+"!" { return BANG; }
+"-" { return DASH; }
+"~" { return TILDE; }
+"+" { return PLUS; }
+"*" { return STAR; }
+"/" { return SLASH; }
+"%" { return PERCENT; }
+"<" { return LEFT_ANGLE; }
+">" { return RIGHT_ANGLE; }
+"|" { return VERTICAL_BAR; }
+"^" { return CARET; }
+"&" { return AMPERSAND; }
+"?" { return QUESTION; }
+
+<FIELDS>{L}({L}|{D})* {
+ BEGIN(INITIAL);
+ yylval->lex.string = NewPoolTString(yytext);
+ return FIELD_SELECTION;
+}
+<FIELDS>[ \t\v\f\r] {}
+<FIELDS>. {
+ yyextra->error(*yylloc, "Illegal character at fieldname start", yytext, "");
+ return 0;
+}
+
+[ \t\v\n\f\r] { }
+<*><<EOF>> { yyterminate(); }
+<*>. { assert(false); return 0; }
+
+%%
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ pp::Token token;
+ yyget_extra(yyscanner)->getPreprocessor().lex(&token);
+ yy_size_t len = token.type == 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;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ 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_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 = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+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 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.
+ 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(iter->first.c_str(), 1);
+ }
+ if (context->getFragmentPrecisionHigh())
+ preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ preprocessor->setMaxTokenSize(GetGlobalMaxTokenSize(context->getShaderSpec()));
+
+ return 0;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.y b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.y
new file mode 100644
index 000000000..7476f62cb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang.y
@@ -0,0 +1,1491 @@
+/*
+//
+// 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 contains the Yacc grammar for GLSL ES.
+Based on ANSI C Yacc grammar:
+http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
+*/
+
+%{
+//
+// 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/Cache.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ParseContext.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+%}
+%expect 1 /* One shift reduce conflict because of if | else */
+%parse-param {TParseContext* context}
+%param {void *scanner}
+%define api.pure full
+%locations
+
+%code requires {
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+}
+
+%union {
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ TIntermBlock* intermBlock;
+ TIntermSwitch* intermSwitch;
+ TIntermCase* intermCase;
+ };
+ union {
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ TQualifierWrapperBase* qualifierWrapper;
+ TTypeQualifierBuilder* typeQualifierBuilder;
+ };
+ } interm;
+}
+
+%{
+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) { \
+ if (context->getShaderType() != GL_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->getShaderType() != GL_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ } \
+}
+
+#define COMPUTE_ONLY(S, L) { \
+ if (context->getShaderType() != GL_COMPUTE_SHADER) { \
+ context->error(L, " supported in compute shaders only ", S); \
+ } \
+}
+
+#define NON_COMPUTE_ONLY(S, L) { \
+ if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \
+ context->error(L, " supported in vertex and fragment shaders only ", S); \
+ } \
+}
+
+#define ES2_ONLY(S, L) { \
+ if (context->getShaderVersion() != 100) { \
+ context->error(L, " supported in GLSL ES 1.00 only ", S); \
+ } \
+}
+
+#define ES3_OR_NEWER(TOKEN, LINE, REASON) { \
+ if (context->getShaderVersion() < 300) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.00 and above only ", TOKEN); \
+ } \
+}
+
+#define ES3_1_ONLY(TOKEN, LINE, REASON) { \
+ if (context->getShaderVersion() != 310) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.10 only ", TOKEN); \
+ } \
+}
+%}
+
+%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
+%token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3
+%token <lex> CENTROID FLAT SMOOTH
+%token <lex> STRUCT VOID_TYPE WHILE
+%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY
+%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
+%token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY
+%token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW
+%token <lex> LAYOUT
+
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT
+%token <lex> FIELD_SELECTION
+%token <lex> LEFT_OP RIGHT_OP
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token <lex> SUB_ASSIGN
+
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+%type <lex> identifier
+%type <interm> assignment_operator unary_operator
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
+%type <interm.intermTypedNode> expression integer_expression assignment_expression
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
+%type <interm.intermTypedNode> relational_expression equality_expression
+%type <interm.intermTypedNode> conditional_expression constant_expression
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
+%type <interm.intermTypedNode> function_call initializer condition conditionopt
+
+%type <interm.intermBlock> translation_unit
+%type <interm.intermNode> function_definition statement simple_statement
+%type <interm.intermBlock> statement_list compound_statement compound_statement_no_new_scope
+%type <interm.intermNode> declaration_statement selection_statement expression_statement
+%type <interm.intermNode> declaration external_declaration
+%type <interm.intermNode> for_init_statement
+%type <interm.nodePair> selection_rest_statement for_rest_statement
+%type <interm.intermSwitch> switch_statement
+%type <interm.intermCase> case_label
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
+%type <interm> single_declaration init_declarator_list
+
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
+%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id
+
+%type <interm.type> fully_specified_type type_specifier
+
+%type <interm.precision> precision_qualifier
+%type <interm.layoutQualifier> layout_qualifier
+%type <interm.qualifier> storage_qualifier interpolation_qualifier
+%type <interm.qualifierWrapper> single_type_qualifier invariant_qualifier
+%type <interm.typeQualifierBuilder> type_qualifier
+
+%type <interm.typeSpecifierNonArray> type_specifier_nonarray struct_specifier
+%type <interm.type> type_specifier_no_prec
+%type <interm.field> struct_declarator
+%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
+%type <interm.function> function_header function_declarator function_identifier
+%type <interm.function> function_header_with_parameters function_call_header
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
+%type <interm> function_call_or_method
+
+%type <lex> enter_struct
+
+%start translation_unit
+%%
+
+identifier
+ : IDENTIFIER
+ | TYPE_NAME
+
+variable_identifier
+ : IDENTIFIER {
+ // The symbol table search was done in the lexical phase
+ $$ = context->parseVariableIdentifier(@1, $1.string, $1.symbol);
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+ }
+ ;
+
+primary_expression
+ : variable_identifier {
+ $$ = $1;
+ }
+ | INTCONSTANT {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setIConst($1.i);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1);
+ }
+ | UINTCONSTANT {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setUConst($1.u);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1);
+ }
+ | FLOATCONSTANT {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst($1.f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
+ }
+ | BOOLCONSTANT {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setBConst($1.b);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1);
+ }
+ | LEFT_PAREN expression RIGHT_PAREN {
+ $$ = $2;
+ }
+ ;
+
+postfix_expression
+ : primary_expression {
+ $$ = $1;
+ }
+ | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
+ $$ = context->addIndexExpression($1, @2, $3);
+ }
+ | function_call {
+ $$ = $1;
+ }
+ | postfix_expression DOT FIELD_SELECTION {
+ $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3);
+ }
+ | postfix_expression INC_OP {
+ $$ = context->addUnaryMathLValue(EOpPostIncrement, $1, @2);
+ }
+ | postfix_expression DEC_OP {
+ $$ = context->addUnaryMathLValue(EOpPostDecrement, $1, @2);
+ }
+ ;
+
+integer_expression
+ : expression {
+ context->checkIsScalarInteger($1, "[]");
+ $$ = $1;
+ }
+ ;
+
+function_call
+ : function_call_or_method {
+ bool fatalError = false;
+ $$ = context->addFunctionCallOrMethod($1.function, $1.nodePair.node1, $1.nodePair.node2, @1, &fatalError);
+ if (fatalError)
+ {
+ YYERROR;
+ }
+ }
+ ;
+
+function_call_or_method
+ : function_call_generic {
+ $$ = $1;
+ $$.nodePair.node2 = nullptr;
+ }
+ | postfix_expression DOT function_call_generic {
+ ES3_OR_NEWER("", @3, "methods");
+ $$ = $3;
+ $$.nodePair.node2 = $1;
+ }
+ ;
+
+function_call_generic
+ : function_call_header_with_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ | function_call_header_no_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+function_call_header_no_parameters
+ : function_call_header VOID_TYPE {
+ $$.function = $1;
+ $$.nodePair.node1 = nullptr;
+ }
+ | function_call_header {
+ $$.function = $1;
+ $$.nodePair.node1 = nullptr;
+ }
+ ;
+
+function_call_header_with_parameters
+ : function_call_header assignment_expression {
+ const TType *type = new TType($2->getType());
+ $1->addParameter(TConstParameter(type));
+ $$.function = $1;
+ $$.nodePair.node1 = TIntermediate::MakeAggregate($2, @2);
+ }
+ | function_call_header_with_parameters COMMA assignment_expression {
+ const TType *type = new TType($3->getType());
+ $1.function->addParameter(TConstParameter(type));
+ $$.function = $1.function;
+ $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2);
+ }
+ ;
+
+function_call_header
+ : function_identifier LEFT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+// Grammar Note: Constructors look like functions, but are recognized as types.
+
+function_identifier
+ : type_specifier_no_prec {
+ if ($1.array) {
+ ES3_OR_NEWER("[]", @1, "array constructor");
+ }
+ $$ = context->addConstructorFunc($1);
+ }
+ | IDENTIFIER {
+ context->checkIsNotReserved(@1, *$1.string);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ | FIELD_SELECTION {
+ context->checkIsNotReserved(@1, *$1.string);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ ;
+
+unary_expression
+ : postfix_expression {
+ $$ = $1;
+ }
+ | INC_OP unary_expression {
+ $$ = context->addUnaryMathLValue(EOpPreIncrement, $2, @1);
+ }
+ | DEC_OP unary_expression {
+ $$ = context->addUnaryMathLValue(EOpPreDecrement, $2, @1);
+ }
+ | unary_operator unary_expression {
+ if ($1.op != EOpNull) {
+ $$ = context->addUnaryMath($1.op, $2, @1);
+ } else
+ $$ = $2;
+ }
+ ;
+// Grammar Note: No traditional style type casts.
+
+unary_operator
+ : PLUS { $$.op = EOpPositive; }
+ | DASH { $$.op = EOpNegative; }
+ | BANG { $$.op = EOpLogicalNot; }
+ | TILDE {
+ ES3_OR_NEWER("~", @$, "bit-wise operator");
+ $$.op = EOpBitwiseNot;
+ }
+ ;
+// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+
+multiplicative_expression
+ : unary_expression { $$ = $1; }
+ | multiplicative_expression STAR unary_expression {
+ $$ = context->addBinaryMath(EOpMul, $1, $3, @2);
+ }
+ | multiplicative_expression SLASH unary_expression {
+ $$ = context->addBinaryMath(EOpDiv, $1, $3, @2);
+ }
+ | multiplicative_expression PERCENT unary_expression {
+ ES3_OR_NEWER("%", @2, "integer modulus operator");
+ $$ = context->addBinaryMath(EOpIMod, $1, $3, @2);
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression { $$ = $1; }
+ | additive_expression PLUS multiplicative_expression {
+ $$ = context->addBinaryMath(EOpAdd, $1, $3, @2);
+ }
+ | additive_expression DASH multiplicative_expression {
+ $$ = context->addBinaryMath(EOpSub, $1, $3, @2);
+ }
+ ;
+
+shift_expression
+ : additive_expression { $$ = $1; }
+ | shift_expression LEFT_OP additive_expression {
+ ES3_OR_NEWER("<<", @2, "bit-wise operator");
+ $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2);
+ }
+ | shift_expression RIGHT_OP additive_expression {
+ ES3_OR_NEWER(">>", @2, "bit-wise operator");
+ $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2);
+ }
+ ;
+
+relational_expression
+ : shift_expression { $$ = $1; }
+ | relational_expression LEFT_ANGLE shift_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpLessThan, $1, $3, @2);
+ }
+ | relational_expression RIGHT_ANGLE shift_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpGreaterThan, $1, $3, @2);
+ }
+ | relational_expression LE_OP shift_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpLessThanEqual, $1, $3, @2);
+ }
+ | relational_expression GE_OP shift_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, $1, $3, @2);
+ }
+ ;
+
+equality_expression
+ : relational_expression { $$ = $1; }
+ | equality_expression EQ_OP relational_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpEqual, $1, $3, @2);
+ }
+ | equality_expression NE_OP relational_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpNotEqual, $1, $3, @2);
+ }
+ ;
+
+and_expression
+ : equality_expression { $$ = $1; }
+ | and_expression AMPERSAND equality_expression {
+ ES3_OR_NEWER("&", @2, "bit-wise operator");
+ $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2);
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression { $$ = $1; }
+ | exclusive_or_expression CARET and_expression {
+ ES3_OR_NEWER("^", @2, "bit-wise operator");
+ $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2);
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression { $$ = $1; }
+ | inclusive_or_expression VERTICAL_BAR exclusive_or_expression {
+ ES3_OR_NEWER("|", @2, "bit-wise operator");
+ $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2);
+ }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression { $$ = $1; }
+ | logical_and_expression AND_OP inclusive_or_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpLogicalAnd, $1, $3, @2);
+ }
+ ;
+
+logical_xor_expression
+ : logical_and_expression { $$ = $1; }
+ | logical_xor_expression XOR_OP logical_and_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpLogicalXor, $1, $3, @2);
+ }
+ ;
+
+logical_or_expression
+ : logical_xor_expression { $$ = $1; }
+ | logical_or_expression OR_OP logical_xor_expression {
+ $$ = context->addBinaryMathBooleanResult(EOpLogicalOr, $1, $3, @2);
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression { $$ = $1; }
+ | logical_or_expression QUESTION expression COLON assignment_expression {
+ $$ = context->addTernarySelection($1, $3, $5, @2);
+ }
+ ;
+
+assignment_expression
+ : conditional_expression { $$ = $1; }
+ | unary_expression assignment_operator assignment_expression {
+ context->checkCanBeLValue(@2, "assign", $1);
+ $$ = context->addAssign($2.op, $1, $3, @2);
+ }
+ ;
+
+assignment_operator
+ : EQUAL { $$.op = EOpAssign; }
+ | MUL_ASSIGN { $$.op = EOpMulAssign; }
+ | DIV_ASSIGN { $$.op = EOpDivAssign; }
+ | MOD_ASSIGN {
+ ES3_OR_NEWER("%=", @$, "integer modulus operator");
+ $$.op = EOpIModAssign;
+ }
+ | ADD_ASSIGN { $$.op = EOpAddAssign; }
+ | SUB_ASSIGN { $$.op = EOpSubAssign; }
+ | LEFT_ASSIGN {
+ ES3_OR_NEWER("<<=", @$, "bit-wise operator");
+ $$.op = EOpBitShiftLeftAssign;
+ }
+ | RIGHT_ASSIGN {
+ ES3_OR_NEWER(">>=", @$, "bit-wise operator");
+ $$.op = EOpBitShiftRightAssign;
+ }
+ | AND_ASSIGN {
+ ES3_OR_NEWER("&=", @$, "bit-wise operator");
+ $$.op = EOpBitwiseAndAssign;
+ }
+ | XOR_ASSIGN {
+ ES3_OR_NEWER("^=", @$, "bit-wise operator");
+ $$.op = EOpBitwiseXorAssign;
+ }
+ | OR_ASSIGN {
+ ES3_OR_NEWER("|=", @$, "bit-wise operator");
+ $$.op = EOpBitwiseOrAssign;
+ }
+ ;
+
+expression
+ : assignment_expression {
+ $$ = $1;
+ }
+ | expression COMMA assignment_expression {
+ $$ = context->addComma($1, $3, @2);
+ }
+ ;
+
+constant_expression
+ : conditional_expression {
+ context->checkIsConst($1);
+ $$ = $1;
+ }
+ ;
+
+enter_struct
+ : IDENTIFIER LEFT_BRACE {
+ context->enterStructDeclaration(@1, *$1.string);
+ $$ = $1;
+ }
+ ;
+
+declaration
+ : function_prototype SEMICOLON {
+ $$ = context->addFunctionPrototypeDeclaration(*($1.function), @1);
+ }
+ | init_declarator_list SEMICOLON {
+ TIntermAggregate *aggNode = $1.intermAggregate;
+ if (aggNode && aggNode->getOp() == EOpNull)
+ aggNode->setOp(EOpDeclaration);
+ $$ = aggNode;
+ }
+ | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
+ if (($2 == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) {
+ context->error(@1, "precision is not supported in fragment shader", "highp");
+ }
+ if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
+ context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.getBasicType()));
+ }
+ $$ = 0;
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
+ ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
+ $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, NULL, @$, NULL, @$);
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
+ ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
+ $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, NULL, @$);
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
+ ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks");
+ $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, $7, @6);
+ }
+ | type_qualifier SEMICOLON {
+ context->parseGlobalLayoutQualifier(*$1);
+ $$ = 0;
+ }
+ | type_qualifier IDENTIFIER SEMICOLON // e.g. to qualify an existing variable as invariant
+ {
+ $$ = context->parseInvariantDeclaration(*$1, @2, $2.string, $2.symbol);
+ }
+ ;
+
+function_prototype
+ : function_declarator RIGHT_PAREN {
+ $$.function = context->parseFunctionDeclarator(@2, $1);
+ context->exitFunctionDeclaration();
+ }
+ ;
+
+function_declarator
+ : function_header {
+ $$ = $1;
+ }
+ | function_header_with_parameters {
+ $$ = $1;
+ }
+ ;
+
+
+function_header_with_parameters
+ : function_header parameter_declaration {
+ // Add the parameter
+ $$ = $1;
+ if ($2.param.type->getBasicType() != EbtVoid)
+ $1->addParameter($2.param.turnToConst());
+ else
+ delete $2.param.type;
+ }
+ | function_header_with_parameters COMMA parameter_declaration {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ($3.param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error(@2, "cannot be an argument type except for '(void)'", "void");
+ delete $3.param.type;
+ } else {
+ // Add the parameter
+ $$ = $1;
+ $1->addParameter($3.param.turnToConst());
+ }
+ }
+ ;
+
+function_header
+ : fully_specified_type IDENTIFIER LEFT_PAREN {
+ $$ = context->parseFunctionHeader($1, $2.string, @2);
+
+ context->symbolTable.push();
+ context->enterFunctionDeclaration();
+ }
+ ;
+
+parameter_declarator
+ // Type + name
+ : type_specifier identifier {
+ if ($1.getBasicType() == EbtVoid) {
+ context->error(@2, "illegal use of type 'void'", $2.string->c_str());
+ }
+ context->checkIsNotReserved(@2, *$2.string);
+ TParameter param = {$2.string, new TType($1)};
+ $$.param = param;
+ }
+ | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ // Check that we can make an array out of this type
+ context->checkIsValidTypeForArray(@3, $1);
+
+ context->checkIsNotReserved(@2, *$2.string);
+
+ unsigned int size = context->checkIsValidArraySize(@3, $4);
+
+ $1.setArraySize(size);
+
+ TType* type = new TType($1);
+ TParameter param = { $2.string, type };
+ $$.param = param;
+ }
+ ;
+
+parameter_declaration
+ //
+ // The only parameter qualifier a parameter can have are
+ // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
+ //
+
+ //
+ // Type + name
+ //
+ : type_qualifier parameter_declarator {
+ $$ = $2;
+ context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
+ }
+ | parameter_declarator {
+ $$ = $1;
+ $$.param.type->setQualifier(EvqIn);
+ }
+ | type_qualifier parameter_type_specifier {
+ $$ = $2;
+ context->checkIsParameterQualifierValid(@2, *$1, $2.param.type);
+ }
+ | parameter_type_specifier {
+ $$ = $1;
+ $$.param.type->setQualifier(EvqIn);
+ }
+ ;
+
+parameter_type_specifier
+ : type_specifier {
+ TParameter param = { 0, new TType($1) };
+ $$.param = param;
+ }
+ ;
+
+init_declarator_list
+ : single_declaration {
+ $$ = $1;
+ }
+ | init_declarator_list COMMA identifier {
+ $$ = $1;
+ $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, @3, *$3.string);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+ $$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
+ ES3_OR_NEWER("[]", @3, "implicitly sized array");
+ $$ = $1;
+ $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
+ ES3_OR_NEWER("=", @7, "first-class arrays (array initializer)");
+ $$ = $1;
+ $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5, @7, $8);
+ }
+ | init_declarator_list COMMA identifier EQUAL initializer {
+ $$ = $1;
+ $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5);
+ }
+ ;
+
+single_declaration
+ : fully_specified_type {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, "");
+ }
+ | fully_specified_type identifier {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
+ }
+ | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4);
+ }
+ | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
+ ES3_OR_NEWER("[]", @3, "implicitly sized array");
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6);
+ }
+ | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
+ ES3_OR_NEWER("=", @6, "first-class arrays (array initializer)");
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7);
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
+ }
+ ;
+
+fully_specified_type
+ : type_specifier {
+ $$ = $1;
+
+ if ($1.array) {
+ ES3_OR_NEWER("[]", @1, "first-class-array");
+ if (context->getShaderVersion() != 300) {
+ $1.clearArrayness();
+ }
+ }
+ }
+ | type_qualifier type_specifier {
+ $$ = context->addFullySpecifiedType(*$1, $2);
+ }
+ ;
+
+interpolation_qualifier
+ : SMOOTH {
+ $$ = EvqSmooth;
+ }
+ | FLAT {
+ $$ = EvqFlat;
+ }
+ ;
+
+type_qualifier
+ : single_type_qualifier {
+ $$ = context->createTypeQualifierBuilder(@1);
+ $$->appendQualifier($1);
+ }
+ | type_qualifier single_type_qualifier {
+ $$ = $1;
+ $$->appendQualifier($2);
+ }
+ ;
+
+invariant_qualifier
+ : INVARIANT {
+ // empty
+ }
+ ;
+
+single_type_qualifier
+ : storage_qualifier {
+ if (!context->declaringFunction() && $1 != EvqConst && !context->symbolTable.atGlobalLevel())
+ {
+ context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1));
+ }
+ $$ = new TStorageQualifierWrapper($1, @1);
+ }
+ | layout_qualifier {
+ context->checkIsAtGlobalLevel(@1, "layout");
+ $$ = new TLayoutQualifierWrapper($1, @1);
+ }
+ | precision_qualifier {
+ $$ = new TPrecisionQualifierWrapper($1, @1);
+ }
+ | interpolation_qualifier {
+ $$ = new TInterpolationQualifierWrapper($1, @1);
+ }
+ | invariant_qualifier {
+ context->checkIsAtGlobalLevel(@1, "invariant");
+ $$ = new TInvariantQualifierWrapper(@1);
+ }
+ ;
+
+
+storage_qualifier
+ :
+ ATTRIBUTE {
+ VERTEX_ONLY("attribute", @1);
+ ES2_ONLY("attribute", @1);
+ context->checkIsAtGlobalLevel(@1, "attribute");
+ $$ = EvqAttribute;
+ }
+ | VARYING {
+ ES2_ONLY("varying", @1);
+ context->checkIsAtGlobalLevel(@1, "varying");
+ if (context->getShaderType() == GL_VERTEX_SHADER)
+ $$ = EvqVaryingOut;
+ else
+ $$ = EvqVaryingIn;
+ }
+ | CONST_QUAL {
+ $$ = EvqConst;
+ }
+ | IN_QUAL {
+ if (context->declaringFunction())
+ {
+ $$ = EvqIn;
+ }
+ else if (context->getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ ES3_OR_NEWER("in", @1, "storage qualifier");
+ $$ = EvqFragmentIn;
+ }
+ else if (context->getShaderType() == GL_VERTEX_SHADER)
+ {
+ ES3_OR_NEWER("in", @1, "storage qualifier");
+ $$ = EvqVertexIn;
+ }
+ else
+ {
+ $$ = EvqComputeIn;
+ }
+ }
+ | OUT_QUAL {
+ if (context->declaringFunction())
+ {
+ $$ = EvqOut;
+ }
+ else
+ {
+ ES3_OR_NEWER("out", @1, "storage qualifier");
+ NON_COMPUTE_ONLY("out", @1);
+ if (context->getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ $$ = EvqFragmentOut;
+ }
+ else
+ {
+ $$ = EvqVertexOut;
+ }
+ }
+ }
+ | INOUT_QUAL {
+ if (!context->declaringFunction())
+ {
+ context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters");
+ }
+ $$ = EvqInOut;
+ }
+ | CENTROID {
+ ES3_OR_NEWER("centroid", @1, "storage qualifier");
+ $$ = EvqCentroid;
+ }
+ | UNIFORM {
+ context->checkIsAtGlobalLevel(@1, "uniform");
+ $$ = EvqUniform;
+ }
+ ;
+
+type_specifier
+ : type_specifier_no_prec {
+ $$ = $1;
+
+ if ($$.precision == EbpUndefined) {
+ $$.precision = context->symbolTable.getDefaultPrecision($1.getBasicType());
+ }
+ }
+ ;
+
+precision_qualifier
+ : HIGH_PRECISION {
+ $$ = EbpHigh;
+ }
+ | MEDIUM_PRECISION {
+ $$ = EbpMedium;
+ }
+ | LOW_PRECISION {
+ $$ = EbpLow;
+ }
+ ;
+
+layout_qualifier
+ : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN {
+ ES3_OR_NEWER("layout", @1, "qualifier");
+ $$ = $3;
+ }
+ ;
+
+layout_qualifier_id_list
+ : layout_qualifier_id {
+ $$ = $1;
+ }
+ | layout_qualifier_id_list COMMA layout_qualifier_id {
+ $$ = context->joinLayoutQualifiers($1, $3, @3);
+ }
+ ;
+
+layout_qualifier_id
+ : IDENTIFIER {
+ $$ = context->parseLayoutQualifier(*$1.string, @1);
+ }
+ | IDENTIFIER EQUAL INTCONSTANT {
+ $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3);
+ }
+ | IDENTIFIER EQUAL UINTCONSTANT {
+ $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3);
+ }
+ ;
+
+type_specifier_no_prec
+ : type_specifier_nonarray {
+ $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ }
+ | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
+ ES3_OR_NEWER("[]", @2, "implicitly sized array");
+ $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ $$.setArraySize(0);
+ }
+ | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ if (context->checkIsValidTypeForArray(@2, $$))
+ {
+ unsigned int size = context->checkIsValidArraySize(@2, $3);
+ $$.setArraySize(size);
+ }
+ }
+ ;
+
+type_specifier_nonarray
+ : VOID_TYPE {
+ $$.initialize(EbtVoid, @1);
+ }
+ | FLOAT_TYPE {
+ $$.initialize(EbtFloat, @1);
+ }
+ | INT_TYPE {
+ $$.initialize(EbtInt, @1);
+ }
+ | UINT_TYPE {
+ $$.initialize(EbtUInt, @1);
+ }
+ | BOOL_TYPE {
+ $$.initialize(EbtBool, @1);
+ }
+ | VEC2 {
+ $$.initialize(EbtFloat, @1);
+ $$.setAggregate(2);
+ }
+ | VEC3 {
+ $$.initialize(EbtFloat, @1);
+ $$.setAggregate(3);
+ }
+ | VEC4 {
+ $$.initialize(EbtFloat, @1);
+ $$.setAggregate(4);
+ }
+ | BVEC2 {
+ $$.initialize(EbtBool, @1);
+ $$.setAggregate(2);
+ }
+ | BVEC3 {
+ $$.initialize(EbtBool, @1);
+ $$.setAggregate(3);
+ }
+ | BVEC4 {
+ $$.initialize(EbtBool, @1);
+ $$.setAggregate(4);
+ }
+ | IVEC2 {
+ $$.initialize(EbtInt, @1);
+ $$.setAggregate(2);
+ }
+ | IVEC3 {
+ $$.initialize(EbtInt, @1);
+ $$.setAggregate(3);
+ }
+ | IVEC4 {
+ $$.initialize(EbtInt, @1);
+ $$.setAggregate(4);
+ }
+ | UVEC2 {
+ $$.initialize(EbtUInt, @1);
+ $$.setAggregate(2);
+ }
+ | UVEC3 {
+ $$.initialize(EbtUInt, @1);
+ $$.setAggregate(3);
+ }
+ | UVEC4 {
+ $$.initialize(EbtUInt, @1);
+ $$.setAggregate(4);
+ }
+ | MATRIX2 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(2, 2);
+ }
+ | MATRIX3 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(3, 3);
+ }
+ | MATRIX4 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(4, 4);
+ }
+ | MATRIX2x3 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(2, 3);
+ }
+ | MATRIX3x2 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(3, 2);
+ }
+ | MATRIX2x4 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(2, 4);
+ }
+ | MATRIX4x2 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(4, 2);
+ }
+ | MATRIX3x4 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(3, 4);
+ }
+ | MATRIX4x3 {
+ $$.initialize(EbtFloat, @1);
+ $$.setMatrix(4, 3);
+ }
+ | SAMPLER2D {
+ $$.initialize(EbtSampler2D, @1);
+ }
+ | SAMPLER3D {
+ $$.initialize(EbtSampler3D, @1);
+ }
+ | SAMPLERCUBE {
+ $$.initialize(EbtSamplerCube, @1);
+ }
+ | SAMPLER2DARRAY {
+ $$.initialize(EbtSampler2DArray, @1);
+ }
+ | ISAMPLER2D {
+ $$.initialize(EbtISampler2D, @1);
+ }
+ | ISAMPLER3D {
+ $$.initialize(EbtISampler3D, @1);
+ }
+ | ISAMPLERCUBE {
+ $$.initialize(EbtISamplerCube, @1);
+ }
+ | ISAMPLER2DARRAY {
+ $$.initialize(EbtISampler2DArray, @1);
+ }
+ | USAMPLER2D {
+ $$.initialize(EbtUSampler2D, @1);
+ }
+ | USAMPLER3D {
+ $$.initialize(EbtUSampler3D, @1);
+ }
+ | USAMPLERCUBE {
+ $$.initialize(EbtUSamplerCube, @1);
+ }
+ | USAMPLER2DARRAY {
+ $$.initialize(EbtUSampler2DArray, @1);
+ }
+ | SAMPLER2DSHADOW {
+ $$.initialize(EbtSampler2DShadow, @1);
+ }
+ | SAMPLERCUBESHADOW {
+ $$.initialize(EbtSamplerCubeShadow, @1);
+ }
+ | SAMPLER2DARRAYSHADOW {
+ $$.initialize(EbtSampler2DArrayShadow, @1);
+ }
+ | SAMPLER_EXTERNAL_OES {
+ if (!context->supportsExtension("GL_OES_EGL_image_external") &&
+ !context->supportsExtension("GL_NV_EGL_stream_consumer_external")) {
+ context->error(@1, "unsupported type", "samplerExternalOES");
+ }
+ $$.initialize(EbtSamplerExternalOES, @1);
+ }
+ | SAMPLER2DRECT {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error(@1, "unsupported type", "sampler2DRect");
+ }
+ $$.initialize(EbtSampler2DRect, @1);
+ }
+ | struct_specifier {
+ $$ = $1;
+ }
+ | TYPE_NAME {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>($1.symbol)->getType();
+ $$.initialize(EbtStruct, @1);
+ $$.userDef = &structure;
+ }
+ ;
+
+struct_specifier
+ : STRUCT identifier LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE {
+ $$ = context->addStructure(@1, @2, $2.string, $5);
+ }
+ | STRUCT LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE {
+ $$ = context->addStructure(@1, @$, NewPoolTString(""), $4);
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration {
+ $$ = $1;
+ }
+ | struct_declaration_list struct_declaration {
+ $$ = $1;
+ for (size_t i = 0; i < $2->size(); ++i) {
+ TField* field = (*$2)[i];
+ for (size_t j = 0; j < $$->size(); ++j) {
+ if ((*$$)[j]->name() == field->name()) {
+ context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str());
+ }
+ }
+ $$->push_back(field);
+ }
+ }
+ ;
+
+struct_declaration
+ : type_specifier struct_declarator_list SEMICOLON {
+ $$ = context->addStructDeclaratorList($1, $2);
+ }
+ | type_qualifier type_specifier struct_declarator_list SEMICOLON {
+ // ES3 Only, but errors should be handled elsewhere
+ $$ = context->addStructDeclaratorListWithQualifiers(*$1, &$2, $3);
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator {
+ $$ = NewPoolTFieldList();
+ $$->push_back($1);
+ }
+ | struct_declarator_list COMMA struct_declarator {
+ $$->push_back($3);
+ }
+ ;
+
+struct_declarator
+ : identifier {
+ context->checkIsNotReserved(@1, *$1.string);
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ $$ = new TField(type, $1.string, @1);
+ }
+ | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ context->checkIsNotReserved(@1, *$1.string);
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ unsigned int size = context->checkIsValidArraySize(@3, $3);
+ type->setArraySize(size);
+
+ $$ = new TField(type, $1.string, @1);
+ }
+ ;
+
+initializer
+ : assignment_expression { $$ = $1; }
+ ;
+
+declaration_statement
+ : declaration { $$ = $1; }
+ ;
+
+statement
+ : compound_statement { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+// Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported.
+
+simple_statement
+ : declaration_statement { $$ = $1; }
+ | expression_statement { $$ = $1; }
+ | selection_statement { $$ = $1; }
+ | switch_statement { $$ = $1; }
+ | case_label { $$ = $1; }
+ | iteration_statement { $$ = $1; }
+ | jump_statement { $$ = $1; }
+ ;
+
+compound_statement
+ : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
+ | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
+ if ($3 != 0) {
+ $3->setLine(@$);
+ }
+ $$ = $3;
+ }
+ ;
+
+statement_no_new_scope
+ : compound_statement_no_new_scope { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+statement_with_scope
+ : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; }
+ | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; }
+ ;
+
+compound_statement_no_new_scope
+ // Statement that doesn't create a new scope, for selection_statement, iteration_statement
+ : LEFT_BRACE RIGHT_BRACE {
+ $$ = 0;
+ }
+ | LEFT_BRACE statement_list RIGHT_BRACE {
+ if ($2) {
+ $2->setLine(@$);
+ }
+ $$ = $2;
+ }
+ ;
+
+statement_list
+ : statement {
+ $$ = new TIntermBlock();
+ $$->setLine(@$);
+ $$->appendStatement($1);
+ }
+ | statement_list statement {
+ $$ = $1;
+ $$->appendStatement($2);
+ }
+ ;
+
+expression_statement
+ : SEMICOLON { $$ = 0; }
+ | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
+ ;
+
+selection_statement
+ : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
+ context->checkIsScalarBool(@1, $3);
+ $$ = context->intermediate.addIfElse($3, $5, @1);
+ }
+ ;
+
+selection_rest_statement
+ : statement_with_scope ELSE statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ | statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ ;
+
+switch_statement
+ : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
+ $$ = context->addSwitch($3, $6, @1);
+ context->decrSwitchNestingLevel();
+ }
+ ;
+
+case_label
+ : CASE constant_expression COLON {
+ $$ = context->addCase($2, @1);
+ }
+ | DEFAULT COLON {
+ $$ = context->addDefault(@1);
+ }
+ ;
+
+condition
+ // In 1996 c++ draft, conditions can include single declarations
+ : expression {
+ $$ = $1;
+ context->checkIsScalarBool($1->getLine(), $1);
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ TIntermNode *intermNode;
+ context->checkIsScalarBool(@2, $1);
+
+ if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode))
+ $$ = $4;
+ else {
+ $$ = 0;
+ }
+ }
+ ;
+
+iteration_statement
+ : WHILE LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } condition RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
+ context->decrLoopNestingLevel();
+ }
+ | DO { context->incrLoopNestingLevel(); } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ context->checkIsScalarBool(@8, $6);
+
+ $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
+ context->decrLoopNestingLevel();
+ }
+ | FOR LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
+ context->decrLoopNestingLevel();
+ }
+ ;
+
+for_init_statement
+ : expression_statement {
+ $$ = $1;
+ }
+ | declaration_statement {
+ $$ = $1;
+ }
+ ;
+
+conditionopt
+ : condition {
+ $$ = $1;
+ }
+ | /* May be null */ {
+ $$ = 0;
+ }
+ ;
+
+for_rest_statement
+ : conditionopt SEMICOLON {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ | conditionopt SEMICOLON expression {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ ;
+
+jump_statement
+ : CONTINUE SEMICOLON {
+ $$ = context->addBranch(EOpContinue, @1);
+ }
+ | BREAK SEMICOLON {
+ $$ = context->addBranch(EOpBreak, @1);
+ }
+ | RETURN SEMICOLON {
+ $$ = context->addBranch(EOpReturn, @1);
+ }
+ | RETURN expression SEMICOLON {
+ $$ = context->addBranch(EOpReturn, $2, @1);
+ }
+ | DISCARD SEMICOLON {
+ FRAG_ONLY("discard", @1);
+ $$ = context->addBranch(EOpKill, @1);
+ }
+ ;
+
+// Grammar Note: No 'goto'. Gotos are not supported.
+
+translation_unit
+ : external_declaration {
+ $$ = new TIntermBlock();
+ $$->setLine(@$);
+ $$->appendStatement($1);
+ context->setTreeRoot($$);
+ }
+ | translation_unit external_declaration {
+ $$->appendStatement($2);
+ }
+ ;
+
+external_declaration
+ : function_definition {
+ $$ = $1;
+ }
+ | declaration {
+ $$ = $1;
+ }
+ ;
+
+function_definition
+ : function_prototype {
+ context->parseFunctionDefinitionHeader(@1, &($1.function), &$1.intermAggregate);
+ }
+ compound_statement_no_new_scope {
+ $$ = context->addFunctionDefinition(*($1.function), $1.intermAggregate, $3, @1);
+ }
+ ;
+
+%%
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context, context->getScanner());
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_lex.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_lex.cpp
new file mode 100644
index 000000000..8ad7b1464
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_lex.cpp
@@ -0,0 +1,3424 @@
+#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!
+
+// 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: 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
+
+
+
+#line 28 "./glslang_lex.cpp"
+
+#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 5
+#define YY_FLEX_SUBMINOR_VERSION 39
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.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;
+typedef uint64_t flex_uint64_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
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned 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
+#define YY_BUF_SIZE 16384
+#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
+
+#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 { \
+ yy_size_t 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.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t 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 (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t 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) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char 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 yy_fatal_error (yyconst 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 = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 240
+#define YY_END_OF_BUFFER 241
+/* 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 yyconst flex_int16_t yy_accept[820] =
+ { 0,
+ 0, 0, 0, 0, 241, 239, 238, 238, 222, 228,
+ 233, 217, 218, 226, 225, 214, 223, 221, 227, 180,
+ 180, 215, 211, 229, 216, 230, 234, 177, 219, 220,
+ 232, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 212, 231, 213, 224, 237, 236, 240, 235, 208,
+ 194, 213, 202, 197, 192, 200, 190, 201, 191, 186,
+ 193, 185, 179, 180, 0, 183, 0, 220, 212, 219,
+ 209, 205, 207, 206, 210, 177, 198, 204, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+
+ 12, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 15, 177, 177, 23, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 199, 203, 235, 0, 189, 185, 0, 188, 182,
+ 0, 184, 178, 195, 196, 177, 136, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 13, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+
+ 177, 27, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 24, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 0, 186,
+ 0, 185, 187, 181, 177, 177, 177, 30, 177, 177,
+ 18, 174, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 16, 139, 177, 177, 177, 177, 21, 177,
+ 177, 143, 155, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 152, 4, 35, 36, 37,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 142, 31, 177, 177, 28, 177,
+ 177, 177, 177, 177, 177, 177, 47, 48, 49, 29,
+ 177, 177, 177, 177, 177, 177, 10, 53, 54, 55,
+ 177, 137, 177, 177, 7, 177, 177, 177, 177, 164,
+ 165, 166, 177, 32, 177, 156, 26, 167, 168, 169,
+ 2, 161, 162, 163, 177, 177, 177, 25, 159, 177,
+ 177, 177, 50, 51, 52, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 86, 177, 177, 177,
+
+ 177, 177, 177, 177, 153, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 138, 177, 177, 176,
+ 56, 57, 58, 177, 177, 14, 177, 91, 177, 177,
+ 177, 177, 89, 177, 177, 177, 154, 149, 92, 177,
+ 177, 177, 177, 177, 177, 144, 177, 177, 177, 78,
+ 38, 41, 43, 42, 39, 45, 44, 46, 40, 177,
+ 177, 177, 177, 160, 135, 177, 177, 147, 177, 177,
+ 177, 34, 87, 173, 22, 148, 77, 177, 158, 17,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 19, 33, 177, 177, 177, 177,
+
+ 177, 177, 93, 94, 95, 177, 177, 177, 177, 177,
+ 3, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 140, 177, 177, 177, 177, 177, 8, 177,
+ 177, 9, 177, 177, 177, 177, 20, 79, 11, 150,
+ 97, 98, 99, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 145, 177, 177, 177, 81,
+ 83, 80, 177, 177, 177, 177, 177, 177, 177, 141,
+ 101, 102, 103, 177, 177, 157, 177, 146, 177, 177,
+ 6, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 96, 151, 1, 177, 177, 177, 177, 177, 175, 177,
+
+ 90, 5, 170, 59, 62, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 82, 177,
+ 177, 177, 177, 100, 177, 177, 177, 177, 177, 120,
+ 66, 67, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 88, 177, 177, 177, 104,
+ 122, 70, 71, 177, 177, 84, 177, 177, 177, 177,
+ 177, 177, 177, 115, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 129, 177, 177, 177, 177, 60,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 116, 105, 177, 106, 177, 177, 177, 130,
+
+ 177, 177, 68, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 117, 177, 177, 131,
+ 177, 177, 72, 107, 108, 177, 111, 177, 112, 177,
+ 177, 177, 177, 177, 85, 177, 177, 177, 177, 64,
+ 177, 63, 126, 177, 177, 109, 110, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 124, 127, 118,
+ 177, 65, 177, 177, 177, 177, 177, 177, 177, 177,
+ 125, 128, 177, 177, 121, 69, 177, 177, 171, 177,
+ 177, 177, 74, 177, 177, 123, 73, 177, 177, 177,
+ 177, 177, 177, 132, 177, 177, 177, 177, 177, 177,
+
+ 133, 177, 177, 177, 75, 177, 134, 113, 114, 177,
+ 177, 177, 61, 177, 177, 172, 119, 76, 0
+ } ;
+
+static yyconst flex_int32_t 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, 20, 20, 21, 21, 22, 23, 24,
+ 25, 26, 27, 1, 28, 29, 30, 31, 32, 33,
+ 34, 34, 34, 34, 34, 34, 35, 34, 36, 34,
+ 34, 37, 38, 34, 39, 34, 34, 40, 34, 34,
+ 41, 1, 42, 43, 44, 1, 45, 46, 47, 48,
+
+ 49, 50, 51, 52, 53, 34, 54, 55, 56, 57,
+ 58, 59, 34, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 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 yyconst flex_int32_t yy_meta[73] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 3, 2, 2, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 4, 3, 3, 3, 3, 2, 2,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 1, 1,
+ 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[825] =
+ { 0,
+ 0, 0, 72, 0, 1016, 1017, 1017, 1017, 990, 120,
+ 141, 1017, 1017, 989, 138, 1017, 137, 135, 988, 154,
+ 208, 986, 1017, 154, 986, 132, 1017, 0, 1017, 1017,
+ 139, 130, 123, 140, 147, 133, 177, 952, 186, 151,
+ 139, 116, 161, 946, 173, 959, 193, 199, 208, 215,
+ 108, 1017, 184, 1017, 1017, 1017, 1017, 1017, 0, 1017,
+ 1017, 1017, 1017, 1017, 1017, 1017, 1017, 1017, 1017, 230,
+ 1017, 235, 235, 0, 271, 1017, 0, 1017, 1017, 1017,
+ 982, 1017, 1017, 1017, 981, 0, 1017, 1017, 943, 948,
+ 152, 945, 953, 952, 939, 942, 953, 243, 947, 935,
+
+ 932, 945, 932, 929, 929, 935, 147, 248, 929, 939,
+ 925, 931, 934, 935, 0, 927, 937, 249, 936, 931,
+ 912, 177, 916, 929, 920, 184, 913, 250, 925, 927,
+ 257, 916, 913, 902, 911, 249, 257, 915, 911, 913,
+ 902, 905, 196, 217, 269, 914, 902, 914, 262, 907,
+ 906, 1017, 1017, 0, 311, 1017, 292, 328, 1017, 1017,
+ 335, 342, 257, 1017, 1017, 905, 0, 901, 896, 900,
+ 909, 906, 315, 890, 890, 901, 893, 215, 903, 900,
+ 900, 898, 895, 887, 893, 880, 878, 890, 876, 892,
+ 0, 889, 877, 884, 881, 885, 886, 879, 876, 865,
+
+ 864, 877, 880, 868, 876, 864, 870, 861, 316, 866,
+ 869, 860, 867, 856, 860, 851, 865, 864, 855, 861,
+ 307, 845, 848, 846, 856, 846, 841, 839, 841, 851,
+ 837, 839, 836, 847, 846, 849, 831, 316, 839, 835,
+ 833, 842, 821, 353, 839, 841, 830, 822, 363, 370,
+ 378, 389, 1017, 1017, 819, 829, 828, 0, 826, 383,
+ 0, 0, 819, 817, 817, 818, 813, 821, 810, 827,
+ 816, 394, 0, 0, 810, 820, 819, 819, 0, 804,
+ 397, 0, 0, 806, 400, 813, 814, 805, 799, 798,
+ 799, 798, 798, 406, 793, 0, 0, 789, 788, 787,
+
+ 789, 790, 795, 789, 785, 798, 793, 793, 791, 790,
+ 784, 778, 780, 779, 783, 775, 778, 773, 781, 786,
+ 774, 771, 783, 774, 0, 0, 780, 776, 0, 768,
+ 768, 773, 764, 771, 409, 768, 0, 0, 0, 0,
+ 758, 770, 769, 768, 769, 769, 0, 0, 0, 0,
+ 756, 0, 764, 755, 0, 754, 755, 749, 759, 0,
+ 0, 0, 750, 0, 746, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 756, 413, 755, 0, 0, 753,
+ 749, 746, 0, 0, 0, 738, 415, 418, 427, 743,
+ 739, 744, 735, 733, 746, 731, 0, 731, 744, 733,
+
+ 729, 735, 730, 737, 0, 735, 732, 736, 720, 718,
+ 721, 727, 733, 728, 727, 715, 0, 717, 718, 0,
+ 0, 0, 0, 715, 718, 0, 712, 0, 725, 705,
+ 714, 709, 0, 702, 702, 715, 0, 717, 0, 431,
+ 730, 729, 728, 695, 694, 0, 711, 710, 705, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 694,
+ 707, 694, 691, 0, 0, 696, 695, 0, 692, 699,
+ 698, 0, 684, 0, 0, 0, 0, 681, 0, 0,
+ 680, 691, 434, 684, 690, 689, 686, 681, 678, 671,
+ 671, 684, 669, 681, 0, 0, 674, 697, 696, 695,
+
+ 662, 661, 427, 428, 0, 673, 676, 674, 663, 659,
+ 0, 671, 668, 667, 657, 656, 646, 663, 649, 441,
+ 657, 660, 0, 677, 676, 675, 642, 641, 0, 655,
+ 642, 0, 652, 645, 646, 649, 0, 0, 0, 0,
+ 669, 668, 0, 645, 648, 633, 640, 631, 638, 639,
+ 639, 638, 624, 451, 636, 0, 637, 626, 625, 0,
+ 0, 0, 650, 649, 648, 615, 614, 610, 618, 0,
+ 646, 645, 0, 622, 625, 0, 458, 0, 603, 612,
+ 0, 608, 607, 616, 616, 604, 618, 602, 616, 611,
+ 0, 0, 0, 628, 627, 626, 593, 592, 0, 592,
+
+ 0, 0, 434, 454, 616, 602, 605, 588, 600, 588,
+ 587, 596, 596, 613, 612, 611, 578, 577, 0, 577,
+ 578, 577, 587, 0, 590, 586, 588, 584, 571, 602,
+ 449, 0, 579, 582, 574, 566, 573, 564, 585, 573,
+ 569, 571, 569, 569, 568, 0, 556, 555, 565, 0,
+ 585, 462, 0, 562, 565, 0, 565, 564, 548, 540,
+ 548, 538, 546, 0, 543, 542, 563, 551, 549, 549,
+ 533, 536, 550, 534, 565, 545, 546, 543, 540, 550,
+ 527, 541, 540, 524, 523, 522, 543, 531, 529, 529,
+ 510, 509, 0, 537, 509, 535, 507, 511, 510, 541,
+
+ 521, 518, 0, 517, 520, 516, 518, 502, 499, 512,
+ 497, 498, 505, 499, 488, 487, 0, 493, 492, 523,
+ 503, 500, 0, 0, 0, 496, 0, 495, 0, 501,
+ 500, 484, 481, 482, 0, 474, 482, 472, 478, 499,
+ 478, 0, 0, 490, 489, 0, 0, 488, 487, 471,
+ 468, 469, 483, 482, 459, 458, 464, 0, 0, 485,
+ 457, 483, 475, 467, 453, 132, 161, 177, 215, 245,
+ 0, 0, 288, 289, 0, 0, 294, 315, 0, 316,
+ 306, 331, 0, 363, 402, 0, 0, 395, 383, 395,
+ 387, 433, 434, 0, 435, 420, 461, 427, 430, 431,
+
+ 0, 450, 452, 443, 0, 464, 0, 0, 0, 445,
+ 446, 440, 0, 441, 442, 0, 0, 0, 1017, 506,
+ 509, 512, 513, 514
+ } ;
+
+static yyconst flex_int16_t yy_def[825] =
+ { 0,
+ 819, 1, 819, 3, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 820, 819, 819,
+ 819, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 819, 819, 819, 819, 819, 819, 819, 821, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 822,
+ 819, 823, 20, 21, 819, 819, 824, 819, 819, 819,
+ 819, 819, 819, 819, 819, 820, 819, 819, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 819, 819, 821, 819, 819, 823, 819, 819, 819,
+ 819, 819, 824, 819, 819, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 819, 819,
+ 819, 819, 819, 819, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+
+ 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
+ 820, 820, 820, 820, 820, 820, 820, 820, 0, 819,
+ 819, 819, 819, 819
+ } ;
+
+static yyconst flex_int16_t yy_nxt[1090] =
+ { 0,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 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,
+ 29, 30, 31, 28, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 28, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 28, 28, 28, 52, 53,
+ 54, 55, 56, 57, 58, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 59,
+
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 56, 56, 56, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 56, 56, 56, 56, 61, 62, 63, 66, 68, 70,
+ 70, 70, 70, 70, 70, 70, 84, 85, 79, 150,
+ 123, 69, 67, 87, 124, 64, 72, 151, 73, 73,
+ 73, 73, 73, 73, 74, 80, 89, 81, 82, 784,
+ 92, 88, 93, 121, 95, 75, 94, 103, 96, 104,
+ 90, 91, 76, 77, 97, 99, 122, 98, 105, 100,
+
+ 115, 187, 75, 116, 101, 125, 117, 118, 152, 168,
+ 102, 119, 188, 169, 120, 785, 76, 128, 126, 77,
+ 72, 106, 74, 74, 74, 74, 74, 74, 74, 107,
+ 112, 108, 129, 207, 109, 130, 212, 132, 113, 75,
+ 110, 208, 213, 786, 133, 134, 76, 139, 135, 114,
+ 140, 236, 237, 153, 136, 137, 75, 138, 141, 147,
+ 143, 155, 156, 148, 144, 142, 158, 159, 145, 238,
+ 76, 146, 149, 160, 819, 267, 268, 239, 155, 156,
+ 161, 787, 161, 158, 159, 162, 162, 162, 162, 162,
+ 162, 162, 189, 227, 176, 254, 215, 160, 177, 178,
+
+ 819, 220, 229, 199, 788, 190, 200, 201, 228, 216,
+ 202, 217, 203, 240, 245, 230, 246, 221, 222, 254,
+ 249, 241, 249, 158, 159, 250, 250, 250, 250, 250,
+ 250, 250, 298, 299, 300, 789, 790, 251, 791, 251,
+ 158, 159, 252, 252, 252, 252, 252, 252, 252, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 261, 312, 330, 792, 793, 313, 337,
+ 338, 339, 794, 331, 253, 795, 262, 250, 250, 250,
+ 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
+ 250, 253, 252, 252, 252, 252, 252, 252, 252, 348,
+
+ 349, 350, 156, 252, 252, 252, 252, 252, 252, 252,
+ 360, 361, 362, 368, 369, 370, 372, 373, 374, 156,
+ 796, 159, 383, 384, 385, 421, 422, 423, 441, 442,
+ 443, 451, 452, 453, 454, 455, 456, 797, 159, 798,
+ 799, 444, 445, 457, 458, 459, 498, 499, 500, 524,
+ 525, 526, 800, 801, 546, 548, 563, 564, 565, 501,
+ 502, 636, 527, 528, 547, 549, 594, 595, 596, 566,
+ 567, 637, 568, 614, 615, 616, 666, 802, 803, 597,
+ 598, 638, 804, 667, 805, 668, 617, 618, 639, 686,
+ 640, 641, 806, 807, 808, 809, 687, 810, 688, 811,
+
+ 812, 813, 814, 815, 816, 817, 818, 86, 86, 86,
+ 154, 154, 154, 70, 157, 163, 163, 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, 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, 706, 705, 704, 703, 702, 701,
+
+ 700, 699, 698, 697, 696, 695, 694, 693, 692, 691,
+ 690, 689, 685, 684, 683, 682, 681, 680, 679, 678,
+ 677, 676, 675, 674, 673, 672, 671, 670, 669, 665,
+ 664, 663, 662, 661, 660, 659, 658, 657, 656, 655,
+ 654, 653, 652, 651, 650, 649, 648, 647, 646, 645,
+ 644, 643, 642, 635, 634, 633, 632, 631, 630, 629,
+ 628, 627, 626, 625, 624, 623, 622, 621, 620, 619,
+ 613, 612, 611, 610, 609, 608, 607, 606, 605, 604,
+ 603, 602, 601, 600, 599, 593, 592, 591, 590, 589,
+ 588, 587, 586, 585, 584, 583, 582, 581, 580, 579,
+
+ 578, 577, 576, 575, 574, 573, 572, 571, 570, 569,
+ 562, 561, 560, 559, 558, 557, 556, 555, 554, 553,
+ 552, 551, 550, 545, 544, 543, 542, 541, 540, 539,
+ 538, 537, 536, 535, 534, 533, 532, 531, 530, 529,
+ 523, 522, 521, 520, 519, 518, 517, 516, 515, 514,
+ 513, 512, 511, 510, 509, 508, 507, 506, 505, 504,
+ 503, 497, 496, 495, 494, 493, 492, 491, 490, 489,
+ 488, 487, 486, 485, 484, 483, 482, 481, 480, 479,
+ 478, 477, 476, 475, 474, 473, 472, 471, 470, 469,
+ 468, 467, 466, 465, 464, 463, 462, 461, 460, 450,
+
+ 449, 448, 447, 446, 440, 439, 438, 437, 436, 435,
+ 434, 433, 432, 431, 430, 429, 428, 427, 426, 425,
+ 424, 420, 419, 418, 417, 416, 415, 414, 413, 412,
+ 411, 410, 409, 408, 407, 406, 405, 404, 403, 402,
+ 401, 400, 399, 398, 397, 396, 395, 394, 393, 392,
+ 391, 390, 389, 388, 387, 386, 382, 381, 380, 379,
+ 378, 377, 376, 375, 371, 367, 366, 365, 364, 363,
+ 359, 358, 357, 356, 355, 354, 353, 352, 351, 347,
+ 346, 345, 344, 343, 342, 341, 340, 336, 335, 334,
+ 333, 332, 329, 328, 327, 326, 325, 324, 323, 322,
+
+ 321, 320, 319, 318, 317, 316, 315, 314, 311, 310,
+ 309, 308, 307, 306, 305, 304, 303, 302, 301, 297,
+ 296, 295, 294, 293, 292, 291, 290, 289, 288, 287,
+ 286, 285, 284, 283, 282, 281, 280, 279, 278, 277,
+ 276, 275, 274, 273, 272, 271, 270, 269, 266, 265,
+ 264, 263, 260, 259, 258, 257, 256, 255, 248, 247,
+ 244, 243, 242, 235, 234, 233, 232, 231, 226, 225,
+ 224, 223, 219, 218, 214, 211, 210, 209, 206, 205,
+ 204, 198, 197, 196, 195, 194, 193, 192, 191, 186,
+ 185, 184, 183, 182, 181, 180, 179, 175, 174, 173,
+
+ 172, 171, 170, 167, 166, 165, 164, 131, 127, 111,
+ 83, 78, 71, 65, 60, 819, 5, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819
+ } ;
+
+static yyconst flex_int16_t yy_chk[1090] =
+ { 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, 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, 26, 26, 24, 51,
+ 42, 17, 15, 31, 42, 11, 20, 51, 20, 20,
+ 20, 20, 20, 20, 20, 24, 32, 24, 24, 766,
+ 33, 31, 33, 41, 34, 20, 33, 36, 34, 36,
+ 32, 32, 20, 20, 34, 35, 41, 34, 36, 35,
+
+ 40, 107, 20, 40, 35, 43, 40, 40, 53, 91,
+ 35, 40, 107, 91, 40, 767, 20, 45, 43, 20,
+ 21, 37, 21, 21, 21, 21, 21, 21, 21, 37,
+ 39, 37, 45, 122, 37, 45, 126, 47, 39, 21,
+ 37, 122, 126, 768, 47, 47, 21, 48, 47, 39,
+ 48, 143, 143, 53, 47, 47, 21, 47, 48, 50,
+ 49, 70, 70, 50, 49, 48, 72, 72, 49, 144,
+ 21, 49, 50, 73, 73, 178, 178, 144, 70, 70,
+ 75, 769, 75, 72, 72, 75, 75, 75, 75, 75,
+ 75, 75, 108, 136, 98, 163, 128, 73, 98, 98,
+
+ 73, 131, 137, 118, 770, 108, 118, 118, 136, 128,
+ 118, 128, 118, 145, 149, 137, 149, 131, 131, 163,
+ 155, 145, 155, 157, 157, 155, 155, 155, 155, 155,
+ 155, 155, 209, 209, 209, 773, 774, 158, 777, 158,
+ 157, 157, 158, 158, 158, 158, 158, 158, 158, 161,
+ 161, 161, 161, 161, 161, 161, 162, 162, 162, 162,
+ 162, 162, 162, 173, 221, 238, 778, 780, 221, 244,
+ 244, 244, 781, 238, 162, 782, 173, 249, 249, 249,
+ 249, 249, 249, 249, 250, 250, 250, 250, 250, 250,
+ 250, 162, 251, 251, 251, 251, 251, 251, 251, 260,
+
+ 260, 260, 250, 252, 252, 252, 252, 252, 252, 252,
+ 272, 272, 272, 281, 281, 281, 285, 285, 285, 250,
+ 784, 252, 294, 294, 294, 335, 335, 335, 376, 376,
+ 376, 387, 387, 387, 388, 388, 388, 785, 252, 788,
+ 789, 376, 376, 389, 389, 389, 440, 440, 440, 483,
+ 483, 483, 790, 791, 503, 504, 520, 520, 520, 440,
+ 440, 603, 483, 483, 503, 504, 554, 554, 554, 520,
+ 520, 603, 520, 577, 577, 577, 631, 792, 793, 554,
+ 554, 604, 795, 631, 796, 631, 577, 577, 604, 652,
+ 604, 604, 797, 798, 799, 800, 652, 802, 652, 803,
+
+ 804, 806, 810, 811, 812, 814, 815, 820, 820, 820,
+ 821, 821, 821, 822, 823, 824, 824, 765, 764, 763,
+ 762, 761, 760, 757, 756, 755, 754, 753, 752, 751,
+ 750, 749, 748, 745, 744, 741, 740, 739, 738, 737,
+ 736, 734, 733, 732, 731, 730, 728, 726, 722, 721,
+ 720, 719, 718, 716, 715, 714, 713, 712, 711, 710,
+ 709, 708, 707, 706, 705, 704, 702, 701, 700, 699,
+ 698, 697, 696, 695, 694, 692, 691, 690, 689, 688,
+ 687, 686, 685, 684, 683, 682, 681, 680, 679, 678,
+ 677, 676, 675, 674, 673, 672, 671, 670, 669, 668,
+
+ 667, 666, 665, 663, 662, 661, 660, 659, 658, 657,
+ 655, 654, 651, 649, 648, 647, 645, 644, 643, 642,
+ 641, 640, 639, 638, 637, 636, 635, 634, 633, 630,
+ 629, 628, 627, 626, 625, 623, 622, 621, 620, 618,
+ 617, 616, 615, 614, 613, 612, 611, 610, 609, 608,
+ 607, 606, 605, 600, 598, 597, 596, 595, 594, 590,
+ 589, 588, 587, 586, 585, 584, 583, 582, 580, 579,
+ 575, 574, 572, 571, 569, 568, 567, 566, 565, 564,
+ 563, 559, 558, 557, 555, 553, 552, 551, 550, 549,
+ 548, 547, 546, 545, 544, 542, 541, 536, 535, 534,
+
+ 533, 531, 530, 528, 527, 526, 525, 524, 522, 521,
+ 519, 518, 517, 516, 515, 514, 513, 512, 510, 509,
+ 508, 507, 506, 502, 501, 500, 499, 498, 497, 494,
+ 493, 492, 491, 490, 489, 488, 487, 486, 485, 484,
+ 482, 481, 478, 473, 471, 470, 469, 467, 466, 463,
+ 462, 461, 460, 449, 448, 447, 445, 444, 443, 442,
+ 441, 438, 436, 435, 434, 432, 431, 430, 429, 427,
+ 425, 424, 419, 418, 416, 415, 414, 413, 412, 411,
+ 410, 409, 408, 407, 406, 404, 403, 402, 401, 400,
+ 399, 398, 396, 395, 394, 393, 392, 391, 390, 386,
+
+ 382, 381, 380, 377, 375, 365, 363, 359, 358, 357,
+ 356, 354, 353, 351, 346, 345, 344, 343, 342, 341,
+ 336, 334, 333, 332, 331, 330, 328, 327, 324, 323,
+ 322, 321, 320, 319, 318, 317, 316, 315, 314, 313,
+ 312, 311, 310, 309, 308, 307, 306, 305, 304, 303,
+ 302, 301, 300, 299, 298, 295, 293, 292, 291, 290,
+ 289, 288, 287, 286, 284, 280, 278, 277, 276, 275,
+ 271, 270, 269, 268, 267, 266, 265, 264, 263, 259,
+ 257, 256, 255, 248, 247, 246, 245, 243, 242, 241,
+ 240, 239, 237, 236, 235, 234, 233, 232, 231, 230,
+
+ 229, 228, 227, 226, 225, 224, 223, 222, 220, 219,
+ 218, 217, 216, 215, 214, 213, 212, 211, 210, 208,
+ 207, 206, 205, 204, 203, 202, 201, 200, 199, 198,
+ 197, 196, 195, 194, 193, 192, 190, 189, 188, 187,
+ 186, 185, 184, 183, 182, 181, 180, 179, 177, 176,
+ 175, 174, 172, 171, 170, 169, 168, 166, 151, 150,
+ 148, 147, 146, 142, 141, 140, 139, 138, 135, 134,
+ 133, 132, 130, 129, 127, 125, 124, 123, 121, 120,
+ 119, 117, 116, 114, 113, 112, 111, 110, 109, 106,
+ 105, 104, 103, 102, 101, 100, 99, 97, 96, 95,
+
+ 94, 93, 92, 90, 89, 85, 81, 46, 44, 38,
+ 25, 22, 19, 14, 9, 5, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[241] =
+ { 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/translator/glslang.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/length_limits.h"
+#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_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 uint_constant(TParseContext *context);
+static int int_constant(TParseContext *context);
+static int float_constant(yyscan_t yyscanner);
+static int floatsuffix_check(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;
+ yy_size_t yy_n_chars;
+ yy_size_t 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 );
+
+yy_size_t 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 yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst 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
+#define YY_READ_BUF_SIZE 8192
+#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, 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 = '*'; \
+ size_t 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 = fread(buf, 1, 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 break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register 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 ( 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
+ {
+ register 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 >= 820 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 819 );
+ 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] )
+ {
+ yy_size_t 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_keyword_ES3_reserved(context, VARYING); }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return BREAK; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return CONTINUE; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return DO; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return FOR; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return WHILE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return IF; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return ELSE; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SWITCH); }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CASE); }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, DEFAULT); }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CENTROID); }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, FLAT); }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SMOOTH); }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return IN_QUAL; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ return OUT_QUAL; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ return INOUT_QUAL; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ return FLOAT_TYPE; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ return INT_TYPE; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UINT_TYPE); }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ return VOID_TYPE; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ return BOOL_TYPE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ yylval->lex.b = true; return BOOLCONSTANT; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ yylval->lex.b = false; return BOOLCONSTANT; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ return DISCARD; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ return RETURN; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ return MATRIX2; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ return MATRIX3; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ return MATRIX4; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2); }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3); }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4); }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x3); }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x2); }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x4); }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x2); }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x4); }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x3); }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ return VEC2; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return VEC3; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return VEC4; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ return IVEC2; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ return IVEC3; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ return IVEC4; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return BVEC2; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ return BVEC3; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ return BVEC4; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC2); }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC3); }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC4); }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ return SAMPLER2D; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ return SAMPLERCUBE; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ return SAMPLER_EXTERNAL_OES; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3D); }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ return SAMPLER2DRECT; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2D); }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER3D); }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2D); }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER3D); }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLERCUBE); }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ return STRUCT; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, LAYOUT); }
+ YY_BREAK
+/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
+case 79:
+case 80:
+case 81:
+case 82:
+case 83:
+case 84:
+case 85:
+case 86:
+case 87:
+case 88:
+case 89:
+case 90:
+case 91:
+case 92:
+case 93:
+case 94:
+case 95:
+case 96:
+case 97:
+case 98:
+case 99:
+case 100:
+case 101:
+case 102:
+case 103:
+case 104:
+case 105:
+case 106:
+case 107:
+case 108:
+case 109:
+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:
+YY_RULE_SETUP
+{
+ if (context->getShaderVersion() < 300) {
+ yylval->lex.string = NewPoolTString(yytext);
+ 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 135:
+YY_RULE_SETUP
+{
+ if (context->getShaderVersion() >= 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return reserved_word(yyscanner);
+}
+ YY_BREAK
+/* Reserved keywords */
+case 136:
+case 137:
+case 138:
+case 139:
+case 140:
+case 141:
+case 142:
+case 143:
+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:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 177:
+YY_RULE_SETUP
+{
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+ YY_BREAK
+case 178:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 179:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 180:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 181:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 182:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 183:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 184:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 185:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 186:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 187:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 188:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 189:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 190:
+YY_RULE_SETUP
+{ return ADD_ASSIGN; }
+ YY_BREAK
+case 191:
+YY_RULE_SETUP
+{ return SUB_ASSIGN; }
+ YY_BREAK
+case 192:
+YY_RULE_SETUP
+{ return MUL_ASSIGN; }
+ YY_BREAK
+case 193:
+YY_RULE_SETUP
+{ return DIV_ASSIGN; }
+ YY_BREAK
+case 194:
+YY_RULE_SETUP
+{ return MOD_ASSIGN; }
+ YY_BREAK
+case 195:
+YY_RULE_SETUP
+{ return LEFT_ASSIGN; }
+ YY_BREAK
+case 196:
+YY_RULE_SETUP
+{ return RIGHT_ASSIGN; }
+ YY_BREAK
+case 197:
+YY_RULE_SETUP
+{ return AND_ASSIGN; }
+ YY_BREAK
+case 198:
+YY_RULE_SETUP
+{ return XOR_ASSIGN; }
+ YY_BREAK
+case 199:
+YY_RULE_SETUP
+{ return OR_ASSIGN; }
+ YY_BREAK
+case 200:
+YY_RULE_SETUP
+{ return INC_OP; }
+ YY_BREAK
+case 201:
+YY_RULE_SETUP
+{ return DEC_OP; }
+ YY_BREAK
+case 202:
+YY_RULE_SETUP
+{ return AND_OP; }
+ YY_BREAK
+case 203:
+YY_RULE_SETUP
+{ return OR_OP; }
+ YY_BREAK
+case 204:
+YY_RULE_SETUP
+{ return XOR_OP; }
+ YY_BREAK
+case 205:
+YY_RULE_SETUP
+{ return LE_OP; }
+ YY_BREAK
+case 206:
+YY_RULE_SETUP
+{ return GE_OP; }
+ YY_BREAK
+case 207:
+YY_RULE_SETUP
+{ return EQ_OP; }
+ YY_BREAK
+case 208:
+YY_RULE_SETUP
+{ return NE_OP; }
+ YY_BREAK
+case 209:
+YY_RULE_SETUP
+{ return LEFT_OP; }
+ YY_BREAK
+case 210:
+YY_RULE_SETUP
+{ return RIGHT_OP; }
+ YY_BREAK
+case 211:
+YY_RULE_SETUP
+{ return SEMICOLON; }
+ YY_BREAK
+case 212:
+YY_RULE_SETUP
+{ return LEFT_BRACE; }
+ YY_BREAK
+case 213:
+YY_RULE_SETUP
+{ return RIGHT_BRACE; }
+ YY_BREAK
+case 214:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 215:
+YY_RULE_SETUP
+{ return COLON; }
+ YY_BREAK
+case 216:
+YY_RULE_SETUP
+{ return EQUAL; }
+ YY_BREAK
+case 217:
+YY_RULE_SETUP
+{ return LEFT_PAREN; }
+ YY_BREAK
+case 218:
+YY_RULE_SETUP
+{ return RIGHT_PAREN; }
+ YY_BREAK
+case 219:
+YY_RULE_SETUP
+{ return LEFT_BRACKET; }
+ YY_BREAK
+case 220:
+YY_RULE_SETUP
+{ return RIGHT_BRACKET; }
+ YY_BREAK
+case 221:
+YY_RULE_SETUP
+{ BEGIN(FIELDS); return DOT; }
+ YY_BREAK
+case 222:
+YY_RULE_SETUP
+{ return BANG; }
+ YY_BREAK
+case 223:
+YY_RULE_SETUP
+{ return DASH; }
+ YY_BREAK
+case 224:
+YY_RULE_SETUP
+{ return TILDE; }
+ YY_BREAK
+case 225:
+YY_RULE_SETUP
+{ return PLUS; }
+ YY_BREAK
+case 226:
+YY_RULE_SETUP
+{ return STAR; }
+ YY_BREAK
+case 227:
+YY_RULE_SETUP
+{ return SLASH; }
+ YY_BREAK
+case 228:
+YY_RULE_SETUP
+{ return PERCENT; }
+ YY_BREAK
+case 229:
+YY_RULE_SETUP
+{ return LEFT_ANGLE; }
+ YY_BREAK
+case 230:
+YY_RULE_SETUP
+{ return RIGHT_ANGLE; }
+ YY_BREAK
+case 231:
+YY_RULE_SETUP
+{ return VERTICAL_BAR; }
+ YY_BREAK
+case 232:
+YY_RULE_SETUP
+{ return CARET; }
+ YY_BREAK
+case 233:
+YY_RULE_SETUP
+{ return AMPERSAND; }
+ YY_BREAK
+case 234:
+YY_RULE_SETUP
+{ return QUESTION; }
+ YY_BREAK
+case 235:
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ yylval->lex.string = NewPoolTString(yytext);
+ return FIELD_SELECTION;
+}
+ YY_BREAK
+case 236:
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 237:
+YY_RULE_SETUP
+{
+ yyextra->error(*yylloc, "Illegal character at fieldname start", yytext, "");
+ return 0;
+}
+ YY_BREAK
+case 238:
+/* rule 238 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(FIELDS):
+{ yyterminate(); }
+ YY_BREAK
+case 239:
+YY_RULE_SETUP
+{ assert(false); return 0; }
+ YY_BREAK
+case 240:
+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;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register 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
+ {
+ yy_size_t 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 )
+ {
+ yy_size_t 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,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ 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. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ 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 ((yy_size_t) (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. */
+ yy_size_t 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,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ 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)
+{
+ register yy_state_type yy_current_state;
+ register 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 )
+ {
+ register 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 >= 820 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) 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)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register 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 >= 820 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 819);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#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 */
+ yy_size_t offset = 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 EOF;
+
+ 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(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;
+ 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. */
+ int 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 0;
+
+ 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 = 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 = 0;
+ 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 (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes(yystr,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 (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _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 yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) 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.
+ */
+yy_size_t 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
+ * @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 line_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 = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ 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 = (FILE *) 0;
+ yyout = (FILE *) 0;
+#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, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* 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 (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ 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) {
+ pp::Token token;
+ yyget_extra(yyscanner)->getPreprocessor().lex(&token);
+ yy_size_t len = token.type == 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;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ 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_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 = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+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 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.
+ 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(iter->first.c_str(), 1);
+ }
+ if (context->getFragmentPrecisionHigh())
+ preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ preprocessor->setMaxTokenSize(GetGlobalMaxTokenSize(context->getShaderSpec()));
+
+ return 0;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.cpp
new file mode 100644
index 000000000..3e50fbc4b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.cpp
@@ -0,0 +1,4917 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
+
+/* 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/Cache.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ParseContext.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+
+
+
+# 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
+
+
+
+/* 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,
+ VARYING = 299,
+ MATRIX2x3 = 300,
+ MATRIX3x2 = 301,
+ MATRIX2x4 = 302,
+ MATRIX4x2 = 303,
+ MATRIX3x4 = 304,
+ MATRIX4x3 = 305,
+ CENTROID = 306,
+ FLAT = 307,
+ SMOOTH = 308,
+ STRUCT = 309,
+ VOID_TYPE = 310,
+ WHILE = 311,
+ SAMPLER2D = 312,
+ SAMPLERCUBE = 313,
+ SAMPLER_EXTERNAL_OES = 314,
+ SAMPLER2DRECT = 315,
+ SAMPLER2DARRAY = 316,
+ ISAMPLER2D = 317,
+ ISAMPLER3D = 318,
+ ISAMPLERCUBE = 319,
+ ISAMPLER2DARRAY = 320,
+ USAMPLER2D = 321,
+ USAMPLER3D = 322,
+ USAMPLERCUBE = 323,
+ USAMPLER2DARRAY = 324,
+ SAMPLER3D = 325,
+ SAMPLER3DRECT = 326,
+ SAMPLER2DSHADOW = 327,
+ SAMPLERCUBESHADOW = 328,
+ SAMPLER2DARRAYSHADOW = 329,
+ LAYOUT = 330,
+ IDENTIFIER = 331,
+ TYPE_NAME = 332,
+ FLOATCONSTANT = 333,
+ INTCONSTANT = 334,
+ UINTCONSTANT = 335,
+ BOOLCONSTANT = 336,
+ FIELD_SELECTION = 337,
+ LEFT_OP = 338,
+ RIGHT_OP = 339,
+ INC_OP = 340,
+ DEC_OP = 341,
+ LE_OP = 342,
+ GE_OP = 343,
+ EQ_OP = 344,
+ NE_OP = 345,
+ AND_OP = 346,
+ OR_OP = 347,
+ XOR_OP = 348,
+ MUL_ASSIGN = 349,
+ DIV_ASSIGN = 350,
+ ADD_ASSIGN = 351,
+ MOD_ASSIGN = 352,
+ LEFT_ASSIGN = 353,
+ RIGHT_ASSIGN = 354,
+ AND_ASSIGN = 355,
+ XOR_ASSIGN = 356,
+ OR_ASSIGN = 357,
+ SUB_ASSIGN = 358,
+ LEFT_PAREN = 359,
+ RIGHT_PAREN = 360,
+ LEFT_BRACKET = 361,
+ RIGHT_BRACKET = 362,
+ LEFT_BRACE = 363,
+ RIGHT_BRACE = 364,
+ DOT = 365,
+ COMMA = 366,
+ COLON = 367,
+ EQUAL = 368,
+ SEMICOLON = 369,
+ BANG = 370,
+ DASH = 371,
+ TILDE = 372,
+ PLUS = 373,
+ STAR = 374,
+ SLASH = 375,
+ PERCENT = 376,
+ LEFT_ANGLE = 377,
+ RIGHT_ANGLE = 378,
+ VERTICAL_BAR = 379,
+ CARET = 380,
+ AMPERSAND = 381,
+ QUESTION = 382
+ };
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ TIntermBlock* intermBlock;
+ TIntermSwitch* intermSwitch;
+ TIntermCase* intermCase;
+ };
+ union {
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ 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) { \
+ if (context->getShaderType() != GL_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->getShaderType() != GL_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ } \
+}
+
+#define COMPUTE_ONLY(S, L) { \
+ if (context->getShaderType() != GL_COMPUTE_SHADER) { \
+ context->error(L, " supported in compute shaders only ", S); \
+ } \
+}
+
+#define NON_COMPUTE_ONLY(S, L) { \
+ if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \
+ context->error(L, " supported in vertex and fragment shaders only ", S); \
+ } \
+}
+
+#define ES2_ONLY(S, L) { \
+ if (context->getShaderVersion() != 100) { \
+ context->error(L, " supported in GLSL ES 1.00 only ", S); \
+ } \
+}
+
+#define ES3_OR_NEWER(TOKEN, LINE, REASON) { \
+ if (context->getShaderVersion() < 300) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.00 and above only ", TOKEN); \
+ } \
+}
+
+#define ES3_1_ONLY(TOKEN, LINE, REASON) { \
+ if (context->getShaderVersion() != 310) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.10 only ", TOKEN); \
+ } \
+}
+
+
+
+#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 109
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2432
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 128
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 94
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 269
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 405
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 382
+
+#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
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 237, 237, 238, 241, 251, 254, 259, 264, 269,
+ 274, 280, 283, 286, 289, 292, 295, 301, 308, 319,
+ 323, 331, 334, 340, 344, 351, 357, 366, 374, 380,
+ 386, 395, 398, 401, 404, 414, 415, 416, 417, 425,
+ 426, 429, 432, 439, 440, 443, 449, 450, 454, 461,
+ 462, 465, 468, 471, 477, 478, 481, 487, 488, 495,
+ 496, 503, 504, 511, 512, 518, 519, 525, 526, 532,
+ 533, 539, 540, 547, 548, 549, 550, 554, 555, 556,
+ 560, 564, 568, 572, 579, 582, 588, 595, 602, 605,
+ 611, 620, 624, 628, 632, 636, 643, 650, 653, 660,
+ 668, 688, 698, 706, 731, 735, 739, 743, 750, 757,
+ 760, 764, 768, 773, 778, 785, 789, 793, 797, 802,
+ 807, 814, 824, 830, 833, 839, 843, 850, 856, 863,
+ 867, 870, 873, 882, 888, 896, 899, 919, 938, 945,
+ 949, 956, 966, 969, 972, 978, 985, 988, 994, 997,
+ 1000, 1006, 1009, 1014, 1025, 1028, 1031, 1034, 1037, 1040,
+ 1044, 1048, 1052, 1056, 1060, 1064, 1068, 1072, 1076, 1080,
+ 1084, 1088, 1092, 1096, 1100, 1104, 1108, 1112, 1116, 1120,
+ 1124, 1127, 1130, 1133, 1136, 1139, 1142, 1145, 1148, 1151,
+ 1154, 1157, 1160, 1163, 1166, 1169, 1176, 1182, 1185, 1197,
+ 1197, 1200, 1200, 1206, 1209, 1224, 1227, 1234, 1238, 1244,
+ 1250, 1262, 1266, 1270, 1271, 1277, 1278, 1279, 1280, 1281,
+ 1282, 1283, 1287, 1288, 1288, 1288, 1297, 1298, 1302, 1302,
+ 1303, 1303, 1308, 1311, 1320, 1325, 1332, 1333, 1337, 1344,
+ 1348, 1355, 1355, 1362, 1365, 1372, 1376, 1389, 1389, 1394,
+ 1394, 1400, 1400, 1408, 1411, 1417, 1420, 1426, 1430, 1437,
+ 1440, 1443, 1446, 1449, 1458, 1464, 1470, 1473, 1479, 1479
+};
+#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",
+ "VARYING", "MATRIX2x3", "MATRIX3x2", "MATRIX2x4", "MATRIX4x2",
+ "MATRIX3x4", "MATRIX4x3", "CENTROID", "FLAT", "SMOOTH", "STRUCT",
+ "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", "SAMPLER_EXTERNAL_OES",
+ "SAMPLER2DRECT", "SAMPLER2DARRAY", "ISAMPLER2D", "ISAMPLER3D",
+ "ISAMPLERCUBE", "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D",
+ "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER3D", "SAMPLER3DRECT",
+ "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", "SAMPLER2DARRAYSHADOW", "LAYOUT",
+ "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", "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", "$@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
+};
+# endif
+
+#define YYPACT_NINF -348
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-348)))
+
+#define YYTABLE_NINF -229
+
+#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[] =
+{
+ 2144, -348, -348, -348, -348, 144, -348, -348, -348, -348,
+ -348, -348, -348, -348, -348, -348, -348, -348, -348, -348,
+ -348, -348, -348, -348, -348, -348, -348, -348, -348, -348,
+ -348, -348, -348, -348, -348, -348, -348, -348, -348, -348,
+ -348, -53, -348, -348, -348, -348, -348, -348, -348, -348,
+ -348, -348, -348, -348, -348, -348, -348, -348, -348, -348,
+ -83, -348, -348, -89, -70, -81, 2219, -26, -348, 60,
+ -348, 1163, -348, -348, -348, -348, -348, -348, -348, -66,
+ -348, 2069, -348, -348, 2355, -348, -348, -348, -41, -2,
+ -348, -30, -348, 2219, -348, -348, -348, 2219, 80, 80,
+ -348, -17, -75, -65, -348, 2219, -348, -348, 1233, -348,
+ -348, -15, 2219, -348, -10, -85, -348, 389, -348, -348,
+ -348, -348, 1, -49, -348, 1331, 1622, -348, -348, 2219,
+ 80, 1814, -348, 19, -348, -348, -348, -348, -348, 1622,
+ 1622, 1622, -348, -348, -348, -348, -348, -348, -348, -24,
+ -348, -348, -348, 37, -22, 1717, 67, -348, 1622, 34,
+ 14, 76, -46, 72, 51, 75, 78, 112, 113, -77,
+ -348, 98, -348, -348, 1899, 2219, 84, -348, -2, 94,
+ 97, -348, 108, 109, 100, 1429, 114, 1622, 104, 115,
+ 111, -348, -348, 190, -348, -348, -19, -348, -89, 117,
+ -348, -348, -348, -348, 505, -348, -348, -348, -348, -348,
+ -348, 1622, 1524, 1622, 116, 110, -348, -348, 80, 118,
+ 27, -348, -58, -348, -348, -348, -5, -348, -348, 1622,
+ 2287, -348, -348, 1622, 121, -348, -348, -348, 1622, 1622,
+ 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622,
+ 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, -348, -348,
+ 1984, -348, -348, -348, -348, -348, 119, -348, 1622, -348,
+ -348, 32, 1622, 122, -348, -348, -348, 621, -348, -348,
+ -348, -348, -348, -348, -348, -348, -348, -348, -348, 1622,
+ 1622, -348, -348, -348, 124, 120, 129, -348, 1622, 125,
+ 33, 1622, 80, -348, -87, -348, -348, 130, 128, -348,
+ 136, -348, -348, -348, -348, -348, 34, 34, 14, 14,
+ 76, 76, 76, 76, -46, -46, 72, 51, 75, 78,
+ 112, 113, 54, -348, 166, -30, 853, 969, -3, -348,
+ -1, -348, 1066, 621, -348, -348, -348, 1622, 132, -348,
+ 1622, -348, 135, -348, 1622, -348, -348, 1622, 139, -348,
+ -348, -348, -348, 1066, 119, -348, 128, 80, 2219, 141,
+ 140, -348, 1622, -348, -348, 145, -348, 1622, -348, 134,
+ 146, 236, -348, 147, 143, 737, -348, -348, 148, 17,
+ 1622, 737, 119, -348, 1622, -348, -348, -348, -348, 149,
+ 128, -348, -348, -348, -348
+};
+
+ /* 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, 127, 142, 143, 144, 0, 133, 135, 158, 155,
+ 156, 157, 162, 163, 164, 165, 166, 167, 159, 160,
+ 161, 168, 169, 170, 171, 172, 173, 136, 137, 138,
+ 140, 134, 174, 175, 176, 177, 178, 179, 139, 124,
+ 123, 0, 154, 180, 182, 195, 196, 183, 184, 185,
+ 186, 187, 188, 189, 190, 191, 181, 192, 193, 194,
+ 0, 198, 267, 268, 0, 98, 97, 0, 109, 115,
+ 131, 0, 132, 125, 128, 121, 130, 129, 141, 151,
+ 197, 0, 264, 266, 0, 2, 3, 201, 0, 0,
+ 88, 0, 96, 0, 105, 99, 107, 0, 108, 0,
+ 89, 2, 116, 0, 94, 0, 126, 122, 0, 1,
+ 265, 0, 0, 199, 148, 0, 146, 0, 269, 100,
+ 104, 106, 102, 110, 101, 0, 0, 87, 95, 0,
+ 0, 0, 203, 4, 8, 6, 7, 9, 30, 0,
+ 0, 0, 152, 37, 36, 38, 35, 5, 11, 31,
+ 13, 18, 19, 0, 0, 24, 0, 39, 0, 43,
+ 46, 49, 54, 57, 59, 61, 63, 65, 67, 69,
+ 86, 0, 28, 90, 0, 0, 0, 145, 0, 0,
+ 0, 249, 0, 0, 0, 0, 0, 0, 0, 0,
+ 223, 232, 236, 39, 71, 84, 0, 212, 0, 141,
+ 215, 234, 214, 213, 0, 216, 217, 218, 219, 220,
+ 221, 0, 0, 0, 0, 0, 211, 120, 0, 209,
+ 0, 207, 0, 204, 32, 33, 0, 15, 16, 0,
+ 0, 22, 21, 0, 154, 25, 27, 34, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 153, 202,
+ 0, 149, 150, 147, 260, 259, 230, 251, 0, 263,
+ 261, 0, 0, 0, 244, 247, 222, 0, 74, 75,
+ 77, 76, 79, 80, 81, 82, 83, 78, 73, 0,
+ 0, 237, 233, 235, 0, 0, 0, 114, 0, 117,
+ 0, 0, 0, 205, 0, 91, 10, 0, 17, 29,
+ 14, 20, 26, 40, 41, 42, 45, 44, 47, 48,
+ 52, 53, 50, 51, 55, 56, 58, 60, 62, 64,
+ 66, 68, 0, 200, 0, 0, 0, 0, 0, 262,
+ 0, 243, 0, 224, 72, 85, 103, 0, 111, 118,
+ 0, 206, 0, 208, 0, 92, 12, 0, 0, 229,
+ 231, 254, 253, 256, 230, 241, 245, 0, 0, 0,
+ 0, 112, 0, 119, 210, 0, 70, 0, 255, 0,
+ 0, 240, 238, 0, 0, 0, 225, 113, 0, 0,
+ 257, 0, 230, 242, 0, 227, 248, 226, 93, 0,
+ 258, 252, 239, 246, 250
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -348, -40, -348, -348, -348, -348, -348, -348, 28, -348,
+ -348, -348, -348, -60, -348, -72, -71, -127, -52, 8,
+ 12, 16, 7, 10, 11, -348, -86, -122, -348, -133,
+ -78, -348, 9, 13, -348, -348, -348, 169, 177, 174,
+ -348, -348, -326, -348, -59, -348, -69, -348, -61, 268,
+ -348, -348, 96, 0, -348, -348, -348, -348, -100, -120,
+ 57, -23, -140, -57, -198, -322, -105, -348, -348, -110,
+ -347, -348, -348, -88, 5, -42, -348, -348, -348, -348,
+ -348, -67, -348, -348, -348, -348, -348, -348, -348, -348,
+ -348, 216, -348, -348
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 219, 147, 148, 149, 307, 150, 151, 152, 153,
+ 154, 155, 156, 193, 158, 159, 160, 161, 162, 163,
+ 164, 165, 166, 167, 168, 169, 194, 195, 289, 196,
+ 171, 105, 197, 198, 64, 65, 66, 94, 95, 96,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 115, 116, 172, 79, 80, 175, 112, 131, 132,
+ 220, 221, 217, 200, 201, 202, 203, 277, 370, 396,
+ 334, 335, 336, 397, 204, 205, 206, 382, 207, 383,
+ 208, 369, 209, 342, 266, 337, 363, 379, 380, 210,
+ 81, 82, 83, 91
+};
+
+ /* 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[] =
+{
+ 78, 88, 106, 118, 216, 98, 293, 97, 226, 62,
+ 107, 223, 174, 63, 360, 256, 367, 381, 304, 354,
+ 177, 89, 170, 85, 86, 90, 178, 355, 106, 102,
+ 93, 125, 98, 235, 97, 92, 98, 367, 126, 170,
+ 108, 245, 246, 127, 130, 402, 129, 215, 157, 128,
+ 257, 130, 271, 129, 223, 87, 305, 212, 122, 123,
+ 106, 227, 228, 395, 213, 157, 78, 113, 218, 395,
+ 130, 78, 129, 297, 114, 260, 247, 248, 117, 224,
+ 225, 78, 229, 232, 111, 99, 230, 124, 100, 233,
+ 62, 216, 290, 78, 63, 291, 308, 78, 237, 173,
+ 306, 170, 364, 176, 365, 78, 290, 211, 290, 273,
+ 290, 312, 78, 130, 130, 129, 129, 199, 320, 321,
+ 322, 323, 399, -29, 332, 170, 170, 157, 290, 78,
+ 241, 78, 242, 294, 296, 338, 101, 86, 302, 340,
+ 223, 303, 231, 290, 302, 293, 339, 351, 2, 3,
+ 4, 157, 157, 238, 239, 240, 85, 86, 349, 243,
+ 244, 249, 250, 261, 262, 290, 357, 344, 345, 316,
+ 317, 236, 318, 319, 78, 78, 216, 251, 313, 314,
+ 315, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+ 157, 157, 157, 157, 157, 157, 157, 324, 325, 130,
+ 252, 129, 253, 254, 199, 258, 255, 371, 264, 366,
+ 373, 265, 267, 268, 269, 170, 274, 299, 272, 275,
+ 276, -28, 358, 352, 301, 216, -23, -228, 216, 298,
+ 366, 346, 387, 347, 341, 376, 348, 356, 350, 290,
+ -30, 157, 374, 377, 389, 372, 385, 359, 390, 386,
+ 216, 391, 388, 392, 403, 190, 394, 400, 311, 326,
+ 78, 329, 398, 404, 327, 330, 120, 331, 170, 328,
+ 119, 121, 216, 84, 263, 300, 375, 199, 393, 353,
+ 361, 401, 343, 368, 278, 279, 280, 281, 282, 283,
+ 284, 285, 286, 287, 157, 362, 378, 110, 0, 106,
+ 0, 0, 0, 288, 368, 0, 0, 107, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 384, 0, 0,
+ 0, 0, 0, 0, 0, 0, 199, 199, 0, 0,
+ 0, 0, 199, 199, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 199, 0, 0, 0, 0, 78, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 199, 0, 0, 0, 0,
+ 0, 199, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 179, 180, 181, 0, 182, 183, 184,
+ 185, 186, 187, 188, 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, 189, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 60, 133, 61, 134, 135, 136,
+ 137, 138, 0, 0, 139, 140, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 141, 0, 0, 0, 190, 191, 0,
+ 0, 0, 0, 192, 143, 144, 145, 146, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 179,
+ 180, 181, 0, 182, 183, 184, 185, 186, 187, 188,
+ 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, 189, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 0, 57, 58, 59,
+ 60, 133, 61, 134, 135, 136, 137, 138, 0, 0,
+ 139, 140, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 141,
+ 0, 0, 0, 190, 292, 0, 0, 0, 0, 192,
+ 143, 144, 145, 146, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 179, 180, 181, 0, 182,
+ 183, 184, 185, 186, 187, 188, 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, 189, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 0, 57, 58, 59, 60, 133, 61, 134,
+ 135, 136, 137, 138, 0, 0, 139, 140, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 141, 0, 0, 0, 190,
+ 0, 0, 0, 0, 0, 192, 143, 144, 145, 146,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 179, 180, 181, 0, 182, 183, 184, 185, 186,
+ 187, 188, 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, 189, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 0, 57,
+ 58, 59, 60, 133, 61, 134, 135, 136, 137, 138,
+ 0, 0, 139, 140, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 141, 0, 0, 0, 117, 0, 0, 0, 0,
+ 0, 192, 143, 144, 145, 146, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 179, 180, 181,
+ 0, 182, 183, 184, 185, 186, 187, 188, 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, 189,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 0, 57, 58, 59, 60, 133,
+ 61, 134, 135, 136, 137, 138, 0, 0, 139, 140,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 141, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 192, 143, 144,
+ 145, 146, 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, 0, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 60, 133, 61, 134, 135, 136,
+ 137, 138, 0, 0, 139, 140, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 4, 141, 6, 7, 8, 9, 10, 11,
+ 0, 0, 0, 192, 143, 144, 145, 146, 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, 0, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 0, 57, 58,
+ 59, 60, 133, 61, 134, 135, 136, 137, 138, 0,
+ 0, 139, 140, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 141, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 143, 144, 145, 146, 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, 0,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 0, 57, 58, 59, 60, 103,
+ 61, 0, 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, 104, 32, 33,
+ 34, 35, 36, 37, 0, 0, 0, 41, 42, 0,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 0, 57, 58, 59, 0, 133,
+ 61, 134, 135, 136, 137, 138, 0, 0, 139, 140,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 141, 0, 0,
+ 142, 8, 9, 10, 11, 0, 0, 0, 143, 144,
+ 145, 146, 0, 0, 0, 0, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 0, 0, 0, 0, 0, 32, 33, 34, 35,
+ 36, 37, 0, 0, 0, 41, 42, 0, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 0, 57, 58, 59, 0, 133, 61, 134,
+ 135, 136, 137, 138, 0, 0, 139, 140, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 141, 0, 0, 214, 8,
+ 9, 10, 11, 0, 0, 0, 143, 144, 145, 146,
+ 0, 0, 0, 0, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 0,
+ 0, 0, 0, 0, 32, 33, 34, 35, 36, 37,
+ 0, 0, 0, 41, 42, 0, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 0, 133, 61, 134, 135, 136,
+ 137, 138, 0, 0, 139, 140, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 141, 8, 9, 10, 11, 0, 0,
+ 0, 0, 0, 270, 143, 144, 145, 146, 0, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 0, 0, 0, 0, 0, 32,
+ 33, 34, 35, 36, 37, 0, 0, 0, 41, 42,
+ 0, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 0, 57, 58, 59, 0,
+ 133, 61, 134, 135, 136, 137, 138, 0, 0, 139,
+ 140, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 141, 0,
+ 0, 295, 8, 9, 10, 11, 0, 0, 0, 143,
+ 144, 145, 146, 0, 0, 0, 0, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 0, 0, 0, 0, 0, 32, 33, 34,
+ 35, 36, 37, 0, 0, 0, 41, 42, 0, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 0, 57, 58, 59, 0, 133, 61,
+ 134, 135, 136, 137, 138, 0, 0, 139, 140, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 141, 8, 9, 10,
+ 11, 0, 0, 0, 0, 0, 0, 143, 144, 145,
+ 146, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 0, 0, 0,
+ 0, 0, 32, 33, 34, 35, 36, 37, 0, 0,
+ 0, 41, 234, 0, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 0, 57,
+ 58, 59, 0, 133, 61, 134, 135, 136, 137, 138,
+ 0, 0, 139, 140, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+ 4, 141, 6, 7, 8, 9, 10, 11, 0, 0,
+ 0, 0, 143, 144, 145, 146, 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,
+ 0, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 0, 57, 58, 59, 60,
+ 0, 61, 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, 222, 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, 0, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 60, 0, 61, 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, 259, 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,
+ 0, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 0, 57, 58, 59, 60,
+ 0, 61, 0, 0, 0, 0, 0, 0, 0, 109,
+ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 333, 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, 0, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 60, 0, 61, 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,
+ 0, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 0, 57, 58, 59, 60,
+ 0, 61, 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, 0, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 58, 59, 60, 0, 61, 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, 32, 33, 34, 35, 36, 37, 0, 0,
+ 0, 41, 42, 0, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 0, 57,
+ 58, 59, 0, 309, 61, 8, 9, 10, 11, 310,
+ 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,
+ 32, 33, 34, 35, 36, 37, 0, 0, 0, 41,
+ 42, 0, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 0, 57, 58, 59,
+ 0, 0, 61
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 41, 71, 91, 126, 66, 204, 66, 141, 0,
+ 71, 131, 112, 0, 336, 92, 342, 364, 76, 106,
+ 105, 104, 108, 76, 77, 114, 111, 114, 97, 69,
+ 111, 106, 93, 155, 93, 105, 97, 363, 113, 125,
+ 106, 87, 88, 108, 105, 392, 105, 125, 108, 114,
+ 127, 112, 185, 112, 174, 108, 114, 106, 98, 99,
+ 129, 85, 86, 385, 113, 125, 66, 108, 129, 391,
+ 131, 71, 131, 213, 76, 175, 122, 123, 108, 139,
+ 140, 81, 106, 105, 84, 111, 110, 104, 114, 111,
+ 81, 213, 111, 93, 81, 114, 229, 97, 158, 114,
+ 105, 187, 105, 113, 105, 105, 111, 106, 111, 187,
+ 111, 233, 112, 174, 175, 174, 175, 117, 245, 246,
+ 247, 248, 105, 104, 257, 211, 212, 187, 111, 129,
+ 116, 131, 118, 211, 212, 268, 76, 77, 111, 272,
+ 260, 114, 105, 111, 111, 343, 114, 114, 4, 5,
+ 6, 211, 212, 119, 120, 121, 76, 77, 298, 83,
+ 84, 89, 90, 79, 80, 111, 112, 289, 290, 241,
+ 242, 104, 243, 244, 174, 175, 298, 126, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 249, 250, 260,
+ 125, 260, 124, 91, 204, 107, 93, 347, 114, 342,
+ 350, 114, 104, 104, 114, 301, 112, 107, 104, 104,
+ 109, 104, 56, 301, 106, 347, 105, 108, 350, 113,
+ 363, 107, 372, 113, 112, 357, 107, 107, 113, 111,
+ 104, 301, 107, 104, 377, 113, 105, 335, 114, 109,
+ 372, 105, 107, 17, 394, 108, 113, 390, 230, 251,
+ 260, 254, 114, 114, 252, 255, 97, 256, 354, 253,
+ 93, 97, 394, 5, 178, 218, 354, 277, 383, 302,
+ 337, 391, 277, 342, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 354, 337, 363, 81, -1, 368,
+ -1, -1, -1, 113, 363, -1, -1, 368, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 367, -1, -1,
+ -1, -1, -1, -1, -1, -1, 336, 337, -1, -1,
+ -1, -1, 342, 343, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 363, -1, -1, -1, -1, 368, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 385, -1, -1, -1, -1,
+ -1, 391, 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,
+ -1, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, -1, -1, 85, 86, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 104, -1, -1, -1, 108, 109, -1,
+ -1, -1, -1, 114, 115, 116, 117, 118, 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, -1, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, -1, -1,
+ 85, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 104,
+ -1, -1, -1, 108, 109, -1, -1, -1, -1, 114,
+ 115, 116, 117, 118, 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, -1, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, -1, -1, 85, 86, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 104, -1, -1, -1, 108,
+ -1, -1, -1, -1, -1, 114, 115, 116, 117, 118,
+ 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, -1, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ -1, -1, 85, 86, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 104, -1, -1, -1, 108, -1, -1, -1, -1,
+ -1, 114, 115, 116, 117, 118, 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, -1, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, -1, -1, 85, 86,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 104, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 114, 115, 116,
+ 117, 118, 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, -1, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, -1, -1, 85, 86, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 3,
+ 4, 5, 6, 104, 8, 9, 10, 11, 12, 13,
+ -1, -1, -1, 114, 115, 116, 117, 118, -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, -1, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, -1, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, -1,
+ -1, 85, 86, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 3, 4, 5, 6,
+ 104, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, 115, 116, 117, 118, -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, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, 75, 76,
+ 77, -1, -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, 114, 45, 46,
+ 47, 48, 49, 50, -1, -1, -1, 54, 55, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, -1, 76,
+ 77, 78, 79, 80, 81, 82, -1, -1, 85, 86,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 104, -1, -1,
+ 107, 10, 11, 12, 13, -1, -1, -1, 115, 116,
+ 117, 118, -1, -1, -1, -1, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, -1, -1, -1, 45, 46, 47, 48,
+ 49, 50, -1, -1, -1, 54, 55, -1, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, -1, 72, 73, 74, -1, 76, 77, 78,
+ 79, 80, 81, 82, -1, -1, 85, 86, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 104, -1, -1, 107, 10,
+ 11, 12, 13, -1, -1, -1, 115, 116, 117, 118,
+ -1, -1, -1, -1, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, -1, -1, -1, 45, 46, 47, 48, 49, 50,
+ -1, -1, -1, 54, 55, -1, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, -1, 76, 77, 78, 79, 80,
+ 81, 82, -1, -1, 85, 86, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 104, 10, 11, 12, 13, -1, -1,
+ -1, -1, -1, 114, 115, 116, 117, 118, -1, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, -1, -1, -1, -1, -1, 45,
+ 46, 47, 48, 49, 50, -1, -1, -1, 54, 55,
+ -1, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, -1, 72, 73, 74, -1,
+ 76, 77, 78, 79, 80, 81, 82, -1, -1, 85,
+ 86, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 104, -1,
+ -1, 107, 10, 11, 12, 13, -1, -1, -1, 115,
+ 116, 117, 118, -1, -1, -1, -1, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, -1, -1, -1, 45, 46, 47,
+ 48, 49, 50, -1, -1, -1, 54, 55, -1, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, -1, 72, 73, 74, -1, 76, 77,
+ 78, 79, 80, 81, 82, -1, -1, 85, 86, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 104, 10, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, 115, 116, 117,
+ 118, -1, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, -1,
+ -1, -1, 45, 46, 47, 48, 49, 50, -1, -1,
+ -1, 54, 55, -1, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70, -1, 72,
+ 73, 74, -1, 76, 77, 78, 79, 80, 81, 82,
+ -1, -1, 85, 86, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 104, 8, 9, 10, 11, 12, 13, -1, -1,
+ -1, -1, 115, 116, 117, 118, -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,
+ -1, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, -1, 72, 73, 74, 75,
+ -1, 77, -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, 109, 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, -1, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, 75, -1, 77, -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, 109, 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,
+ -1, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, -1, 72, 73, 74, 75,
+ -1, 77, -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, 109, 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, -1, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, 75, -1, 77, 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,
+ -1, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, -1, 72, 73, 74, 75,
+ -1, 77, 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, -1, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, 75, -1, 77, 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, 45, 46, 47, 48, 49, 50, -1, -1,
+ -1, 54, 55, -1, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70, -1, 72,
+ 73, 74, -1, 76, 77, 10, 11, 12, 13, 82,
+ -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,
+ 45, 46, 47, 48, 49, 50, -1, -1, -1, 54,
+ 55, -1, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, -1, 72, 73, 74,
+ -1, -1, 77
+};
+
+ /* 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, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 72, 73, 74,
+ 75, 77, 160, 161, 162, 163, 164, 168, 169, 170,
+ 171, 172, 173, 174, 175, 176, 177, 178, 181, 182,
+ 183, 218, 219, 220, 177, 76, 77, 108, 129, 104,
+ 114, 221, 105, 111, 165, 166, 167, 172, 176, 111,
+ 114, 76, 129, 76, 114, 159, 174, 176, 106, 0,
+ 219, 181, 185, 108, 76, 179, 180, 108, 201, 166,
+ 165, 167, 129, 129, 104, 106, 113, 108, 114, 172,
+ 176, 186, 187, 76, 78, 79, 80, 81, 82, 85,
+ 86, 104, 107, 115, 116, 117, 118, 130, 131, 132,
+ 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
+ 154, 158, 181, 114, 186, 184, 113, 105, 111, 14,
+ 15, 16, 18, 19, 20, 21, 22, 23, 24, 56,
+ 108, 109, 114, 141, 154, 155, 157, 160, 161, 181,
+ 191, 192, 193, 194, 202, 203, 204, 206, 208, 210,
+ 217, 106, 106, 113, 107, 158, 155, 190, 176, 129,
+ 188, 189, 109, 187, 141, 141, 157, 85, 86, 106,
+ 110, 105, 105, 111, 55, 155, 104, 141, 119, 120,
+ 121, 116, 118, 83, 84, 87, 88, 122, 123, 89,
+ 90, 126, 125, 124, 91, 93, 92, 127, 107, 109,
+ 186, 79, 80, 180, 114, 114, 212, 104, 104, 114,
+ 114, 157, 104, 158, 112, 104, 109, 195, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 113, 156,
+ 111, 114, 109, 192, 158, 107, 158, 190, 113, 107,
+ 188, 106, 111, 114, 76, 114, 105, 133, 157, 76,
+ 82, 136, 155, 141, 141, 141, 143, 143, 144, 144,
+ 145, 145, 145, 145, 146, 146, 147, 148, 149, 150,
+ 151, 152, 157, 109, 198, 199, 200, 213, 157, 114,
+ 157, 112, 211, 202, 155, 155, 107, 113, 107, 190,
+ 113, 114, 158, 189, 106, 114, 107, 112, 56, 201,
+ 193, 191, 203, 214, 105, 105, 157, 170, 172, 209,
+ 196, 190, 113, 190, 107, 158, 155, 104, 209, 215,
+ 216, 198, 205, 207, 129, 105, 109, 190, 107, 157,
+ 114, 105, 17, 194, 113, 193, 197, 201, 114, 105,
+ 157, 197, 198, 190, 114
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 128, 129, 129, 130, 131, 131, 131, 131, 131,
+ 131, 132, 132, 132, 132, 132, 132, 133, 134, 135,
+ 135, 136, 136, 137, 137, 138, 138, 139, 140, 140,
+ 140, 141, 141, 141, 141, 142, 142, 142, 142, 143,
+ 143, 143, 143, 144, 144, 144, 145, 145, 145, 146,
+ 146, 146, 146, 146, 147, 147, 147, 148, 148, 149,
+ 149, 150, 150, 151, 151, 152, 152, 153, 153, 154,
+ 154, 155, 155, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 156, 156, 157, 157, 158, 159, 160, 160,
+ 160, 160, 160, 160, 160, 160, 161, 162, 162, 163,
+ 163, 164, 165, 165, 166, 166, 166, 166, 167, 168,
+ 168, 168, 168, 168, 168, 169, 169, 169, 169, 169,
+ 169, 170, 170, 171, 171, 172, 172, 173, 174, 174,
+ 174, 174, 174, 175, 175, 175, 175, 175, 175, 175,
+ 175, 176, 177, 177, 177, 178, 179, 179, 180, 180,
+ 180, 181, 181, 181, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 184,
+ 183, 185, 183, 186, 186, 187, 187, 188, 188, 189,
+ 189, 190, 191, 192, 192, 193, 193, 193, 193, 193,
+ 193, 193, 194, 195, 196, 194, 197, 197, 199, 198,
+ 200, 198, 201, 201, 202, 202, 203, 203, 204, 205,
+ 205, 207, 206, 208, 208, 209, 209, 211, 210, 212,
+ 210, 213, 210, 214, 214, 215, 215, 216, 216, 217,
+ 217, 217, 217, 217, 218, 218, 219, 219, 221, 220
+};
+
+ /* 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,
+ 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, 5, 2, 1, 2, 1, 1, 1,
+ 3, 6, 7, 8, 5, 1, 2, 5, 6, 7,
+ 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, 4, 1, 3, 1, 3,
+ 3, 1, 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, 0,
+ 6, 0, 5, 1, 2, 3, 4, 1, 3, 1,
+ 4, 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]), (yyvsp[0].lex).string, (yyvsp[0].lex).symbol);
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+ }
+
+ 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->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[0]));
+ }
+
+ break;
+
+ case 7:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setUConst((yyvsp[0].lex).u);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), (yylsp[0]));
+ }
+
+ break;
+
+ case 8:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst((yyvsp[0].lex).f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[0]));
+ }
+
+ break;
+
+ case 9:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setBConst((yyvsp[0].lex).b);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[0]));
+ }
+
+ break;
+
+ case 10:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 11:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 12:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[-3].interm.intermTypedNode), (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 13:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 14:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addFieldSelectionExpression((yyvsp[-2].interm.intermTypedNode), (yylsp[-1]), *(yyvsp[0].lex).string, (yylsp[0]));
+ }
+
+ break;
+
+ case 15:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0]));
+ }
+
+ break;
+
+ case 16:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0]));
+ }
+
+ break;
+
+ case 17:
+
+ {
+ context->checkIsScalarInteger((yyvsp[0].interm.intermTypedNode), "[]");
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 18:
+
+ {
+ bool fatalError = false;
+ (yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).nodePair.node1, (yyvsp[0].interm).nodePair.node2, (yylsp[0]), &fatalError);
+ if (fatalError)
+ {
+ YYERROR;
+ }
+ }
+
+ break;
+
+ case 19:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ (yyval.interm).nodePair.node2 = nullptr;
+ }
+
+ break;
+
+ case 20:
+
+ {
+ ES3_OR_NEWER("", (yylsp[0]), "methods");
+ (yyval.interm) = (yyvsp[0].interm);
+ (yyval.interm).nodePair.node2 = (yyvsp[-2].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 21:
+
+ {
+ (yyval.interm) = (yyvsp[-1].interm);
+ }
+
+ break;
+
+ case 22:
+
+ {
+ (yyval.interm) = (yyvsp[-1].interm);
+ }
+
+ break;
+
+ case 23:
+
+ {
+ (yyval.interm).function = (yyvsp[-1].interm.function);
+ (yyval.interm).nodePair.node1 = nullptr;
+ }
+
+ break;
+
+ case 24:
+
+ {
+ (yyval.interm).function = (yyvsp[0].interm.function);
+ (yyval.interm).nodePair.node1 = nullptr;
+ }
+
+ break;
+
+ case 25:
+
+ {
+ const TType *type = new TType((yyvsp[0].interm.intermTypedNode)->getType());
+ (yyvsp[-1].interm.function)->addParameter(TConstParameter(type));
+ (yyval.interm).function = (yyvsp[-1].interm.function);
+ (yyval.interm).nodePair.node1 = TIntermediate::MakeAggregate((yyvsp[0].interm.intermTypedNode), (yylsp[0]));
+ }
+
+ break;
+
+ case 26:
+
+ {
+ const TType *type = new TType((yyvsp[0].interm.intermTypedNode)->getType());
+ (yyvsp[-2].interm).function->addParameter(TConstParameter(type));
+ (yyval.interm).function = (yyvsp[-2].interm).function;
+ (yyval.interm).nodePair.node1 = context->intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 27:
+
+ {
+ (yyval.interm.function) = (yyvsp[-1].interm.function);
+ }
+
+ break;
+
+ case 28:
+
+ {
+ if ((yyvsp[0].interm.type).array) {
+ ES3_OR_NEWER("[]", (yylsp[0]), "array constructor");
+ }
+ (yyval.interm.function) = context->addConstructorFunc((yyvsp[0].interm.type));
+ }
+
+ break;
+
+ case 29:
+
+ {
+ context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[0].lex).string, type);
+ (yyval.interm.function) = function;
+ }
+
+ break;
+
+ case 30:
+
+ {
+ context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[0].lex).string, type);
+ (yyval.interm.function) = function;
+ }
+
+ break;
+
+ case 31:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 32:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreIncrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 33:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreDecrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 34:
+
+ {
+ if ((yyvsp[-1].interm).op != EOpNull) {
+ (yyval.interm.intermTypedNode) = context->addUnaryMath((yyvsp[-1].interm).op, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ } else
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 35:
+
+ { (yyval.interm).op = EOpPositive; }
+
+ break;
+
+ case 36:
+
+ { (yyval.interm).op = EOpNegative; }
+
+ break;
+
+ case 37:
+
+ { (yyval.interm).op = EOpLogicalNot; }
+
+ break;
+
+ case 38:
+
+ {
+ ES3_OR_NEWER("~", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitwiseNot;
+ }
+
+ break;
+
+ case 39:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 40:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 41:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 42:
+
+ {
+ 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 43:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 44:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 45:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 46:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 47:
+
+ {
+ 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 48:
+
+ {
+ 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 49:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 50:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 51:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 52:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 53:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 54:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 55:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 56:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 57:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 58:
+
+ {
+ 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 59:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 60:
+
+ {
+ 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 61:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 62:
+
+ {
+ 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 63:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 64:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 65:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 66:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 67:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 68:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 69:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 70:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addTernarySelection((yyvsp[-4].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-3]));
+ }
+
+ break;
+
+ case 71:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 72:
+
+ {
+ context->checkCanBeLValue((yylsp[-1]), "assign", (yyvsp[-2].interm.intermTypedNode));
+ (yyval.interm.intermTypedNode) = context->addAssign((yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 73:
+
+ { (yyval.interm).op = EOpAssign; }
+
+ break;
+
+ case 74:
+
+ { (yyval.interm).op = EOpMulAssign; }
+
+ break;
+
+ case 75:
+
+ { (yyval.interm).op = EOpDivAssign; }
+
+ break;
+
+ case 76:
+
+ {
+ ES3_OR_NEWER("%=", (yyloc), "integer modulus operator");
+ (yyval.interm).op = EOpIModAssign;
+ }
+
+ break;
+
+ case 77:
+
+ { (yyval.interm).op = EOpAddAssign; }
+
+ break;
+
+ case 78:
+
+ { (yyval.interm).op = EOpSubAssign; }
+
+ break;
+
+ case 79:
+
+ {
+ ES3_OR_NEWER("<<=", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitShiftLeftAssign;
+ }
+
+ break;
+
+ case 80:
+
+ {
+ ES3_OR_NEWER(">>=", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitShiftRightAssign;
+ }
+
+ break;
+
+ case 81:
+
+ {
+ ES3_OR_NEWER("&=", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitwiseAndAssign;
+ }
+
+ break;
+
+ case 82:
+
+ {
+ ES3_OR_NEWER("^=", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitwiseXorAssign;
+ }
+
+ break;
+
+ case 83:
+
+ {
+ ES3_OR_NEWER("|=", (yyloc), "bit-wise operator");
+ (yyval.interm).op = EOpBitwiseOrAssign;
+ }
+
+ break;
+
+ case 84:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 85:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 86:
+
+ {
+ context->checkIsConst((yyvsp[0].interm.intermTypedNode));
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 87:
+
+ {
+ context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string);
+ (yyval.lex) = (yyvsp[-1].lex);
+ }
+
+ break;
+
+ case 88:
+
+ {
+ (yyval.interm.intermNode) = context->addFunctionPrototypeDeclaration(*((yyvsp[-1].interm).function), (yylsp[-1]));
+ }
+
+ break;
+
+ case 89:
+
+ {
+ TIntermAggregate *aggNode = (yyvsp[-1].interm).intermAggregate;
+ if (aggNode && aggNode->getOp() == EOpNull)
+ aggNode->setOp(EOpDeclaration);
+ (yyval.interm.intermNode) = aggNode;
+ }
+
+ break;
+
+ case 90:
+
+ {
+ if (((yyvsp[-2].interm.precision) == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) {
+ context->error((yylsp[-3]), "precision is not supported in fragment shader", "highp");
+ }
+ if (!context->symbolTable.setDefaultPrecision( (yyvsp[-1].interm.type), (yyvsp[-2].interm.precision) )) {
+ context->error((yylsp[-3]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[-1].interm.type).getBasicType()));
+ }
+ (yyval.interm.intermNode) = 0;
+ }
+
+ break;
+
+ case 91:
+
+ {
+ ES3_OR_NEWER((yyvsp[-3].lex).string->c_str(), (yylsp[-4]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-4].interm.typeQualifierBuilder), (yylsp[-3]), *(yyvsp[-3].lex).string, (yyvsp[-2].interm.fieldList), NULL, (yyloc), NULL, (yyloc));
+ }
+
+ break;
+
+ case 92:
+
+ {
+ ES3_OR_NEWER((yyvsp[-4].lex).string->c_str(), (yylsp[-5]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-5].interm.typeQualifierBuilder), (yylsp[-4]), *(yyvsp[-4].lex).string, (yyvsp[-3].interm.fieldList), (yyvsp[-1].lex).string, (yylsp[-1]), NULL, (yyloc));
+ }
+
+ break;
+
+ case 93:
+
+ {
+ ES3_OR_NEWER((yyvsp[-7].lex).string->c_str(), (yylsp[-8]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-8].interm.typeQualifierBuilder), (yylsp[-7]), *(yyvsp[-7].lex).string, (yyvsp[-6].interm.fieldList), (yyvsp[-4].lex).string, (yylsp[-4]), (yyvsp[-2].interm.intermTypedNode), (yylsp[-3]));
+ }
+
+ break;
+
+ case 94:
+
+ {
+ context->parseGlobalLayoutQualifier(*(yyvsp[-1].interm.typeQualifierBuilder));
+ (yyval.interm.intermNode) = 0;
+ }
+
+ break;
+
+ case 95:
+
+ {
+ (yyval.interm.intermNode) = context->parseInvariantDeclaration(*(yyvsp[-2].interm.typeQualifierBuilder), (yylsp[-1]), (yyvsp[-1].lex).string, (yyvsp[-1].lex).symbol);
+ }
+
+ break;
+
+ case 96:
+
+ {
+ (yyval.interm).function = context->parseFunctionDeclarator((yylsp[0]), (yyvsp[-1].interm.function));
+ context->exitFunctionDeclaration();
+ }
+
+ break;
+
+ case 97:
+
+ {
+ (yyval.interm.function) = (yyvsp[0].interm.function);
+ }
+
+ break;
+
+ case 98:
+
+ {
+ (yyval.interm.function) = (yyvsp[0].interm.function);
+ }
+
+ break;
+
+ case 99:
+
+ {
+ // 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.turnToConst());
+ else
+ delete (yyvsp[0].interm).param.type;
+ }
+
+ break;
+
+ case 100:
+
+ {
+ //
+ // 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 an argument type except for '(void)'", "void");
+ delete (yyvsp[0].interm).param.type;
+ } else {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[-2].interm.function);
+ (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param.turnToConst());
+ }
+ }
+
+ break;
+
+ case 101:
+
+ {
+ (yyval.interm.function) = context->parseFunctionHeader((yyvsp[-2].interm.type), (yyvsp[-1].lex).string, (yylsp[-1]));
+
+ context->symbolTable.push();
+ context->enterFunctionDeclaration();
+ }
+
+ break;
+
+ case 102:
+
+ {
+ if ((yyvsp[-1].interm.type).getBasicType() == EbtVoid) {
+ context->error((yylsp[0]), "illegal use of type 'void'", (yyvsp[0].lex).string->c_str());
+ }
+ context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string);
+ TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))};
+ (yyval.interm).param = param;
+ }
+
+ break;
+
+ case 103:
+
+ {
+ // Check that we can make an array out of this type
+ context->checkIsValidTypeForArray((yylsp[-2]), (yyvsp[-4].interm.type));
+
+ context->checkIsNotReserved((yylsp[-3]), *(yyvsp[-3].lex).string);
+
+ unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+
+ (yyvsp[-4].interm.type).setArraySize(size);
+
+ TType* type = new TType((yyvsp[-4].interm.type));
+ TParameter param = { (yyvsp[-3].lex).string, type };
+ (yyval.interm).param = param;
+ }
+
+ break;
+
+ case 104:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm).param.type);
+ }
+
+ break;
+
+ case 105:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ (yyval.interm).param.type->setQualifier(EvqIn);
+ }
+
+ break;
+
+ case 106:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm).param.type);
+ }
+
+ break;
+
+ case 107:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ (yyval.interm).param.type->setQualifier(EvqIn);
+ }
+
+ break;
+
+ case 108:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[0].interm.type)) };
+ (yyval.interm).param = param;
+ }
+
+ break;
+
+ case 109:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ }
+
+ break;
+
+ case 110:
+
+ {
+ (yyval.interm) = (yyvsp[-2].interm);
+ (yyval.interm).intermAggregate = context->parseDeclarator((yyval.interm).type, (yyvsp[-2].interm).intermAggregate, (yylsp[0]), *(yyvsp[0].lex).string);
+ }
+
+ break;
+
+ case 111:
+
+ {
+ (yyval.interm) = (yyvsp[-5].interm);
+ (yyval.interm).intermAggregate = context->parseArrayDeclarator((yyval.interm).type, (yyvsp[-5].interm).intermAggregate, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 112:
+
+ {
+ ES3_OR_NEWER("[]", (yylsp[-4]), "implicitly sized array");
+ (yyval.interm) = (yyvsp[-6].interm);
+ (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-6].interm).intermAggregate, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 113:
+
+ {
+ ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)");
+ (yyval.interm) = (yyvsp[-7].interm);
+ (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-7].interm).intermAggregate, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 114:
+
+ {
+ (yyval.interm) = (yyvsp[-4].interm);
+ (yyval.interm).intermAggregate = context->parseInitDeclarator((yyval.interm).type, (yyvsp[-4].interm).intermAggregate, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 115:
+
+ {
+ (yyval.interm).type = (yyvsp[0].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), "");
+ }
+
+ break;
+
+ case 116:
+
+ {
+ (yyval.interm).type = (yyvsp[-1].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), *(yyvsp[0].lex).string);
+ }
+
+ break;
+
+ case 117:
+
+ {
+ (yyval.interm).type = (yyvsp[-4].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 118:
+
+ {
+ ES3_OR_NEWER("[]", (yylsp[-3]), "implicitly sized array");
+ (yyval.interm).type = (yyvsp[-5].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 119:
+
+ {
+ ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)");
+ (yyval.interm).type = (yyvsp[-6].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 120:
+
+ {
+ (yyval.interm).type = (yyvsp[-3].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 121:
+
+ {
+ (yyval.interm.type) = (yyvsp[0].interm.type);
+
+ if ((yyvsp[0].interm.type).array) {
+ ES3_OR_NEWER("[]", (yylsp[0]), "first-class-array");
+ if (context->getShaderVersion() != 300) {
+ (yyvsp[0].interm.type).clearArrayness();
+ }
+ }
+ }
+
+ break;
+
+ case 122:
+
+ {
+ (yyval.interm.type) = context->addFullySpecifiedType(*(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.type));
+ }
+
+ break;
+
+ case 123:
+
+ {
+ (yyval.interm.qualifier) = EvqSmooth;
+ }
+
+ break;
+
+ case 124:
+
+ {
+ (yyval.interm.qualifier) = EvqFlat;
+ }
+
+ break;
+
+ case 125:
+
+ {
+ (yyval.interm.typeQualifierBuilder) = context->createTypeQualifierBuilder((yylsp[0]));
+ (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper));
+ }
+
+ break;
+
+ case 126:
+
+ {
+ (yyval.interm.typeQualifierBuilder) = (yyvsp[-1].interm.typeQualifierBuilder);
+ (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper));
+ }
+
+ break;
+
+ case 127:
+
+ {
+ // empty
+ }
+
+ break;
+
+ case 128:
+
+ {
+ if (!context->declaringFunction() && (yyvsp[0].interm.qualifier) != EvqConst && !context->symbolTable.atGlobalLevel())
+ {
+ context->error((yylsp[0]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[0].interm.qualifier)));
+ }
+ (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 129:
+
+ {
+ context->checkIsAtGlobalLevel((yylsp[0]), "layout");
+ (yyval.interm.qualifierWrapper) = new TLayoutQualifierWrapper((yyvsp[0].interm.layoutQualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 130:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TPrecisionQualifierWrapper((yyvsp[0].interm.precision), (yylsp[0]));
+ }
+
+ break;
+
+ case 131:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TInterpolationQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 132:
+
+ {
+ context->checkIsAtGlobalLevel((yylsp[0]), "invariant");
+ (yyval.interm.qualifierWrapper) = new TInvariantQualifierWrapper((yylsp[0]));
+ }
+
+ break;
+
+ case 133:
+
+ {
+ VERTEX_ONLY("attribute", (yylsp[0]));
+ ES2_ONLY("attribute", (yylsp[0]));
+ context->checkIsAtGlobalLevel((yylsp[0]), "attribute");
+ (yyval.interm.qualifier) = EvqAttribute;
+ }
+
+ break;
+
+ case 134:
+
+ {
+ ES2_ONLY("varying", (yylsp[0]));
+ context->checkIsAtGlobalLevel((yylsp[0]), "varying");
+ if (context->getShaderType() == GL_VERTEX_SHADER)
+ (yyval.interm.qualifier) = EvqVaryingOut;
+ else
+ (yyval.interm.qualifier) = EvqVaryingIn;
+ }
+
+ break;
+
+ case 135:
+
+ {
+ (yyval.interm.qualifier) = EvqConst;
+ }
+
+ break;
+
+ case 136:
+
+ {
+ if (context->declaringFunction())
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ }
+ else if (context->getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier");
+ (yyval.interm.qualifier) = EvqFragmentIn;
+ }
+ else if (context->getShaderType() == GL_VERTEX_SHADER)
+ {
+ ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier");
+ (yyval.interm.qualifier) = EvqVertexIn;
+ }
+ else
+ {
+ (yyval.interm.qualifier) = EvqComputeIn;
+ }
+ }
+
+ break;
+
+ case 137:
+
+ {
+ if (context->declaringFunction())
+ {
+ (yyval.interm.qualifier) = EvqOut;
+ }
+ else
+ {
+ ES3_OR_NEWER("out", (yylsp[0]), "storage qualifier");
+ NON_COMPUTE_ONLY("out", (yylsp[0]));
+ if (context->getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ (yyval.interm.qualifier) = EvqFragmentOut;
+ }
+ else
+ {
+ (yyval.interm.qualifier) = EvqVertexOut;
+ }
+ }
+ }
+
+ break;
+
+ case 138:
+
+ {
+ if (!context->declaringFunction())
+ {
+ context->error((yylsp[0]), "invalid inout qualifier", "'inout' can be only used with function parameters");
+ }
+ (yyval.interm.qualifier) = EvqInOut;
+ }
+
+ break;
+
+ case 139:
+
+ {
+ ES3_OR_NEWER("centroid", (yylsp[0]), "storage qualifier");
+ (yyval.interm.qualifier) = EvqCentroid;
+ }
+
+ break;
+
+ case 140:
+
+ {
+ context->checkIsAtGlobalLevel((yylsp[0]), "uniform");
+ (yyval.interm.qualifier) = EvqUniform;
+ }
+
+ break;
+
+ case 141:
+
+ {
+ (yyval.interm.type) = (yyvsp[0].interm.type);
+
+ if ((yyval.interm.type).precision == EbpUndefined) {
+ (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[0].interm.type).getBasicType());
+ }
+ }
+
+ break;
+
+ case 142:
+
+ {
+ (yyval.interm.precision) = EbpHigh;
+ }
+
+ break;
+
+ case 143:
+
+ {
+ (yyval.interm.precision) = EbpMedium;
+ }
+
+ break;
+
+ case 144:
+
+ {
+ (yyval.interm.precision) = EbpLow;
+ }
+
+ break;
+
+ case 145:
+
+ {
+ ES3_OR_NEWER("layout", (yylsp[-3]), "qualifier");
+ (yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier);
+ }
+
+ break;
+
+ case 146:
+
+ {
+ (yyval.interm.layoutQualifier) = (yyvsp[0].interm.layoutQualifier);
+ }
+
+ break;
+
+ case 147:
+
+ {
+ (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 148:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[0].lex).string, (yylsp[0]));
+ }
+
+ break;
+
+ case 149:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
+ }
+
+ break;
+
+ case 150:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
+ }
+
+ break;
+
+ case 151:
+
+ {
+ (yyval.interm.type).initialize((yyvsp[0].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ }
+
+ break;
+
+ case 152:
+
+ {
+ ES3_OR_NEWER("[]", (yylsp[-1]), "implicitly sized array");
+ (yyval.interm.type).initialize((yyvsp[-2].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ (yyval.interm.type).setArraySize(0);
+ }
+
+ break;
+
+ case 153:
+
+ {
+ (yyval.interm.type).initialize((yyvsp[-3].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ if (context->checkIsValidTypeForArray((yylsp[-2]), (yyval.interm.type)))
+ {
+ unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ (yyval.interm.type).setArraySize(size);
+ }
+ }
+
+ break;
+
+ case 154:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtVoid, (yylsp[0]));
+ }
+
+ break;
+
+ case 155:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ }
+
+ break;
+
+ case 156:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ }
+
+ break;
+
+ case 157:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ }
+
+ break;
+
+ case 158:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ }
+
+ break;
+
+ case 159:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 160:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 161:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 162:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 163:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 164:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 165:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 166:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 167:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 168:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 169:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 170:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 171:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 2);
+ }
+
+ break;
+
+ case 172:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 3);
+ }
+
+ break;
+
+ case 173:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 4);
+ }
+
+ break;
+
+ case 174:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 3);
+ }
+
+ break;
+
+ case 175:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 2);
+ }
+
+ break;
+
+ case 176:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 4);
+ }
+
+ break;
+
+ case 177:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 2);
+ }
+
+ break;
+
+ case 178:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 4);
+ }
+
+ break;
+
+ case 179:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 3);
+ }
+
+ break;
+
+ case 180:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 181:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 182:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 183:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 184:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 185:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 186:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 187:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 188:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 189:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 190:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 191:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 192:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 193:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCubeShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 194:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArrayShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 195:
+
+ {
+ if (!context->supportsExtension("GL_OES_EGL_image_external") &&
+ !context->supportsExtension("GL_NV_EGL_stream_consumer_external")) {
+ context->error((yylsp[0]), "unsupported type", "samplerExternalOES");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternalOES, (yylsp[0]));
+ }
+
+ break;
+
+ case 196:
+
+ {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error((yylsp[0]), "unsupported type", "sampler2DRect");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DRect, (yylsp[0]));
+ }
+
+ break;
+
+ case 197:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = (yyvsp[0].interm.typeSpecifierNonArray);
+ }
+
+ break;
+
+ case 198:
+
+ {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>((yyvsp[0].lex).symbol)->getType();
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtStruct, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).userDef = &structure;
+ }
+
+ break;
+
+ case 199:
+
+ { context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string); }
+
+ break;
+
+ case 200:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-5]), (yylsp[-4]), (yyvsp[-4].lex).string, (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 201:
+
+ { context->enterStructDeclaration((yylsp[0]), *(yyvsp[0].lex).string); }
+
+ break;
+
+ case 202:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-4]), (yyloc), NewPoolTString(""), (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 203:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[0].interm.fieldList);
+ }
+
+ break;
+
+ case 204:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[-1].interm.fieldList);
+ for (size_t i = 0; i < (yyvsp[0].interm.fieldList)->size(); ++i) {
+ TField* field = (*(yyvsp[0].interm.fieldList))[i];
+ for (size_t j = 0; j < (yyval.interm.fieldList)->size(); ++j) {
+ if ((*(yyval.interm.fieldList))[j]->name() == field->name()) {
+ context->error((yylsp[0]), "duplicate field name in structure:", "struct", field->name().c_str());
+ }
+ }
+ (yyval.interm.fieldList)->push_back(field);
+ }
+ }
+
+ break;
+
+ case 205:
+
+ {
+ (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 206:
+
+ {
+ // ES3 Only, but errors should be handled elsewhere
+ (yyval.interm.fieldList) = context->addStructDeclaratorListWithQualifiers(*(yyvsp[-3].interm.typeQualifierBuilder), &(yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 207:
+
+ {
+ (yyval.interm.fieldList) = NewPoolTFieldList();
+ (yyval.interm.fieldList)->push_back((yyvsp[0].interm.field));
+ }
+
+ break;
+
+ case 208:
+
+ {
+ (yyval.interm.fieldList)->push_back((yyvsp[0].interm.field));
+ }
+
+ break;
+
+ case 209:
+
+ {
+ context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string);
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ (yyval.interm.field) = new TField(type, (yyvsp[0].lex).string, (yylsp[0]));
+ }
+
+ break;
+
+ case 210:
+
+ {
+ context->checkIsNotReserved((yylsp[-3]), *(yyvsp[-3].lex).string);
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ unsigned int size = context->checkIsValidArraySize((yylsp[-1]), (yyvsp[-1].interm.intermTypedNode));
+ type->setArraySize(size);
+
+ (yyval.interm.field) = new TField(type, (yyvsp[-3].lex).string, (yylsp[-3]));
+ }
+
+ break;
+
+ case 211:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 212:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 213:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 214:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 215:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 216:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 217:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 218:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); }
+
+ break;
+
+ case 219:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); }
+
+ break;
+
+ case 220:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 221:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 222:
+
+ { (yyval.interm.intermBlock) = 0; }
+
+ break;
+
+ case 223:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 224:
+
+ { context->symbolTable.pop(); }
+
+ break;
+
+ case 225:
+
+ {
+ if ((yyvsp[-2].interm.intermBlock) != 0) {
+ (yyvsp[-2].interm.intermBlock)->setLine((yyloc));
+ }
+ (yyval.interm.intermBlock) = (yyvsp[-2].interm.intermBlock);
+ }
+
+ break;
+
+ case 226:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 227:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 228:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 229:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 230:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 231:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 232:
+
+ {
+ (yyval.interm.intermBlock) = 0;
+ }
+
+ break;
+
+ case 233:
+
+ {
+ if ((yyvsp[-1].interm.intermBlock)) {
+ (yyvsp[-1].interm.intermBlock)->setLine((yyloc));
+ }
+ (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
+ }
+
+ break;
+
+ case 234:
+
+ {
+ (yyval.interm.intermBlock) = new TIntermBlock();
+ (yyval.interm.intermBlock)->setLine((yyloc));
+ (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 235:
+
+ {
+ (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
+ (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 236:
+
+ { (yyval.interm.intermNode) = 0; }
+
+ break;
+
+ case 237:
+
+ { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[-1].interm.intermTypedNode)); }
+
+ break;
+
+ case 238:
+
+ {
+ context->checkIsScalarBool((yylsp[-4]), (yyvsp[-2].interm.intermTypedNode));
+ (yyval.interm.intermNode) = context->intermediate.addIfElse((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yylsp[-4]));
+ }
+
+ break;
+
+ case 239:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 240:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+
+ break;
+
+ case 241:
+
+ { context->incrSwitchNestingLevel(); }
+
+ break;
+
+ case 242:
+
+ {
+ (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermBlock), (yylsp[-5]));
+ context->decrSwitchNestingLevel();
+ }
+
+ break;
+
+ case 243:
+
+ {
+ (yyval.interm.intermCase) = context->addCase((yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
+ }
+
+ break;
+
+ case 244:
+
+ {
+ (yyval.interm.intermCase) = context->addDefault((yylsp[-1]));
+ }
+
+ break;
+
+ case 245:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ context->checkIsScalarBool((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 246:
+
+ {
+ TIntermNode *intermNode;
+ context->checkIsScalarBool((yylsp[-2]), (yyvsp[-3].interm.type));
+
+ if (!context->executeInitializer((yylsp[-2]), *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), (yyvsp[0].interm.intermTypedNode), &intermNode))
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ else {
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ }
+
+ break;
+
+ case 247:
+
+ { context->symbolTable.push(); context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 248:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 249:
+
+ { context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 250:
+
+ {
+ context->checkIsScalarBool((yylsp[0]), (yyvsp[-2].interm.intermTypedNode));
+
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 251:
+
+ { context->symbolTable.push(); context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 252:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 253:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 254:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 255:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 256:
+
+ {
+ (yyval.interm.intermTypedNode) = 0;
+ }
+
+ break;
+
+ case 257:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+
+ break;
+
+ case 258:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 259:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
+ }
+
+ break;
+
+ case 260:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
+ }
+
+ break;
+
+ case 261:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
+ }
+
+ break;
+
+ case 262:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
+ }
+
+ break;
+
+ case 263:
+
+ {
+ FRAG_ONLY("discard", (yylsp[-1]));
+ (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1]));
+ }
+
+ break;
+
+ case 264:
+
+ {
+ (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 265:
+
+ {
+ (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 266:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 267:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 268:
+
+ {
+ context->parseFunctionDefinitionHeader((yylsp[0]), &((yyvsp[0].interm).function), &(yyvsp[0].interm).intermAggregate);
+ }
+
+ break;
+
+ case 269:
+
+ {
+ (yyval.interm.intermNode) = context->addFunctionDefinition(*((yyvsp[-2].interm).function), (yyvsp[-2].interm).intermAggregate, (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/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.h b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.h
new file mode 100644
index 000000000..74a56da04
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/glslang_tab.h
@@ -0,0 +1,253 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
+
+/* 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
+
+
+
+/* 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,
+ VARYING = 299,
+ MATRIX2x3 = 300,
+ MATRIX3x2 = 301,
+ MATRIX2x4 = 302,
+ MATRIX4x2 = 303,
+ MATRIX3x4 = 304,
+ MATRIX4x3 = 305,
+ CENTROID = 306,
+ FLAT = 307,
+ SMOOTH = 308,
+ STRUCT = 309,
+ VOID_TYPE = 310,
+ WHILE = 311,
+ SAMPLER2D = 312,
+ SAMPLERCUBE = 313,
+ SAMPLER_EXTERNAL_OES = 314,
+ SAMPLER2DRECT = 315,
+ SAMPLER2DARRAY = 316,
+ ISAMPLER2D = 317,
+ ISAMPLER3D = 318,
+ ISAMPLERCUBE = 319,
+ ISAMPLER2DARRAY = 320,
+ USAMPLER2D = 321,
+ USAMPLER3D = 322,
+ USAMPLERCUBE = 323,
+ USAMPLER2DARRAY = 324,
+ SAMPLER3D = 325,
+ SAMPLER3DRECT = 326,
+ SAMPLER2DSHADOW = 327,
+ SAMPLERCUBESHADOW = 328,
+ SAMPLER2DARRAYSHADOW = 329,
+ LAYOUT = 330,
+ IDENTIFIER = 331,
+ TYPE_NAME = 332,
+ FLOATCONSTANT = 333,
+ INTCONSTANT = 334,
+ UINTCONSTANT = 335,
+ BOOLCONSTANT = 336,
+ FIELD_SELECTION = 337,
+ LEFT_OP = 338,
+ RIGHT_OP = 339,
+ INC_OP = 340,
+ DEC_OP = 341,
+ LE_OP = 342,
+ GE_OP = 343,
+ EQ_OP = 344,
+ NE_OP = 345,
+ AND_OP = 346,
+ OR_OP = 347,
+ XOR_OP = 348,
+ MUL_ASSIGN = 349,
+ DIV_ASSIGN = 350,
+ ADD_ASSIGN = 351,
+ MOD_ASSIGN = 352,
+ LEFT_ASSIGN = 353,
+ RIGHT_ASSIGN = 354,
+ AND_ASSIGN = 355,
+ XOR_ASSIGN = 356,
+ OR_ASSIGN = 357,
+ SUB_ASSIGN = 358,
+ LEFT_PAREN = 359,
+ RIGHT_PAREN = 360,
+ LEFT_BRACKET = 361,
+ RIGHT_BRACKET = 362,
+ LEFT_BRACE = 363,
+ RIGHT_BRACE = 364,
+ DOT = 365,
+ COMMA = 366,
+ COLON = 367,
+ EQUAL = 368,
+ SEMICOLON = 369,
+ BANG = 370,
+ DASH = 371,
+ TILDE = 372,
+ PLUS = 373,
+ STAR = 374,
+ SLASH = 375,
+ PERCENT = 376,
+ LEFT_ANGLE = 377,
+ RIGHT_ANGLE = 378,
+ VERTICAL_BAR = 379,
+ CARET = 380,
+ AMPERSAND = 381,
+ QUESTION = 382
+ };
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ TIntermSwitch* intermSwitch;
+ TIntermCase* intermCase;
+ };
+ union {
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ 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/Source/ThirdParty/ANGLE/src/compiler/translator/intermOut.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/intermOut.cpp
new file mode 100644
index 000000000..352fde35a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/intermOut.cpp
@@ -0,0 +1,723 @@
+//
+// 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/Intermediate.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
+{
+ const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
+ out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
+ << info->getId() << ")";
+}
+
+//
+// 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.
+// See the last function for how to get started.
+// 2. Print out a text based description of the tree.
+//
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TOutputTraverser : public TIntermTraverser
+{
+ public:
+ TOutputTraverser(TInfoSinkBase &i)
+ : TIntermTraverser(true, false, false),
+ sink(i)
+ {
+ }
+ TInfoSinkBase& sink;
+
+ 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;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *) override;
+ bool visitBlock(Visit visit, TIntermBlock *) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
+ bool visitBranch(Visit visit, TIntermBranch *) override;
+};
+
+//
+// Helper functions for printing, not part of traversing.
+//
+void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
+{
+ int i;
+
+ sink.location(node->getLine());
+
+ for (i = 0; i < depth; ++i)
+ sink << " ";
+}
+
+} // namespace anonymous
+
+//
+// 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(sink, node, mDepth);
+
+ sink << "'" << node->getSymbol() << "' ";
+ sink << "(" << node->getCompleteString() << ")\n";
+}
+
+bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ TInfoSinkBase &out = sink;
+ OutputTreeText(out, node, mDepth);
+ out << "vector swizzle";
+ return true;
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ switch (node->getOp())
+ {
+ case EOpComma:
+ out << "comma";
+ break;
+ case EOpAssign:
+ out << "move second child to first child";
+ break;
+ case EOpInitialize:
+ out << "initialize first child with second child";
+ break;
+ case EOpAddAssign:
+ out << "add second child into first child";
+ break;
+ case EOpSubAssign:
+ out << "subtract second child into first child";
+ break;
+ case EOpMulAssign:
+ out << "multiply second child into first child";
+ break;
+ case EOpVectorTimesMatrixAssign:
+ out << "matrix mult second child into first child";
+ break;
+ case EOpVectorTimesScalarAssign:
+ out << "vector scale second child into first child";
+ break;
+ case EOpMatrixTimesScalarAssign:
+ out << "matrix scale second child into first child";
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ out << "matrix mult second child into first child";
+ break;
+ case EOpDivAssign:
+ out << "divide second child into first child";
+ break;
+ case EOpIModAssign:
+ out << "modulo second child into first child";
+ break;
+ case EOpBitShiftLeftAssign:
+ out << "bit-wise shift first child left by second child";
+ break;
+ case EOpBitShiftRightAssign:
+ out << "bit-wise shift first child right by second child";
+ break;
+ case EOpBitwiseAndAssign:
+ out << "bit-wise and second child into first child";
+ break;
+ case EOpBitwiseXorAssign:
+ out << "bit-wise xor second child into first child";
+ break;
+ case EOpBitwiseOrAssign:
+ out << "bit-wise or second child into first child";
+ break;
+
+ case EOpIndexDirect:
+ out << "direct index";
+ break;
+ case EOpIndexIndirect:
+ out << "indirect index";
+ break;
+ case EOpIndexDirectStruct:
+ out << "direct index for structure";
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ out << "direct index for interface block";
+ break;
+
+ case EOpAdd:
+ out << "add";
+ break;
+ case EOpSub:
+ out << "subtract";
+ break;
+ case EOpMul:
+ out << "component-wise multiply";
+ break;
+ case EOpDiv:
+ out << "divide";
+ break;
+ case EOpIMod:
+ out << "modulo";
+ break;
+ case EOpBitShiftLeft:
+ out << "bit-wise shift left";
+ break;
+ case EOpBitShiftRight:
+ out << "bit-wise shift right";
+ break;
+ case EOpBitwiseAnd:
+ out << "bit-wise and";
+ break;
+ case EOpBitwiseXor:
+ out << "bit-wise xor";
+ break;
+ case EOpBitwiseOr:
+ out << "bit-wise or";
+ break;
+
+ case EOpEqual:
+ out << "Compare Equal";
+ break;
+ case EOpNotEqual:
+ out << "Compare Not Equal";
+ break;
+ case EOpLessThan:
+ out << "Compare Less Than";
+ break;
+ case EOpGreaterThan:
+ out << "Compare Greater Than";
+ break;
+ case EOpLessThanEqual:
+ out << "Compare Less Than or Equal";
+ break;
+ case EOpGreaterThanEqual:
+ out << "Compare Greater Than or Equal";
+ break;
+
+ case EOpVectorTimesScalar:
+ out << "vector-scale";
+ break;
+ case EOpVectorTimesMatrix:
+ out << "vector-times-matrix";
+ break;
+ case EOpMatrixTimesVector:
+ out << "matrix-times-vector";
+ break;
+ case EOpMatrixTimesScalar:
+ out << "matrix-scale";
+ break;
+ case EOpMatrixTimesMatrix:
+ out << "matrix-multiply";
+ break;
+
+ case EOpLogicalOr:
+ out << "logical-or";
+ break;
+ case EOpLogicalXor:
+ out << "logical-xor";
+ break;
+ case EOpLogicalAnd:
+ out << "logical-and";
+ break;
+ default:
+ out << "<unknown op>";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\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)
+ {
+ mDepth++;
+ node->getLeft()->traverse(this);
+ mDepth--;
+
+ TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
+ ASSERT(intermConstantUnion);
+
+ OutputTreeText(out, intermConstantUnion, mDepth + 1);
+
+ // The following code finds the field name from the constant union
+ const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
+ 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()];
+
+ out << constantUnion->getIConst() << " (field '" << field->name() << "')";
+
+ return false;
+ }
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ switch (node->getOp())
+ {
+ case EOpNegative: out << "Negate value"; break;
+ case EOpPositive: out << "Positive sign"; break;
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot: out << "Negate conditional"; break;
+ case EOpBitwiseNot: out << "bit-wise not"; break;
+
+ case EOpPostIncrement: out << "Post-Increment"; break;
+ case EOpPostDecrement: out << "Post-Decrement"; break;
+ case EOpPreIncrement: out << "Pre-Increment"; break;
+ case EOpPreDecrement: out << "Pre-Decrement"; break;
+
+ case EOpRadians: out << "radians"; break;
+ case EOpDegrees: out << "degrees"; break;
+ case EOpSin: out << "sine"; break;
+ case EOpCos: out << "cosine"; break;
+ case EOpTan: out << "tangent"; break;
+ case EOpAsin: out << "arc sine"; break;
+ case EOpAcos: out << "arc cosine"; break;
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpSinh: out << "hyperbolic sine"; break;
+ case EOpCosh: out << "hyperbolic cosine"; break;
+ case EOpTanh: out << "hyperbolic tangent"; break;
+ case EOpAsinh: out << "arc hyperbolic sine"; break;
+ case EOpAcosh: out << "arc hyperbolic cosine"; break;
+ case EOpAtanh: out << "arc hyperbolic tangent"; break;
+
+ case EOpExp: out << "exp"; break;
+ case EOpLog: out << "log"; break;
+ case EOpExp2: out << "exp2"; break;
+ case EOpLog2: out << "log2"; break;
+ case EOpSqrt: out << "sqrt"; break;
+ case EOpInverseSqrt: out << "inverse sqrt"; break;
+
+ case EOpAbs: out << "Absolute value"; break;
+ case EOpSign: out << "Sign"; break;
+ case EOpFloor: out << "Floor"; break;
+ case EOpTrunc: out << "Truncate"; break;
+ case EOpRound: out << "Round"; break;
+ case EOpRoundEven: out << "Round half even"; break;
+ case EOpCeil: out << "Ceiling"; break;
+ case EOpFract: out << "Fraction"; break;
+ case EOpIsNan: out << "Is not a number"; break;
+ case EOpIsInf: out << "Is infinity"; break;
+
+ case EOpFloatBitsToInt: out << "float bits to int"; break;
+ case EOpFloatBitsToUint: out << "float bits to uint"; break;
+ case EOpIntBitsToFloat: out << "int bits to float"; break;
+ case EOpUintBitsToFloat: out << "uint bits to float"; break;
+
+ case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break;
+ case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break;
+ case EOpPackHalf2x16: out << "pack half 2x16"; break;
+
+ case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break;
+ case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break;
+ case EOpUnpackHalf2x16: out << "unpack half 2x16"; break;
+
+ case EOpLength: out << "length"; break;
+ case EOpNormalize: out << "normalize"; break;
+ // case EOpDPdx: out << "dPdx"; break;
+ // case EOpDPdy: out << "dPdy"; break;
+ // case EOpFwidth: out << "fwidth"; break;
+
+ case EOpDeterminant: out << "determinant"; break;
+ case EOpTranspose: out << "transpose"; break;
+ case EOpInverse: out << "inverse"; break;
+
+ case EOpAny: out << "any"; break;
+ case EOpAll: out << "all"; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad unary op";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TInfoSinkBase &out = sink;
+ OutputTreeText(out, node, mDepth);
+ OutputFunction(out, "Function Definition", node->getFunctionSymbolInfo());
+ out << "\n";
+ return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ if (node->getOp() == EOpNull)
+ {
+ out.prefix(EPrefixError);
+ out << "node is still EOpNull!\n";
+ return true;
+ }
+
+
+ switch (node->getOp())
+ {
+ case EOpFunctionCall:
+ OutputFunction(out, "Function Call", node->getFunctionSymbolInfo());
+ break;
+ case EOpParameters: out << "Function Parameters: "; break;
+ case EOpPrototype:
+ OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
+ break;
+
+ case EOpConstructFloat: out << "Construct float"; break;
+ case EOpConstructVec2: out << "Construct vec2"; break;
+ case EOpConstructVec3: out << "Construct vec3"; break;
+ case EOpConstructVec4: out << "Construct vec4"; break;
+ case EOpConstructBool: out << "Construct bool"; break;
+ case EOpConstructBVec2: out << "Construct bvec2"; break;
+ case EOpConstructBVec3: out << "Construct bvec3"; break;
+ case EOpConstructBVec4: out << "Construct bvec4"; break;
+ case EOpConstructInt: out << "Construct int"; break;
+ case EOpConstructIVec2: out << "Construct ivec2"; break;
+ case EOpConstructIVec3: out << "Construct ivec3"; break;
+ case EOpConstructIVec4: out << "Construct ivec4"; break;
+ case EOpConstructUInt: out << "Construct uint"; break;
+ case EOpConstructUVec2: out << "Construct uvec2"; break;
+ case EOpConstructUVec3: out << "Construct uvec3"; break;
+ case EOpConstructUVec4: out << "Construct uvec4"; break;
+ case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat2x3: out << "Construct mat2x3"; break;
+ case EOpConstructMat2x4: out << "Construct mat2x4"; break;
+ case EOpConstructMat3x2: out << "Construct mat3x2"; break;
+ case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat3x4: out << "Construct mat3x4"; break;
+ case EOpConstructMat4x2: out << "Construct mat4x2"; break;
+ case EOpConstructMat4x3: out << "Construct mat4x3"; break;
+ case EOpConstructMat4: out << "Construct mat4"; break;
+ case EOpConstructStruct: out << "Construct structure"; break;
+
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+ case EOpVectorEqual: out << "Equal"; break;
+ case EOpVectorNotEqual: out << "NotEqual"; break;
+
+ case EOpMod: out << "mod"; break;
+ case EOpModf: out << "modf"; break;
+ case EOpPow: out << "pow"; break;
+
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpMin: out << "min"; break;
+ case EOpMax: out << "max"; break;
+ case EOpClamp: out << "clamp"; break;
+ case EOpMix: out << "mix"; break;
+ case EOpStep: out << "step"; break;
+ case EOpSmoothStep: out << "smoothstep"; break;
+
+ case EOpDistance: out << "distance"; break;
+ case EOpDot: out << "dot-product"; break;
+ case EOpCross: out << "cross-product"; break;
+ case EOpFaceForward: out << "face-forward"; break;
+ case EOpReflect: out << "reflect"; break;
+ case EOpRefract: out << "refract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+
+ case EOpOuterProduct: out << "outer product"; break;
+
+ case EOpDeclaration: out << "Declaration: "; break;
+ case EOpInvariantDeclaration: out << "Invariant Declaration: "; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad aggregation op";
+ }
+
+ if (node->getOp() != EOpParameters)
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+ out << "Code block\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ out << "Ternary selection";
+ out << " (" << node->getCompleteString() << ")\n";
+
+ ++mDepth;
+
+ OutputTreeText(sink, node, mDepth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, mDepth);
+ if (node->getTrueExpression())
+ {
+ out << "true case\n";
+ node->getTrueExpression()->traverse(this);
+ }
+ if (node->getFalseExpression())
+ {
+ OutputTreeText(sink, node, mDepth);
+ out << "false case\n";
+ node->getFalseExpression()->traverse(this);
+ }
+
+ --mDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ out << "If test\n";
+
+ ++mDepth;
+
+ OutputTreeText(sink, node, mDepth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, mDepth);
+ if (node->getTrueBlock())
+ {
+ out << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ }
+ else
+ {
+ out << "true case is null\n";
+ }
+
+ if (node->getFalseBlock())
+ {
+ OutputTreeText(sink, node, mDepth);
+ out << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --mDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ out << "Switch\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ if (node->getCondition() == nullptr)
+ {
+ out << "Default\n";
+ }
+ else
+ {
+ out << "Case\n";
+ }
+
+ return true;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ TInfoSinkBase &out = sink;
+
+ size_t size = node->getType().getObjectSize();
+
+ for (size_t i = 0; i < size; i++)
+ {
+ OutputTreeText(out, node, mDepth);
+ switch (node->getUnionArrayPointer()[i].getType())
+ {
+ case EbtBool:
+ if (node->getUnionArrayPointer()[i].getBConst())
+ out << "true";
+ else
+ out << "false";
+
+ out << " (" << "const bool" << ")";
+ out << "\n";
+ break;
+ case EbtFloat:
+ out << node->getUnionArrayPointer()[i].getFConst();
+ out << " (const float)\n";
+ break;
+ case EbtInt:
+ out << node->getUnionArrayPointer()[i].getIConst();
+ out << " (const int)\n";
+ break;
+ case EbtUInt:
+ out << node->getUnionArrayPointer()[i].getUConst();
+ out << " (const uint)\n";
+ break;
+ default:
+ out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ out << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ out << "not ";
+ out << "tested first\n";
+
+ ++mDepth;
+
+ OutputTreeText(sink, node, mDepth);
+ if (node->getCondition())
+ {
+ out << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ }
+ else
+ {
+ out << "No loop condition\n";
+ }
+
+ OutputTreeText(sink, node, mDepth);
+ if (node->getBody())
+ {
+ out << "Loop Body\n";
+ node->getBody()->traverse(this);
+ }
+ else
+ {
+ out << "No loop body\n";
+ }
+
+ if (node->getExpression())
+ {
+ OutputTreeText(sink, node, mDepth);
+ out << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --mDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill: out << "Branch: Kill"; break;
+ case EOpBreak: out << "Branch: Break"; break;
+ case EOpContinue: out << "Branch: Continue"; break;
+ case EOpReturn: out << "Branch: Return"; break;
+ default: out << "Branch: Unknown Branch"; break;
+ }
+
+ if (node->getExpression())
+ {
+ out << " with expression\n";
+ ++mDepth;
+ node->getExpression()->traverse(this);
+ --mDepth;
+ }
+ else
+ {
+ out << "\n";
+ }
+
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. Its children will still be processed.
+//
+void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
+{
+ TOutputTraverser it(infoSink);
+
+ ASSERT(root);
+
+ root->traverse(&it);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/length_limits.h b/Source/ThirdParty/ANGLE/src/compiler/translator/length_limits.h
new file mode 100644
index 000000000..88634381f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/length_limits.h
@@ -0,0 +1,21 @@
+//
+// 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.
+
+size_t GetGlobalMaxTokenSize(ShShaderSpec spec);
+
+#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp b/Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp
new file mode 100644
index 000000000..584d65377
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp
@@ -0,0 +1,646 @@
+//
+// 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 "compiler/preprocessor/numeric_lex.h"
+#include "compiler/translator/SymbolTable.h"
+#include "common/utilities.h"
+
+bool strtof_clamp(const std::string &str, float *value)
+{
+ bool success = pp::numeric_lex_float(str, value);
+ if (!success)
+ *value = std::numeric_limits<float>::max();
+ return success;
+}
+
+bool atoi_clamp(const char *str, unsigned int *value)
+{
+ bool success = pp::numeric_lex_int(str, value);
+ if (!success)
+ *value = std::numeric_limits<unsigned int>::max();
+ return success;
+}
+
+namespace sh
+{
+
+GLenum GLVariableType(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ if (type.isScalar())
+ {
+ return GL_FLOAT;
+ }
+ else 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();
+ }
+ }
+ 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();
+ }
+
+ 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();
+ }
+
+ 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();
+ }
+
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtInt)
+ {
+ if (type.isScalar())
+ {
+ return GL_INT;
+ }
+ else 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();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtUInt)
+ {
+ if (type.isScalar())
+ {
+ return GL_UNSIGNED_INT;
+ }
+ else 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();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtBool)
+ {
+ if (type.isScalar())
+ {
+ return GL_BOOL;
+ }
+ else 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();
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ 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 EbtSampler2DRect: return GL_SAMPLER_2D_RECT_ARB;
+ case EbtSampler2DArray: return GL_SAMPLER_2D_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 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 EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW;
+ case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW;
+ case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW;
+ 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:
+ // Should be defined as the default precision by the parser
+ 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:
+ // Should be defined as the default precision by the parser
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ // Other types (boolean, sampler) don't have a precision
+ return GL_NONE;
+}
+
+TString ArrayString(const TType &type)
+{
+ if (!type.isArray())
+ {
+ return "";
+ }
+
+ return "[" + str(type.getArraySize()) + "]";
+}
+
+bool IsVaryingOut(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqVaryingOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqVertexOut:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+}
+
+bool IsVaryingIn(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqCentroidIn:
+ case EvqFragmentIn:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+}
+
+bool IsVarying(TQualifier qualifier)
+{
+ return IsVaryingIn(qualifier) || IsVaryingOut(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:
+ return INTERPOLATION_SMOOTH;
+
+ case EvqCentroidIn:
+ case EvqCentroidOut:
+ return INTERPOLATION_CENTROID;
+
+ default: UNREACHABLE();
+ return INTERPOLATION_SMOOTH;
+ }
+}
+
+TType GetInterfaceBlockType(const sh::InterfaceBlock &block)
+{
+ TType type;
+ TFieldList *fields = new TFieldList;
+ TSourceLoc loc;
+ for (const auto &field : block.fields)
+ {
+ TType *fieldType = new TType(GetShaderVariableType(field));
+ fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
+ }
+
+ TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
+ new TString(block.name.c_str()), fields, new TString(block.instanceName.c_str()),
+ block.arraySize, TLayoutQualifier::create());
+
+ type.setBasicType(EbtInterfaceBlock);
+ type.setInterfaceBlock(interfaceBlock);
+ type.setArraySize(block.arraySize);
+ return type;
+}
+
+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();
+ return TType();
+ }
+}
+
+TType GetShaderVariableType(const sh::ShaderVariable &var)
+{
+ TType type;
+ if (var.isStruct())
+ {
+ TFieldList *fields = new TFieldList;
+ TSourceLoc loc;
+ for (const auto &field : var.fields)
+ {
+ TType *fieldType = new TType(GetShaderVariableType(field));
+ fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
+ }
+ TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
+
+ type.setBasicType(EbtStruct);
+ type.setStruct(structure);
+ }
+ else
+ {
+ type = GetShaderVariableBasicType(var);
+ }
+
+ if (var.isArray())
+ {
+ type.setArraySize(var.elementCount());
+ }
+ return type;
+}
+
+TOperator TypeToConstructorOperator(const TType &type)
+{
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ if (type.isMatrix())
+ {
+ switch (type.getCols())
+ {
+ case 2:
+ switch (type.getRows())
+ {
+ case 2:
+ return EOpConstructMat2;
+ case 3:
+ return EOpConstructMat2x3;
+ case 4:
+ return EOpConstructMat2x4;
+ default:
+ break;
+ }
+ break;
+
+ case 3:
+ switch (type.getRows())
+ {
+ case 2:
+ return EOpConstructMat3x2;
+ case 3:
+ return EOpConstructMat3;
+ case 4:
+ return EOpConstructMat3x4;
+ default:
+ break;
+ }
+ break;
+
+ case 4:
+ switch (type.getRows())
+ {
+ case 2:
+ return EOpConstructMat4x2;
+ case 3:
+ return EOpConstructMat4x3;
+ case 4:
+ return EOpConstructMat4;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructFloat;
+ case 2:
+ return EOpConstructVec2;
+ case 3:
+ return EOpConstructVec3;
+ case 4:
+ return EOpConstructVec4;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructInt;
+ case 2:
+ return EOpConstructIVec2;
+ case 3:
+ return EOpConstructIVec3;
+ case 4:
+ return EOpConstructIVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtUInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructUInt;
+ case 2:
+ return EOpConstructUVec2;
+ case 3:
+ return EOpConstructUVec3;
+ case 4:
+ return EOpConstructUVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructBool;
+ case 2:
+ return EOpConstructBVec2;
+ case 3:
+ return EOpConstructBVec3;
+ case 4:
+ return EOpConstructBVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtStruct:
+ return EOpConstructStruct;
+
+ default:
+ break;
+ }
+
+ return EOpNull;
+}
+
+GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable)
+ : mSymbolTable(symbolTable)
+{
+}
+
+template void GetVariableTraverser::setTypeSpecificInfo(
+ const TType &type, const TString& name, InterfaceBlockField *variable);
+template void GetVariableTraverser::setTypeSpecificInfo(
+ const TType &type, const TString& name, ShaderVariable *variable);
+template void GetVariableTraverser::setTypeSpecificInfo(
+ const TType &type, const TString& name, Uniform *variable);
+
+template<>
+void GetVariableTraverser::setTypeSpecificInfo(
+ const TType &type, const TString& name, Varying *variable)
+{
+ ASSERT(variable);
+ switch (type.getQualifier())
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqVertexOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant())
+ {
+ variable->isInvariant = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ variable->interpolation = GetInterpolationType(type.getQualifier());
+}
+
+template <typename VarT>
+void GetVariableTraverser::traverse(const TType &type,
+ const TString &name,
+ std::vector<VarT> *output)
+{
+ const TStructure *structure = type.getStruct();
+
+ VarT variable;
+ variable.name = name.c_str();
+ variable.arraySize = type.getArraySize();
+
+ if (!structure)
+ {
+ variable.type = GLVariableType(type);
+ variable.precision = GLVariablePrecision(type);
+ }
+ else
+ {
+ // Note: this enum value is not exposed outside ANGLE
+ variable.type = GL_STRUCT_ANGLEX;
+ variable.structName = structure->name().c_str();
+
+ const TFieldList &fields = structure->fields();
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ TField *field = fields[fieldIndex];
+ traverse(*field->type(), field->name(), &variable.fields);
+ }
+ }
+ setTypeSpecificInfo(type, name, &variable);
+ visitVariable(&variable);
+
+ ASSERT(output);
+ output->push_back(variable);
+}
+
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<InterfaceBlockField> *);
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<ShaderVariable> *);
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *);
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
+
+// 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;
+}
+} // namespace sh
diff --git a/Source/ThirdParty/ANGLE/src/compiler/translator/util.h b/Source/ThirdParty/ANGLE/src/compiler/translator/util.h
new file mode 100644
index 000000000..b52689165
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/translator/util.h
@@ -0,0 +1,76 @@
+//
+// 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 "angle_gl.h"
+#include <GLSLANG/ShaderLang.h>
+
+#include "compiler/translator/Operator.h"
+#include "compiler/translator/Types.h"
+
+// strtof_clamp is like strtof but
+// 1. it forces C locale, i.e. forcing '.' as decimal point.
+// 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
+// Return false if overflow happens.
+bool strtof_clamp(const std::string &str, float *value);
+
+// 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);
+
+class TSymbolTable;
+
+namespace sh
+{
+
+GLenum GLVariableType(const TType &type);
+GLenum GLVariablePrecision(const TType &type);
+bool IsVaryingIn(TQualifier qualifier);
+bool IsVaryingOut(TQualifier qualifier);
+bool IsVarying(TQualifier qualifier);
+InterpolationType GetInterpolationType(TQualifier qualifier);
+TString ArrayString(const TType &type);
+
+TType GetInterfaceBlockType(const sh::InterfaceBlock &block);
+TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
+TType GetShaderVariableType(const sh::ShaderVariable &var);
+
+TOperator TypeToConstructorOperator(const TType &type);
+
+class GetVariableTraverser : angle::NonCopyable
+{
+ public:
+ GetVariableTraverser(const TSymbolTable &symbolTable);
+ virtual ~GetVariableTraverser() {}
+
+ template <typename VarT>
+ void traverse(const TType &type, const TString &name, std::vector<VarT> *output);
+
+ protected:
+ // May be overloaded
+ virtual void visitVariable(ShaderVariable *newVar) {}
+
+ private:
+ // Helper function called by traverse() to fill specific fields
+ // for attributes/varyings/uniforms.
+ template <typename VarT>
+ void setTypeSpecificInfo(
+ const TType &type, const TString &name, VarT *variable) {}
+
+ const TSymbolTable &mSymbolTable;
+};
+
+bool IsBuiltinOutputVariable(TQualifier qualifier);
+bool IsBuiltinFragmentInputVariable(TQualifier qualifier);
+bool CanBeInvariantESSL1(TQualifier qualifier);
+bool CanBeInvariantESSL3OrGreater(TQualifier qualifier);
+}
+
+#endif // COMPILER_TRANSLATOR_UTIL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/util.cpp b/Source/ThirdParty/ANGLE/src/compiler/util.cpp
deleted file mode 100644
index d6e5eeed9..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/util.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// 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/util.h"
-
-#include <limits>
-
-#include "compiler/preprocessor/numeric_lex.h"
-
-bool atof_clamp(const char *str, float *value)
-{
- bool success = pp::numeric_lex_float(str, value);
- if (!success)
- *value = std::numeric_limits<float>::max();
- return success;
-}
-
-bool atoi_clamp(const char *str, int *value)
-{
- bool success = pp::numeric_lex_int(str, value);
- if (!success)
- *value = std::numeric_limits<int>::max();
- return success;
-}
-
diff --git a/Source/ThirdParty/ANGLE/src/compiler/util.h b/Source/ThirdParty/ANGLE/src/compiler/util.h
deleted file mode 100644
index dc69f3906..000000000
--- a/Source/ThirdParty/ANGLE/src/compiler/util.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// 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_UTIL_H
-#define COMPILER_UTIL_H
-
-// atof_clamp is like atof but
-// 1. it forces C locale, i.e. forcing '.' as decimal point.
-// 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
-// Return false if overflow happens.
-extern bool atof_clamp(const char *str, float *value);
-
-// If overflow happens, clamp the value to INT_MIN or INT_MAX.
-// Return false if overflow happens.
-extern bool atoi_clamp(const char *str, int *value);
-
-#endif // COMPILER_UTIL_H