Browse Source

Added support for GLSL 3 shaders (GLSL 3.30 and GLSL ES 3.00).

To use GLSL 3 in a shader, the first line of the shader has to be: #pragma language glsl3

glsl1 is the default language.

Added “glsl3” graphics feature as part of the table returned by love.graphics.getSupported().

Added love.graphics.validateShader(boolean gles, shadercode). It returns a boolean along with an error string if the shader code has errors for its target language and platform (gles or desktop).

Implemented support for Core Profile OpenGL 3.3 in love.graphics.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
731b5d5cf0
85 changed files with 50243 additions and 287 deletions
  1. 122 0
      CMakeLists.txt
  2. 420 0
      platform/xcode/liblove.xcodeproj/project.pbxproj
  3. 155 0
      src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp
  4. 49 0
      src/libraries/glslang/OGLCompilersDLL/InitializeDll.h
  5. 76 0
      src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp
  6. 91 0
      src/libraries/glslang/glslang/GenericCodeGen/Link.cpp
  7. 355 0
      src/libraries/glslang/glslang/Include/BaseTypes.h
  8. 266 0
      src/libraries/glslang/glslang/Include/Common.h
  9. 617 0
      src/libraries/glslang/glslang/Include/ConstantUnion.h
  10. 144 0
      src/libraries/glslang/glslang/Include/InfoSink.h
  11. 47 0
      src/libraries/glslang/glslang/Include/InitializeGlobals.h
  12. 324 0
      src/libraries/glslang/glslang/Include/PoolAlloc.h
  13. 140 0
      src/libraries/glslang/glslang/Include/ResourceLimits.h
  14. 173 0
      src/libraries/glslang/glslang/Include/ShHandle.h
  15. 1855 0
      src/libraries/glslang/glslang/Include/Types.h
  16. 318 0
      src/libraries/glslang/glslang/Include/arrays.h
  17. 1253 0
      src/libraries/glslang/glslang/Include/intermediate.h
  18. 6 0
      src/libraries/glslang/glslang/Include/revision.h
  19. 995 0
      src/libraries/glslang/glslang/MachineIndependent/Constant.cpp
  20. 113 0
      src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp
  21. 5759 0
      src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp
  22. 112 0
      src/libraries/glslang/glslang/MachineIndependent/Initialize.h
  23. 302 0
      src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp
  24. 2642 0
      src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp
  25. 136 0
      src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h
  26. 604 0
      src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp
  27. 6269 0
      src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp
  28. 464 0
      src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h
  29. 345 0
      src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp
  30. 118 0
      src/libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp
  31. 39 0
      src/libraries/glslang/glslang/MachineIndependent/RemoveTree.h
  32. 1395 0
      src/libraries/glslang/glslang/MachineIndependent/Scan.cpp
  33. 275 0
      src/libraries/glslang/glslang/MachineIndependent/Scan.h
  34. 86 0
      src/libraries/glslang/glslang/MachineIndependent/ScanContext.h
  35. 1800 0
      src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp
  36. 355 0
      src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp
  37. 728 0
      src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h
  38. 734 0
      src/libraries/glslang/glslang/MachineIndependent/Versions.cpp
  39. 218 0
      src/libraries/glslang/glslang/MachineIndependent/Versions.h
  40. 178 0
      src/libraries/glslang/glslang/MachineIndependent/gl_types.h
  41. 8320 0
      src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp
  42. 400 0
      src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
  43. 950 0
      src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp
  44. 404 0
      src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp
  45. 63 0
      src/libraries/glslang/glslang/MachineIndependent/iomapper.h
  46. 198 0
      src/libraries/glslang/glslang/MachineIndependent/limits.cpp
  47. 1220 0
      src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp
  48. 505 0
      src/libraries/glslang/glslang/MachineIndependent/localintermediate.h
  49. 210 0
      src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp
  50. 138 0
      src/libraries/glslang/glslang/MachineIndependent/parseVersions.h
  51. 1278 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp
  52. 177 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp
  53. 115 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp
  54. 603 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h
  55. 81 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp
  56. 840 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
  57. 77 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
  58. 326 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp
  59. 173 0
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h
  60. 866 0
      src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp
  61. 53 0
      src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h
  62. 745 0
      src/libraries/glslang/glslang/MachineIndependent/reflection.cpp
  63. 156 0
      src/libraries/glslang/glslang/MachineIndependent/reflection.h
  64. 205 0
      src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp
  65. 74 0
      src/libraries/glslang/glslang/OSDependent/Windows/main.cpp
  66. 162 0
      src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp
  67. 66 0
      src/libraries/glslang/glslang/OSDependent/osinclude.h
  68. 548 0
      src/libraries/glslang/glslang/Public/ShaderLang.h
  69. 67 38
      src/modules/graphics/Graphics.cpp
  70. 20 2
      src/modules/graphics/Graphics.h
  71. 211 21
      src/modules/graphics/Shader.cpp
  72. 28 6
      src/modules/graphics/Shader.h
  73. 2 46
      src/modules/graphics/StreamBuffer.cpp
  74. 22 26
      src/modules/graphics/StreamBuffer.h
  75. 94 0
      src/modules/graphics/opengl/BufferSync.cpp
  76. 80 0
      src/modules/graphics/opengl/BufferSync.h
  77. 63 23
      src/modules/graphics/opengl/Graphics.cpp
  78. 5 0
      src/modules/graphics/opengl/Graphics.h
  79. 5 10
      src/modules/graphics/opengl/Shader.cpp
  80. 0 3
      src/modules/graphics/opengl/Shader.h
  81. 367 0
      src/modules/graphics/opengl/StreamBuffer.cpp
  82. 36 0
      src/modules/graphics/opengl/StreamBuffer.h
  83. 63 22
      src/modules/graphics/opengl/wrap_Graphics.cpp
  84. 127 69
      src/modules/graphics/opengl/wrap_Graphics.lua
  85. 22 21
      src/modules/window/sdl/Window.cpp

+ 122 - 0
CMakeLists.txt

@@ -503,6 +503,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 )
 
 set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
+	src/modules/graphics/opengl/BufferSync.cpp
+	src/modules/graphics/opengl/BufferSync.h
 	src/modules/graphics/opengl/Canvas.cpp
 	src/modules/graphics/opengl/Canvas.h
 	src/modules/graphics/opengl/Font.cpp
@@ -523,6 +525,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
 	src/modules/graphics/opengl/Shader.h
 	src/modules/graphics/opengl/SpriteBatch.cpp
 	src/modules/graphics/opengl/SpriteBatch.h
+	src/modules/graphics/opengl/StreamBuffer.cpp
+	src/modules/graphics/opengl/StreamBuffer.h
 	src/modules/graphics/opengl/Text.cpp
 	src/modules/graphics/opengl/Text.h
 	src/modules/graphics/opengl/Video.cpp
@@ -1247,6 +1251,123 @@ set(LOVE_SRC_3P_GLAD
 
 add_library(love_3p_glad ${LOVE_SRC_3P_GLAD})
 
+#
+# glslang
+#
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN
+	src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp
+	src/libraries/glslang/glslang/GenericCodeGen/Link.cpp
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE
+	src/libraries/glslang/glslang/Include/arrays.h
+	src/libraries/glslang/glslang/Include/BaseTypes.h
+	src/libraries/glslang/glslang/Include/Common.h
+	src/libraries/glslang/glslang/Include/ConstantUnion.h
+	src/libraries/glslang/glslang/Include/InfoSink.h
+	src/libraries/glslang/glslang/Include/InitializeGlobals.h
+	src/libraries/glslang/glslang/Include/intermediate.h
+	src/libraries/glslang/glslang/Include/PoolAlloc.h
+	src/libraries/glslang/glslang/Include/ResourceLimits.h
+	src/libraries/glslang/glslang/Include/revision.h
+	src/libraries/glslang/glslang/Include/ShHandle.h
+	src/libraries/glslang/glslang/Include/Types.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR}
+	src/libraries/glslang/glslang/MachineIndependent/Constant.cpp
+	src/libraries/glslang/glslang/MachineIndependent/gl_types.h
+	src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp
+	src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
+	src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Initialize.h
+	src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp
+	src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp
+	src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp
+	src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp
+	src/libraries/glslang/glslang/MachineIndependent/iomapper.h
+	src/libraries/glslang/glslang/MachineIndependent/limits.cpp
+	src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp
+	src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h
+	src/libraries/glslang/glslang/MachineIndependent/localintermediate.h
+	src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h
+	src/libraries/glslang/glslang/MachineIndependent/parseVersions.h
+	src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp
+	src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp
+	src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h
+	src/libraries/glslang/glslang/MachineIndependent/reflection.cpp
+	src/libraries/glslang/glslang/MachineIndependent/reflection.h
+	src/libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp
+	src/libraries/glslang/glslang/MachineIndependent/RemoveTree.h
+	src/libraries/glslang/glslang/MachineIndependent/Scan.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Scan.h
+	src/libraries/glslang/glslang/MachineIndependent/ScanContext.h
+	src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp
+	src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp
+	src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h
+	src/libraries/glslang/glslang/MachineIndependent/Versions.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Versions.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+	src/libraries/glslang/glslang/OSDependent/osinclude.h
+)
+
+if(MSVC)
+	set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+		${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+		src/libraries/glslang/glslang/OSDependent/Windows/main.cpp
+		src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp
+	)
+else()
+	set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+		${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+		src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp
+	)
+endif()
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC
+	src/libraries/glslang/glslang/Public/ShaderLang.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC}
+)
+
+set(LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL
+	src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp
+	src/libraries/glslang/OGLCompilersDLL/InitializeDll.h
+)
+
+set(LOVE_SRC_3P_GLSLANG
+	${LOVE_SRC_3P_GLSLANG_GLSLANG}
+	${LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL}
+)
+
+add_library(love_3p_glslang ${LOVE_SRC_3P_GLSLANG})
+
 #
 # LodePNG
 #
@@ -1456,6 +1577,7 @@ set(LOVE_3P
 	love_3p_ddsparse
 	love_3p_enet
 	love_3p_glad
+	love_3p_glslang
 	love_3p_lodepng
 	love_3p_luasocket
 	love_3p_luautf8

+ 420 - 0
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -885,6 +885,9 @@
 		FA27B3C61B4985D8008A9DCE /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3C31B4985D8008A9DCE /* Video.cpp */; };
 		FA27B3C71B4985D8008A9DCE /* Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3C41B4985D8008A9DCE /* Video.h */; };
 		FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3C81B498623008A9DCE /* Theora.framework */; };
+		FA28EBD51E352DB5003446F4 /* BufferSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* BufferSync.cpp */; };
+		FA28EBD61E352DB5003446F4 /* BufferSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* BufferSync.cpp */; };
+		FA28EBD71E352DB5003446F4 /* BufferSync.h in Headers */ = {isa = PBXBuildFile; fileRef = FA28EBD41E352DB5003446F4 /* BufferSync.h */; };
 		FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
 		FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
 		FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; };
@@ -963,6 +966,9 @@
 		FA620A3A1AA305F6005DB4C2 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA620A391AA305F6005DB4C2 /* types.cpp */; };
 		FA620A3B1AA305F6005DB4C2 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA620A391AA305F6005DB4C2 /* types.cpp */; };
 		FA7550A81AEBE276003E311E /* libluajit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA7550A71AEBE276003E311E /* libluajit.a */; };
+		FA76344A1E28722A0066EF9E /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7634481E28722A0066EF9E /* StreamBuffer.cpp */; };
+		FA76344B1E28722A0066EF9E /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7634481E28722A0066EF9E /* StreamBuffer.cpp */; };
+		FA76344C1E28722A0066EF9E /* StreamBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7634491E28722A0066EF9E /* StreamBuffer.h */; };
 		FA8951A21AA2EDF300EC385A /* wrap_Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */; };
 		FA8951A31AA2EDF300EC385A /* wrap_Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */; };
 		FA8951A41AA2EDF300EC385A /* wrap_Event.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8951A11AA2EDF300EC385A /* wrap_Event.h */; };
@@ -1007,6 +1013,102 @@
 		FAB2D5AC1AABDD8A008224A4 /* TrueTypeRasterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB2D5A91AABDD8A008224A4 /* TrueTypeRasterizer.h */; };
 		FAE272521C05A15B00A67640 /* ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE272501C05A15B00A67640 /* ParticleSystem.cpp */; };
 		FAE272531C05A15B00A67640 /* ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE272511C05A15B00A67640 /* ParticleSystem.h */; };
+		FAF140531E20934C00F898D2 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC21E20934C00F898D2 /* CodeGen.cpp */; };
+		FAF140541E20934C00F898D2 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC21E20934C00F898D2 /* CodeGen.cpp */; };
+		FAF140551E20934C00F898D2 /* Link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC31E20934C00F898D2 /* Link.cpp */; };
+		FAF140561E20934C00F898D2 /* Link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC31E20934C00F898D2 /* Link.cpp */; };
+		FAF140571E20934C00F898D2 /* arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FC51E20934C00F898D2 /* arrays.h */; };
+		FAF140581E20934C00F898D2 /* BaseTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FC61E20934C00F898D2 /* BaseTypes.h */; };
+		FAF140591E20934C00F898D2 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FC71E20934C00F898D2 /* Common.h */; };
+		FAF1405A1E20934C00F898D2 /* ConstantUnion.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FC81E20934C00F898D2 /* ConstantUnion.h */; };
+		FAF1405B1E20934C00F898D2 /* InfoSink.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FC91E20934C00F898D2 /* InfoSink.h */; };
+		FAF1405C1E20934C00F898D2 /* InitializeGlobals.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FCA1E20934C00F898D2 /* InitializeGlobals.h */; };
+		FAF1405D1E20934C00F898D2 /* intermediate.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FCB1E20934C00F898D2 /* intermediate.h */; };
+		FAF1405E1E20934C00F898D2 /* PoolAlloc.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FCC1E20934C00F898D2 /* PoolAlloc.h */; };
+		FAF1405F1E20934C00F898D2 /* ResourceLimits.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FCD1E20934C00F898D2 /* ResourceLimits.h */; };
+		FAF140601E20934C00F898D2 /* revision.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FCE1E20934C00F898D2 /* revision.h */; };
+		FAF140621E20934C00F898D2 /* ShHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FD01E20934C00F898D2 /* ShHandle.h */; };
+		FAF140631E20934C00F898D2 /* Types.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FD11E20934C00F898D2 /* Types.h */; };
+		FAF140641E20934C00F898D2 /* Constant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD31E20934C00F898D2 /* Constant.cpp */; };
+		FAF140651E20934C00F898D2 /* Constant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD31E20934C00F898D2 /* Constant.cpp */; };
+		FAF140661E20934C00F898D2 /* gl_types.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FD41E20934C00F898D2 /* gl_types.h */; };
+		FAF140691E20934C00F898D2 /* glslang_tab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD61E20934C00F898D2 /* glslang_tab.cpp */; };
+		FAF1406A1E20934C00F898D2 /* glslang_tab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD61E20934C00F898D2 /* glslang_tab.cpp */; };
+		FAF1406B1E20934C00F898D2 /* glslang_tab.cpp.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FD71E20934C00F898D2 /* glslang_tab.cpp.h */; };
+		FAF1406C1E20934C00F898D2 /* InfoSink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD81E20934C00F898D2 /* InfoSink.cpp */; };
+		FAF1406D1E20934C00F898D2 /* InfoSink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD81E20934C00F898D2 /* InfoSink.cpp */; };
+		FAF1406E1E20934C00F898D2 /* Initialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD91E20934C00F898D2 /* Initialize.cpp */; };
+		FAF1406F1E20934C00F898D2 /* Initialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FD91E20934C00F898D2 /* Initialize.cpp */; };
+		FAF140701E20934C00F898D2 /* Initialize.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FDA1E20934C00F898D2 /* Initialize.h */; };
+		FAF140711E20934C00F898D2 /* Intermediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDB1E20934C00F898D2 /* Intermediate.cpp */; };
+		FAF140721E20934C00F898D2 /* Intermediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDB1E20934C00F898D2 /* Intermediate.cpp */; };
+		FAF140731E20934C00F898D2 /* intermOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDC1E20934C00F898D2 /* intermOut.cpp */; };
+		FAF140741E20934C00F898D2 /* intermOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDC1E20934C00F898D2 /* intermOut.cpp */; };
+		FAF140751E20934C00F898D2 /* IntermTraverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDD1E20934C00F898D2 /* IntermTraverse.cpp */; };
+		FAF140761E20934C00F898D2 /* IntermTraverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDD1E20934C00F898D2 /* IntermTraverse.cpp */; };
+		FAF140771E20934C00F898D2 /* iomapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDE1E20934C00F898D2 /* iomapper.cpp */; };
+		FAF140781E20934C00F898D2 /* iomapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FDE1E20934C00F898D2 /* iomapper.cpp */; };
+		FAF140791E20934C00F898D2 /* iomapper.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FDF1E20934C00F898D2 /* iomapper.h */; };
+		FAF1407A1E20934C00F898D2 /* limits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE01E20934C00F898D2 /* limits.cpp */; };
+		FAF1407B1E20934C00F898D2 /* limits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE01E20934C00F898D2 /* limits.cpp */; };
+		FAF1407C1E20934C00F898D2 /* linkValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE11E20934C00F898D2 /* linkValidate.cpp */; };
+		FAF1407D1E20934C00F898D2 /* linkValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE11E20934C00F898D2 /* linkValidate.cpp */; };
+		FAF1407E1E20934C00F898D2 /* LiveTraverser.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FE21E20934C00F898D2 /* LiveTraverser.h */; };
+		FAF1407F1E20934C00F898D2 /* localintermediate.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FE31E20934C00F898D2 /* localintermediate.h */; };
+		FAF140801E20934C00F898D2 /* parseConst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE41E20934C00F898D2 /* parseConst.cpp */; };
+		FAF140811E20934C00F898D2 /* parseConst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE41E20934C00F898D2 /* parseConst.cpp */; };
+		FAF140821E20934C00F898D2 /* ParseContextBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE51E20934C00F898D2 /* ParseContextBase.cpp */; };
+		FAF140831E20934C00F898D2 /* ParseContextBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE51E20934C00F898D2 /* ParseContextBase.cpp */; };
+		FAF140841E20934C00F898D2 /* ParseHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE61E20934C00F898D2 /* ParseHelper.cpp */; };
+		FAF140851E20934C00F898D2 /* ParseHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE61E20934C00F898D2 /* ParseHelper.cpp */; };
+		FAF140861E20934C00F898D2 /* ParseHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FE71E20934C00F898D2 /* ParseHelper.h */; };
+		FAF140871E20934C00F898D2 /* parseVersions.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FE81E20934C00F898D2 /* parseVersions.h */; };
+		FAF140881E20934C00F898D2 /* PoolAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE91E20934C00F898D2 /* PoolAlloc.cpp */; };
+		FAF140891E20934C00F898D2 /* PoolAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FE91E20934C00F898D2 /* PoolAlloc.cpp */; };
+		FAF1408A1E20934C00F898D2 /* Pp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEB1E20934C00F898D2 /* Pp.cpp */; };
+		FAF1408B1E20934C00F898D2 /* Pp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEB1E20934C00F898D2 /* Pp.cpp */; };
+		FAF1408C1E20934C00F898D2 /* PpAtom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEC1E20934C00F898D2 /* PpAtom.cpp */; };
+		FAF1408D1E20934C00F898D2 /* PpAtom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEC1E20934C00F898D2 /* PpAtom.cpp */; };
+		FAF1408E1E20934C00F898D2 /* PpContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FED1E20934C00F898D2 /* PpContext.cpp */; };
+		FAF1408F1E20934C00F898D2 /* PpContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FED1E20934C00F898D2 /* PpContext.cpp */; };
+		FAF140901E20934C00F898D2 /* PpContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FEE1E20934C00F898D2 /* PpContext.h */; };
+		FAF140911E20934C00F898D2 /* PpMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEF1E20934C00F898D2 /* PpMemory.cpp */; };
+		FAF140921E20934C00F898D2 /* PpMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FEF1E20934C00F898D2 /* PpMemory.cpp */; };
+		FAF140931E20934C00F898D2 /* PpScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF01E20934C00F898D2 /* PpScanner.cpp */; };
+		FAF140941E20934C00F898D2 /* PpScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF01E20934C00F898D2 /* PpScanner.cpp */; };
+		FAF140951E20934C00F898D2 /* PpSymbols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF11E20934C00F898D2 /* PpSymbols.cpp */; };
+		FAF140961E20934C00F898D2 /* PpSymbols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF11E20934C00F898D2 /* PpSymbols.cpp */; };
+		FAF140971E20934C00F898D2 /* PpTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF21E20934C00F898D2 /* PpTokens.cpp */; };
+		FAF140981E20934C00F898D2 /* PpTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF21E20934C00F898D2 /* PpTokens.cpp */; };
+		FAF140991E20934C00F898D2 /* PpTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FF31E20934C00F898D2 /* PpTokens.h */; };
+		FAF1409A1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF41E20934C00F898D2 /* propagateNoContraction.cpp */; };
+		FAF1409B1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF41E20934C00F898D2 /* propagateNoContraction.cpp */; };
+		FAF1409C1E20934C00F898D2 /* propagateNoContraction.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FF51E20934C00F898D2 /* propagateNoContraction.h */; };
+		FAF1409D1E20934C00F898D2 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF61E20934C00F898D2 /* reflection.cpp */; };
+		FAF1409E1E20934C00F898D2 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF61E20934C00F898D2 /* reflection.cpp */; };
+		FAF1409F1E20934C00F898D2 /* reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FF71E20934C00F898D2 /* reflection.h */; };
+		FAF140A01E20934C00F898D2 /* RemoveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF81E20934C00F898D2 /* RemoveTree.cpp */; };
+		FAF140A11E20934C00F898D2 /* RemoveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FF81E20934C00F898D2 /* RemoveTree.cpp */; };
+		FAF140A21E20934C00F898D2 /* RemoveTree.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FF91E20934C00F898D2 /* RemoveTree.h */; };
+		FAF140A31E20934C00F898D2 /* Scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFA1E20934C00F898D2 /* Scan.cpp */; };
+		FAF140A41E20934C00F898D2 /* Scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFA1E20934C00F898D2 /* Scan.cpp */; };
+		FAF140A51E20934C00F898D2 /* Scan.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FFB1E20934C00F898D2 /* Scan.h */; };
+		FAF140A61E20934C00F898D2 /* ScanContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FFC1E20934C00F898D2 /* ScanContext.h */; };
+		FAF140A71E20934C00F898D2 /* ShaderLang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFD1E20934C00F898D2 /* ShaderLang.cpp */; };
+		FAF140A81E20934C00F898D2 /* ShaderLang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFD1E20934C00F898D2 /* ShaderLang.cpp */; };
+		FAF140A91E20934C00F898D2 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFE1E20934C00F898D2 /* SymbolTable.cpp */; };
+		FAF140AA1E20934C00F898D2 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FFE1E20934C00F898D2 /* SymbolTable.cpp */; };
+		FAF140AB1E20934C00F898D2 /* SymbolTable.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF13FFF1E20934C00F898D2 /* SymbolTable.h */; };
+		FAF140AC1E20934C00F898D2 /* Versions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140001E20934C00F898D2 /* Versions.cpp */; };
+		FAF140AD1E20934C00F898D2 /* Versions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140001E20934C00F898D2 /* Versions.cpp */; };
+		FAF140AE1E20934C00F898D2 /* Versions.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF140011E20934C00F898D2 /* Versions.h */; };
+		FAF140AF1E20934C00F898D2 /* osinclude.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF140031E20934C00F898D2 /* osinclude.h */; };
+		FAF140BB1E20934C00F898D2 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140211E20934C00F898D2 /* ossource.cpp */; };
+		FAF140BC1E20934C00F898D2 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140211E20934C00F898D2 /* ossource.cpp */; };
+		FAF140C41E20934C00F898D2 /* ShaderLang.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF140291E20934C00F898D2 /* ShaderLang.h */; };
+		FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
+		FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
+		FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF1403C1E20934C00F898D2 /* InitializeDll.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -1645,6 +1747,8 @@
 		FA27B3C81B498623008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
 		FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
 		FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
+		FA28EBD31E352DB5003446F4 /* BufferSync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BufferSync.cpp; sourceTree = "<group>"; };
+		FA28EBD41E352DB5003446F4 /* BufferSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferSync.h; sourceTree = "<group>"; };
 		FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = "<group>"; };
 		FA2AF6711DAC76FF0032B62C /* vertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vertex.h; sourceTree = "<group>"; };
 		FA2AF6721DAD62710032B62C /* StreamBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
@@ -1696,6 +1800,8 @@
 		FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
 		FA6AE6041B3335EC00583D5C /* wrap_Graphics.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_Graphics.lua; sourceTree = "<group>"; };
 		FA7550A71AEBE276003E311E /* libluajit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libluajit.a; sourceTree = "<group>"; };
+		FA7634481E28722A0066EF9E /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = "<group>"; };
+		FA7634491E28722A0066EF9E /* StreamBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
 		FA7DA04C1C16874A0056B200 /* wrap_Math.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_Math.lua; sourceTree = "<group>"; };
 		FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Event.cpp; sourceTree = "<group>"; };
 		FA8951A11AA2EDF300EC385A /* wrap_Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = "<group>"; };
@@ -1729,6 +1835,70 @@
 		FAC734C21B2E628700AB460A /* wrap_ImageData.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_ImageData.lua; sourceTree = "<group>"; };
 		FAE272501C05A15B00A67640 /* ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleSystem.cpp; sourceTree = "<group>"; };
 		FAE272511C05A15B00A67640 /* ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleSystem.h; sourceTree = "<group>"; };
+		FAF13FC21E20934C00F898D2 /* CodeGen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGen.cpp; sourceTree = "<group>"; };
+		FAF13FC31E20934C00F898D2 /* Link.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Link.cpp; sourceTree = "<group>"; };
+		FAF13FC51E20934C00F898D2 /* arrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arrays.h; sourceTree = "<group>"; };
+		FAF13FC61E20934C00F898D2 /* BaseTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseTypes.h; sourceTree = "<group>"; };
+		FAF13FC71E20934C00F898D2 /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
+		FAF13FC81E20934C00F898D2 /* ConstantUnion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantUnion.h; sourceTree = "<group>"; };
+		FAF13FC91E20934C00F898D2 /* InfoSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InfoSink.h; sourceTree = "<group>"; };
+		FAF13FCA1E20934C00F898D2 /* InitializeGlobals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeGlobals.h; sourceTree = "<group>"; };
+		FAF13FCB1E20934C00F898D2 /* intermediate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intermediate.h; sourceTree = "<group>"; };
+		FAF13FCC1E20934C00F898D2 /* PoolAlloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoolAlloc.h; sourceTree = "<group>"; };
+		FAF13FCD1E20934C00F898D2 /* ResourceLimits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLimits.h; sourceTree = "<group>"; };
+		FAF13FCE1E20934C00F898D2 /* revision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = revision.h; sourceTree = "<group>"; };
+		FAF13FD01E20934C00F898D2 /* ShHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShHandle.h; sourceTree = "<group>"; };
+		FAF13FD11E20934C00F898D2 /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
+		FAF13FD31E20934C00F898D2 /* Constant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Constant.cpp; sourceTree = "<group>"; };
+		FAF13FD41E20934C00F898D2 /* gl_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gl_types.h; sourceTree = "<group>"; };
+		FAF13FD61E20934C00F898D2 /* glslang_tab.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glslang_tab.cpp; sourceTree = "<group>"; };
+		FAF13FD71E20934C00F898D2 /* glslang_tab.cpp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glslang_tab.cpp.h; sourceTree = "<group>"; };
+		FAF13FD81E20934C00F898D2 /* InfoSink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InfoSink.cpp; sourceTree = "<group>"; };
+		FAF13FD91E20934C00F898D2 /* Initialize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Initialize.cpp; sourceTree = "<group>"; };
+		FAF13FDA1E20934C00F898D2 /* Initialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Initialize.h; sourceTree = "<group>"; };
+		FAF13FDB1E20934C00F898D2 /* Intermediate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Intermediate.cpp; sourceTree = "<group>"; };
+		FAF13FDC1E20934C00F898D2 /* intermOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = intermOut.cpp; sourceTree = "<group>"; };
+		FAF13FDD1E20934C00F898D2 /* IntermTraverse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermTraverse.cpp; sourceTree = "<group>"; };
+		FAF13FDE1E20934C00F898D2 /* iomapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iomapper.cpp; sourceTree = "<group>"; };
+		FAF13FDF1E20934C00F898D2 /* iomapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iomapper.h; sourceTree = "<group>"; };
+		FAF13FE01E20934C00F898D2 /* limits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = limits.cpp; sourceTree = "<group>"; };
+		FAF13FE11E20934C00F898D2 /* linkValidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = linkValidate.cpp; sourceTree = "<group>"; };
+		FAF13FE21E20934C00F898D2 /* LiveTraverser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiveTraverser.h; sourceTree = "<group>"; };
+		FAF13FE31E20934C00F898D2 /* localintermediate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = localintermediate.h; sourceTree = "<group>"; };
+		FAF13FE41E20934C00F898D2 /* parseConst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parseConst.cpp; sourceTree = "<group>"; };
+		FAF13FE51E20934C00F898D2 /* ParseContextBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseContextBase.cpp; sourceTree = "<group>"; };
+		FAF13FE61E20934C00F898D2 /* ParseHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHelper.cpp; sourceTree = "<group>"; };
+		FAF13FE71E20934C00F898D2 /* ParseHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseHelper.h; sourceTree = "<group>"; };
+		FAF13FE81E20934C00F898D2 /* parseVersions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parseVersions.h; sourceTree = "<group>"; };
+		FAF13FE91E20934C00F898D2 /* PoolAlloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoolAlloc.cpp; sourceTree = "<group>"; };
+		FAF13FEB1E20934C00F898D2 /* Pp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Pp.cpp; sourceTree = "<group>"; };
+		FAF13FEC1E20934C00F898D2 /* PpAtom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpAtom.cpp; sourceTree = "<group>"; };
+		FAF13FED1E20934C00F898D2 /* PpContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpContext.cpp; sourceTree = "<group>"; };
+		FAF13FEE1E20934C00F898D2 /* PpContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PpContext.h; sourceTree = "<group>"; };
+		FAF13FEF1E20934C00F898D2 /* PpMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpMemory.cpp; sourceTree = "<group>"; };
+		FAF13FF01E20934C00F898D2 /* PpScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpScanner.cpp; sourceTree = "<group>"; };
+		FAF13FF11E20934C00F898D2 /* PpSymbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpSymbols.cpp; sourceTree = "<group>"; };
+		FAF13FF21E20934C00F898D2 /* PpTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PpTokens.cpp; sourceTree = "<group>"; };
+		FAF13FF31E20934C00F898D2 /* PpTokens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PpTokens.h; sourceTree = "<group>"; };
+		FAF13FF41E20934C00F898D2 /* propagateNoContraction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = propagateNoContraction.cpp; sourceTree = "<group>"; };
+		FAF13FF51E20934C00F898D2 /* propagateNoContraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = propagateNoContraction.h; sourceTree = "<group>"; };
+		FAF13FF61E20934C00F898D2 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reflection.cpp; sourceTree = "<group>"; };
+		FAF13FF71E20934C00F898D2 /* reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflection.h; sourceTree = "<group>"; };
+		FAF13FF81E20934C00F898D2 /* RemoveTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveTree.cpp; sourceTree = "<group>"; };
+		FAF13FF91E20934C00F898D2 /* RemoveTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveTree.h; sourceTree = "<group>"; };
+		FAF13FFA1E20934C00F898D2 /* Scan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Scan.cpp; sourceTree = "<group>"; };
+		FAF13FFB1E20934C00F898D2 /* Scan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scan.h; sourceTree = "<group>"; };
+		FAF13FFC1E20934C00F898D2 /* ScanContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanContext.h; sourceTree = "<group>"; };
+		FAF13FFD1E20934C00F898D2 /* ShaderLang.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderLang.cpp; sourceTree = "<group>"; };
+		FAF13FFE1E20934C00F898D2 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
+		FAF13FFF1E20934C00F898D2 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolTable.h; sourceTree = "<group>"; };
+		FAF140001E20934C00F898D2 /* Versions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Versions.cpp; sourceTree = "<group>"; };
+		FAF140011E20934C00F898D2 /* Versions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Versions.h; sourceTree = "<group>"; };
+		FAF140031E20934C00F898D2 /* osinclude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osinclude.h; sourceTree = "<group>"; };
+		FAF140211E20934C00F898D2 /* ossource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ossource.cpp; sourceTree = "<group>"; };
+		FAF140291E20934C00F898D2 /* ShaderLang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShaderLang.h; sourceTree = "<group>"; };
+		FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
+		FAF1403C1E20934C00F898D2 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -1879,6 +2049,7 @@
 				FA0B79B41A958EA3000E1D17 /* ddsparse */,
 				FA0B79B81A958EA3000E1D17 /* enet */,
 				FA0B79D31A958EA3000E1D17 /* glad */,
+				FAF13FBF1E20934C00F898D2 /* glslang */,
 				FA0B79D81A958EA3000E1D17 /* lodepng */,
 				FA0B79DB1A958EA3000E1D17 /* luasocket */,
 				FA0B7A101A958EA3000E1D17 /* luautf8 */,
@@ -2487,6 +2658,8 @@
 		FA0B7B8C1A95902C000E1D17 /* opengl */ = {
 			isa = PBXGroup;
 			children = (
+				FA28EBD31E352DB5003446F4 /* BufferSync.cpp */,
+				FA28EBD41E352DB5003446F4 /* BufferSync.h */,
 				FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */,
 				FA0B7B8E1A95902C000E1D17 /* Canvas.h */,
 				FA0B7B8F1A95902C000E1D17 /* Font.cpp */,
@@ -2507,6 +2680,8 @@
 				FA0B7B9E1A95902C000E1D17 /* Shader.h */,
 				FA0B7B9F1A95902C000E1D17 /* SpriteBatch.cpp */,
 				FA0B7BA01A95902C000E1D17 /* SpriteBatch.h */,
+				FA7634481E28722A0066EF9E /* StreamBuffer.cpp */,
+				FA7634491E28722A0066EF9E /* StreamBuffer.h */,
 				FA0B7BA11A95902C000E1D17 /* Text.cpp */,
 				FA0B7BA21A95902C000E1D17 /* Text.h */,
 				FA27B3C31B4985D8008A9DCE /* Video.cpp */,
@@ -3137,6 +3312,149 @@
 			path = lz4;
 			sourceTree = "<group>";
 		};
+		FAF13FBF1E20934C00F898D2 /* glslang */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FC01E20934C00F898D2 /* glslang */,
+				FAF1403A1E20934C00F898D2 /* OGLCompilersDLL */,
+			);
+			path = glslang;
+			sourceTree = "<group>";
+		};
+		FAF13FC01E20934C00F898D2 /* glslang */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FC11E20934C00F898D2 /* GenericCodeGen */,
+				FAF13FC41E20934C00F898D2 /* Include */,
+				FAF13FD21E20934C00F898D2 /* MachineIndependent */,
+				FAF140021E20934C00F898D2 /* OSDependent */,
+				FAF140281E20934C00F898D2 /* Public */,
+			);
+			path = glslang;
+			sourceTree = "<group>";
+		};
+		FAF13FC11E20934C00F898D2 /* GenericCodeGen */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FC21E20934C00F898D2 /* CodeGen.cpp */,
+				FAF13FC31E20934C00F898D2 /* Link.cpp */,
+			);
+			path = GenericCodeGen;
+			sourceTree = "<group>";
+		};
+		FAF13FC41E20934C00F898D2 /* Include */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FC51E20934C00F898D2 /* arrays.h */,
+				FAF13FC61E20934C00F898D2 /* BaseTypes.h */,
+				FAF13FC71E20934C00F898D2 /* Common.h */,
+				FAF13FC81E20934C00F898D2 /* ConstantUnion.h */,
+				FAF13FC91E20934C00F898D2 /* InfoSink.h */,
+				FAF13FCA1E20934C00F898D2 /* InitializeGlobals.h */,
+				FAF13FCB1E20934C00F898D2 /* intermediate.h */,
+				FAF13FCC1E20934C00F898D2 /* PoolAlloc.h */,
+				FAF13FCD1E20934C00F898D2 /* ResourceLimits.h */,
+				FAF13FCE1E20934C00F898D2 /* revision.h */,
+				FAF13FD01E20934C00F898D2 /* ShHandle.h */,
+				FAF13FD11E20934C00F898D2 /* Types.h */,
+			);
+			path = Include;
+			sourceTree = "<group>";
+		};
+		FAF13FD21E20934C00F898D2 /* MachineIndependent */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FD31E20934C00F898D2 /* Constant.cpp */,
+				FAF13FD41E20934C00F898D2 /* gl_types.h */,
+				FAF13FD61E20934C00F898D2 /* glslang_tab.cpp */,
+				FAF13FD71E20934C00F898D2 /* glslang_tab.cpp.h */,
+				FAF13FD81E20934C00F898D2 /* InfoSink.cpp */,
+				FAF13FD91E20934C00F898D2 /* Initialize.cpp */,
+				FAF13FDA1E20934C00F898D2 /* Initialize.h */,
+				FAF13FDB1E20934C00F898D2 /* Intermediate.cpp */,
+				FAF13FDC1E20934C00F898D2 /* intermOut.cpp */,
+				FAF13FDD1E20934C00F898D2 /* IntermTraverse.cpp */,
+				FAF13FDE1E20934C00F898D2 /* iomapper.cpp */,
+				FAF13FDF1E20934C00F898D2 /* iomapper.h */,
+				FAF13FE01E20934C00F898D2 /* limits.cpp */,
+				FAF13FE11E20934C00F898D2 /* linkValidate.cpp */,
+				FAF13FE21E20934C00F898D2 /* LiveTraverser.h */,
+				FAF13FE31E20934C00F898D2 /* localintermediate.h */,
+				FAF13FE41E20934C00F898D2 /* parseConst.cpp */,
+				FAF13FE51E20934C00F898D2 /* ParseContextBase.cpp */,
+				FAF13FE61E20934C00F898D2 /* ParseHelper.cpp */,
+				FAF13FE71E20934C00F898D2 /* ParseHelper.h */,
+				FAF13FE81E20934C00F898D2 /* parseVersions.h */,
+				FAF13FE91E20934C00F898D2 /* PoolAlloc.cpp */,
+				FAF13FEA1E20934C00F898D2 /* preprocessor */,
+				FAF13FF41E20934C00F898D2 /* propagateNoContraction.cpp */,
+				FAF13FF51E20934C00F898D2 /* propagateNoContraction.h */,
+				FAF13FF61E20934C00F898D2 /* reflection.cpp */,
+				FAF13FF71E20934C00F898D2 /* reflection.h */,
+				FAF13FF81E20934C00F898D2 /* RemoveTree.cpp */,
+				FAF13FF91E20934C00F898D2 /* RemoveTree.h */,
+				FAF13FFA1E20934C00F898D2 /* Scan.cpp */,
+				FAF13FFB1E20934C00F898D2 /* Scan.h */,
+				FAF13FFC1E20934C00F898D2 /* ScanContext.h */,
+				FAF13FFD1E20934C00F898D2 /* ShaderLang.cpp */,
+				FAF13FFE1E20934C00F898D2 /* SymbolTable.cpp */,
+				FAF13FFF1E20934C00F898D2 /* SymbolTable.h */,
+				FAF140001E20934C00F898D2 /* Versions.cpp */,
+				FAF140011E20934C00F898D2 /* Versions.h */,
+			);
+			path = MachineIndependent;
+			sourceTree = "<group>";
+		};
+		FAF13FEA1E20934C00F898D2 /* preprocessor */ = {
+			isa = PBXGroup;
+			children = (
+				FAF13FEB1E20934C00F898D2 /* Pp.cpp */,
+				FAF13FEC1E20934C00F898D2 /* PpAtom.cpp */,
+				FAF13FED1E20934C00F898D2 /* PpContext.cpp */,
+				FAF13FEE1E20934C00F898D2 /* PpContext.h */,
+				FAF13FEF1E20934C00F898D2 /* PpMemory.cpp */,
+				FAF13FF01E20934C00F898D2 /* PpScanner.cpp */,
+				FAF13FF11E20934C00F898D2 /* PpSymbols.cpp */,
+				FAF13FF21E20934C00F898D2 /* PpTokens.cpp */,
+				FAF13FF31E20934C00F898D2 /* PpTokens.h */,
+			);
+			path = preprocessor;
+			sourceTree = "<group>";
+		};
+		FAF140021E20934C00F898D2 /* OSDependent */ = {
+			isa = PBXGroup;
+			children = (
+				FAF140031E20934C00F898D2 /* osinclude.h */,
+				FAF140041E20934C00F898D2 /* Unix */,
+			);
+			path = OSDependent;
+			sourceTree = "<group>";
+		};
+		FAF140041E20934C00F898D2 /* Unix */ = {
+			isa = PBXGroup;
+			children = (
+				FAF140211E20934C00F898D2 /* ossource.cpp */,
+			);
+			path = Unix;
+			sourceTree = "<group>";
+		};
+		FAF140281E20934C00F898D2 /* Public */ = {
+			isa = PBXGroup;
+			children = (
+				FAF140291E20934C00F898D2 /* ShaderLang.h */,
+			);
+			path = Public;
+			sourceTree = "<group>";
+		};
+		FAF1403A1E20934C00F898D2 /* OGLCompilersDLL */ = {
+			isa = PBXGroup;
+			children = (
+				FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */,
+				FAF1403C1E20934C00F898D2 /* InitializeDll.h */,
+			);
+			path = OGLCompilersDLL;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -3147,18 +3465,22 @@
 				217DFC0A1D9F6D490055D849 /* unix.h in Headers */,
 				FA0B7D7E1A95902C000E1D17 /* Texture.h in Headers */,
 				FA0B7E561A95902C000E1D17 /* wrap_GearJoint.h in Headers */,
+				FAF1409F1E20934C00F898D2 /* reflection.h in Headers */,
 				FA0B7E1D1A95902C000E1D17 /* MouseJoint.h in Headers */,
 				FA1BA0B81E17043400AA2803 /* wrap_Shader.h in Headers */,
 				FA1557C41CE90BD200AFF582 /* EXRHandler.h in Headers */,
 				FA0B7DC91A95902C000E1D17 /* Keyboard.h in Headers */,
 				FA0B7D4A1A95902C000E1D17 /* Polyline.h in Headers */,
+				FAF1405C1E20934C00F898D2 /* InitializeGlobals.h in Headers */,
 				FA0B7DB31A95902C000E1D17 /* wrap_Image.h in Headers */,
 				FA0B7D531A95902C000E1D17 /* Text.h in Headers */,
 				FA0B7D381A95902C000E1D17 /* Font.h in Headers */,
+				FAF140591E20934C00F898D2 /* Common.h in Headers */,
 				FA0B7EC31A95902C000E1D17 /* threads.h in Headers */,
 				FA0B7AC21A958EA3000E1D17 /* enet.h in Headers */,
 				FA4F2BA71DE1E36400CA37D7 /* RecordingDevice.h in Headers */,
 				FA0B7E201A95902C000E1D17 /* Physics.h in Headers */,
+				FAF140791E20934C00F898D2 /* iomapper.h in Headers */,
 				217DFBEA1D9F6D490055D849 /* io.h in Headers */,
 				FA0B79221A958E3B000E1D17 /* delay.h in Headers */,
 				FA0B79481A958E3B000E1D17 /* Vector.h in Headers */,
@@ -3172,6 +3494,7 @@
 				FA0B7E5F1A95902C000E1D17 /* wrap_MouseJoint.h in Headers */,
 				FAB17BED1ABFAF1800F9BA27 /* CompressedData.h in Headers */,
 				217DFC0C1D9F6D490055D849 /* unixtcp.h in Headers */,
+				FA76344C1E28722A0066EF9E /* StreamBuffer.h in Headers */,
 				217DFBF31D9F6D490055D849 /* mime.h in Headers */,
 				FA0B7B361A958EA3000E1D17 /* wuff_convert.h in Headers */,
 				FA0B7D981A95902C000E1D17 /* ImageData.h in Headers */,
@@ -3180,6 +3503,7 @@
 				FA0B7D051A95902C000E1D17 /* wrap_DroppedFile.h in Headers */,
 				FA0B7B271A958EA3000E1D17 /* lutf8lib.h in Headers */,
 				FA0B7E9F1A95902C000E1D17 /* WaveDecoder.h in Headers */,
+				FAF140871E20934C00F898D2 /* parseVersions.h in Headers */,
 				FA0B7AC61A958EA3000E1D17 /* types.h in Headers */,
 				FA0B7D751A95902C000E1D17 /* wrap_Text.h in Headers */,
 				FA0B7DBD1A95902C000E1D17 /* Joystick.h in Headers */,
@@ -3198,15 +3522,19 @@
 				FA0B7AC11A958EA3000E1D17 /* callbacks.h in Headers */,
 				FA0B7D8F1A95902C000E1D17 /* ddsHandler.h in Headers */,
 				FAB2D5AC1AABDD8A008224A4 /* TrueTypeRasterizer.h in Headers */,
+				FAF140C41E20934C00F898D2 /* ShaderLang.h in Headers */,
 				FA1E887F1DF363CD00E808AA /* Filter.h in Headers */,
 				FA27B3C21B4985BF008A9DCE /* wrap_VideoStream.h in Headers */,
 				FA0B7AA31A958EA3000E1D17 /* b2PulleyJoint.h in Headers */,
+				FAF140621E20934C00F898D2 /* ShHandle.h in Headers */,
 				FA0B7B2F1A958EA3000E1D17 /* utf8.h in Headers */,
 				FA19C4C71B4B0BD50059B0B3 /* wrap_Video.h in Headers */,
 				FA0B79231A958E3B000E1D17 /* EnumMap.h in Headers */,
+				FAF140571E20934C00F898D2 /* arrays.h in Headers */,
 				FA0B7A371A958EA3000E1D17 /* b2Distance.h in Headers */,
 				FA0B7E681A95902C000E1D17 /* wrap_PrismaticJoint.h in Headers */,
 				FA0B7D571A95902C000E1D17 /* GLBuffer.h in Headers */,
+				FAF140AB1E20934C00F898D2 /* SymbolTable.h in Headers */,
 				FA27B3C71B4985D8008A9DCE /* Video.h in Headers */,
 				FA0B7ED71A95902D000E1D17 /* Timer.h in Headers */,
 				FA0B7AC31A958EA3000E1D17 /* list.h in Headers */,
@@ -3216,6 +3544,7 @@
 				FAB17BF71ABFC4B100F9BA27 /* lz4hc.h in Headers */,
 				FA0B7E831A95902C000E1D17 /* Shape.h in Headers */,
 				FAE272531C05A15B00A67640 /* ParticleSystem.h in Headers */,
+				FAF140701E20934C00F898D2 /* Initialize.h in Headers */,
 				FA1BA09F1E16CFCE00AA2803 /* Font.h in Headers */,
 				FA0B7EDD1A95902D000E1D17 /* Touch.h in Headers */,
 				FA0B7EDE1A95902D000E1D17 /* Touch.h in Headers */,
@@ -3226,7 +3555,9 @@
 				FA0B7CE41A95902C000E1D17 /* wrap_Audio.h in Headers */,
 				FA0B7A7F1A958EA3000E1D17 /* b2ContactSolver.h in Headers */,
 				FA0B79491A958E3B000E1D17 /* version.h in Headers */,
+				FAF140581E20934C00F898D2 /* BaseTypes.h in Headers */,
 				FA0B7B2B1A958EA3000E1D17 /* stb_image.h in Headers */,
+				FAF140AE1E20934C00F898D2 /* Versions.h in Headers */,
 				FA0B7CD21A95902C000E1D17 /* Audio.h in Headers */,
 				FA0B79421A958E3B000E1D17 /* utf8.h in Headers */,
 				FA0B7D171A95902C000E1D17 /* Font.h in Headers */,
@@ -3235,6 +3566,7 @@
 				FA0B7CFF1A95902C000E1D17 /* File.h in Headers */,
 				FA0B7AB41A958EA3000E1D17 /* ddsinfo.h in Headers */,
 				FA0B7DD21A95902C000E1D17 /* love.h in Headers */,
+				FAF140861E20934C00F898D2 /* ParseHelper.h in Headers */,
 				FA0B7CE71A95902C000E1D17 /* wrap_Source.h in Headers */,
 				FA0B7B231A958EA3000E1D17 /* luasocket.h in Headers */,
 				FA0B7D1D1A95902C000E1D17 /* GlyphData.h in Headers */,
@@ -3248,8 +3580,11 @@
 				FAB17BE21ABFAA2000F9BA27 /* Compressor.h in Headers */,
 				FA0B7E441A95902C000E1D17 /* wrap_CircleShape.h in Headers */,
 				FA0B7EB41A95902C000E1D17 /* System.h in Headers */,
+				FAF1405A1E20934C00F898D2 /* ConstantUnion.h in Headers */,
+				FAF140A51E20934C00F898D2 /* Scan.h in Headers */,
 				FA0B7CE11A95902C000E1D17 /* Source.h in Headers */,
 				FA1BA0AE1E16F9EE00AA2803 /* wrap_Canvas.h in Headers */,
+				FAF140901E20934C00F898D2 /* PpContext.h in Headers */,
 				FA0B7E621A95902C000E1D17 /* wrap_Physics.h in Headers */,
 				FA0B7DF01A95902C000E1D17 /* Mouse.h in Headers */,
 				217DFBDC1D9F6D490055D849 /* buffer.h in Headers */,
@@ -3266,6 +3601,7 @@
 				FA0B7DCC1A95902C000E1D17 /* Keyboard.h in Headers */,
 				FA620A341AA2F8DB005DB4C2 /* wrap_Quad.h in Headers */,
 				FA0B7EA51A95902C000E1D17 /* SoundData.h in Headers */,
+				FAF1405E1E20934C00F898D2 /* PoolAlloc.h in Headers */,
 				FA0B7A821A958EA3000E1D17 /* b2EdgeAndCircleContact.h in Headers */,
 				FA0B79341A958E3B000E1D17 /* Object.h in Headers */,
 				217DFBF11D9F6D490055D849 /* mbox.lua.h in Headers */,
@@ -3330,6 +3666,7 @@
 				FA0B7AE01A958EA3000E1D17 /* lodepng.h in Headers */,
 				FA0B7A4D1A958EA3000E1D17 /* b2BlockAllocator.h in Headers */,
 				FA0B7ECD1A95902C000E1D17 /* wrap_Channel.h in Headers */,
+				FAF140AF1E20934C00F898D2 /* osinclude.h in Headers */,
 				FA0B7A431A958EA3000E1D17 /* b2CircleShape.h in Headers */,
 				FA0B7CD81A95902C000E1D17 /* Audio.h in Headers */,
 				FA0B7CF61A95902C000E1D17 /* File.h in Headers */,
@@ -3344,6 +3681,7 @@
 				FA27B3A91B498151008A9DCE /* Video.h in Headers */,
 				217DFBFA1D9F6D490055D849 /* select.h in Headers */,
 				FA0B7DF61A95902C000E1D17 /* wrap_Mouse.h in Headers */,
+				FAF140661E20934C00F898D2 /* gl_types.h in Headers */,
 				FAB17BF21ABFB37500F9BA27 /* wrap_CompressedData.h in Headers */,
 				FA0B7E801A95902C000E1D17 /* Joint.h in Headers */,
 				FA0B7D2F1A95902C000E1D17 /* Drawable.h in Headers */,
@@ -3352,6 +3690,7 @@
 				FA0B7EC41A95902C000E1D17 /* Thread.h in Headers */,
 				FA0B7DFF1A95902C000E1D17 /* ChainShape.h in Headers */,
 				FA0B7E4D1A95902C000E1D17 /* wrap_EdgeShape.h in Headers */,
+				FAF1405F1E20934C00F898D2 /* ResourceLimits.h in Headers */,
 				FA0B7DDB1A95902C000E1D17 /* RandomGenerator.h in Headers */,
 				FA0B7E841A95902C000E1D17 /* Decoder.h in Headers */,
 				FA0B7A601A958EA3000E1D17 /* b2Body.h in Headers */,
@@ -3361,9 +3700,12 @@
 				FA0B7E741A95902C000E1D17 /* wrap_Shape.h in Headers */,
 				FA0B7A5D1A958EA3000E1D17 /* b2Timer.h in Headers */,
 				FA0B7A4A1A958EA3000E1D17 /* b2Shape.h in Headers */,
+				FAF1407F1E20934C00F898D2 /* localintermediate.h in Headers */,
+				FAF1406B1E20934C00F898D2 /* glslang_tab.cpp.h in Headers */,
 				217DFBF71D9F6D490055D849 /* options.h in Headers */,
 				FA0B7E3B1A95902C000E1D17 /* World.h in Headers */,
 				FA0B7DC31A95902C000E1D17 /* wrap_Joystick.h in Headers */,
+				FAF140631E20934C00F898D2 /* Types.h in Headers */,
 				FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */,
 				FA0B7EE71A95902D000E1D17 /* Window.h in Headers */,
 				FA0B7E651A95902C000E1D17 /* wrap_PolygonShape.h in Headers */,
@@ -3371,6 +3713,7 @@
 				FA0B7DFC1A95902C000E1D17 /* Body.h in Headers */,
 				FA1BA0B31E16FD0800AA2803 /* Shader.h in Headers */,
 				217DFC101D9F6D490055D849 /* url.lua.h in Headers */,
+				FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */,
 				FA0B7A941A958EA3000E1D17 /* b2GearJoint.h in Headers */,
 				FA0B7DF31A95902C000E1D17 /* wrap_Cursor.h in Headers */,
 				FA0B7A461A958EA3000E1D17 /* b2EdgeShape.h in Headers */,
@@ -3382,6 +3725,7 @@
 				FA0B7E261A95902C000E1D17 /* PrismaticJoint.h in Headers */,
 				FA0B7E991A95902C000E1D17 /* Sound.h in Headers */,
 				FA0B7D841A95902C000E1D17 /* CompressedImageData.h in Headers */,
+				FAF1407E1E20934C00F898D2 /* LiveTraverser.h in Headers */,
 				FA0B7D231A95902C000E1D17 /* Rasterizer.h in Headers */,
 				FA0B7CDB1A95902C000E1D17 /* Pool.h in Headers */,
 				FA0B7D0B1A95902C000E1D17 /* wrap_FileData.h in Headers */,
@@ -3396,6 +3740,8 @@
 				FA0B7DA71A95902C000E1D17 /* PNGHandler.h in Headers */,
 				FA0B7AC41A958EA3000E1D17 /* protocol.h in Headers */,
 				FA0B7D8B1A95902C000E1D17 /* CompressedImageData.h in Headers */,
+				FAF140601E20934C00F898D2 /* revision.h in Headers */,
+				FAF140A21E20934C00F898D2 /* RemoveTree.h in Headers */,
 				FA0B7A8E1A958EA3000E1D17 /* b2DistanceJoint.h in Headers */,
 				FA0B7A8B1A958EA3000E1D17 /* b2PolygonContact.h in Headers */,
 				FA0B794C1A958E3B000E1D17 /* wrap_Data.h in Headers */,
@@ -3412,7 +3758,9 @@
 				FA0B7D111A95902C000E1D17 /* BMFontRasterizer.h in Headers */,
 				217DFBE61D9F6D490055D849 /* http.lua.h in Headers */,
 				FA0B7E3E1A95902C000E1D17 /* wrap_Body.h in Headers */,
+				FAF140991E20934C00F898D2 /* PpTokens.h in Headers */,
 				FA0B7A571A958EA3000E1D17 /* b2Settings.h in Headers */,
+				FAF1405B1E20934C00F898D2 /* InfoSink.h in Headers */,
 				FA0B7B321A958EA3000E1D17 /* wuff.h in Headers */,
 				217DFBF81D9F6D490055D849 /* pierror.h in Headers */,
 				217DFC021D9F6D490055D849 /* tcp.h in Headers */,
@@ -3437,6 +3785,7 @@
 				FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */,
 				FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */,
 				FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */,
+				FA28EBD71E352DB5003446F4 /* BufferSync.h in Headers */,
 				FAA3A9B01B7D465A00CED060 /* android.h in Headers */,
 				217DFBDE1D9F6D490055D849 /* compat.h in Headers */,
 				FA0B7A491A958EA3000E1D17 /* b2PolygonShape.h in Headers */,
@@ -3461,6 +3810,7 @@
 				217DFBFE1D9F6D490055D849 /* socket.h in Headers */,
 				FA0B7A971A958EA3000E1D17 /* b2Joint.h in Headers */,
 				FA0B7A851A958EA3000E1D17 /* b2EdgeAndPolygonContact.h in Headers */,
+				FAF1409C1E20934C00F898D2 /* propagateNoContraction.h in Headers */,
 				FA0B7D2D1A95902C000E1D17 /* wrap_Rasterizer.h in Headers */,
 				FA0B7AB71A958EA3000E1D17 /* ddsparse.h in Headers */,
 				FA0B7DA11A95902C000E1D17 /* KTXHandler.h in Headers */,
@@ -3468,6 +3818,7 @@
 				FA0B79311A958E3B000E1D17 /* Module.h in Headers */,
 				217DFBF51D9F6D490055D849 /* mime.lua.h in Headers */,
 				FA9D8DD31DEB56C3002CD881 /* pixelformat.h in Headers */,
+				FAF140A61E20934C00F898D2 /* ScanContext.h in Headers */,
 				FA0B7E4A1A95902C000E1D17 /* wrap_DistanceJoint.h in Headers */,
 				FA0B7D2E1A95902C000E1D17 /* Color.h in Headers */,
 				FA0B7A6A1A958EA3000E1D17 /* b2TimeStep.h in Headers */,
@@ -3489,6 +3840,7 @@
 				FA0B7A511A958EA3000E1D17 /* b2GrowableStack.h in Headers */,
 				FA0B7D921A95902C000E1D17 /* FormatHandler.h in Headers */,
 				FA0B7ADD1A958EA3000E1D17 /* gladfuncs.hpp in Headers */,
+				FAF1405D1E20934C00F898D2 /* intermediate.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3602,12 +3954,16 @@
 				FA0B79371A958E3B000E1D17 /* macosx.mm in Sources */,
 				FA4F2BE81DE6651000CA37D7 /* wrap_Transform.cpp in Sources */,
 				FA0B7D011A95902C000E1D17 /* Filesystem.cpp in Sources */,
+				FAF140651E20934C00F898D2 /* Constant.cpp in Sources */,
 				FA0B7ED91A95902D000E1D17 /* wrap_Timer.cpp in Sources */,
+				FAF1407D1E20934C00F898D2 /* linkValidate.cpp in Sources */,
 				FA0B7DD11A95902C000E1D17 /* love.cpp in Sources */,
 				FA0B7AB61A958EA3000E1D17 /* ddsparse.cpp in Sources */,
 				FA0B7D221A95902C000E1D17 /* Rasterizer.cpp in Sources */,
 				FA0B7A4F1A958EA3000E1D17 /* b2Draw.cpp in Sources */,
+				FAF140BC1E20934C00F898D2 /* ossource.cpp in Sources */,
 				FA0B7D7D1A95902C000E1D17 /* Texture.cpp in Sources */,
+				FAF140A81E20934C00F898D2 /* ShaderLang.cpp in Sources */,
 				FA1BA09E1E16CFCE00AA2803 /* Font.cpp in Sources */,
 				FA0B7ECC1A95902C000E1D17 /* wrap_Channel.cpp in Sources */,
 				FA0B7E6D1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */,
@@ -3627,28 +3983,38 @@
 				FA0B7DEC1A95902C000E1D17 /* Cursor.cpp in Sources */,
 				FA0B7D871A95902C000E1D17 /* ImageData.cpp in Sources */,
 				FA0B7E101A95902C000E1D17 /* FrictionJoint.cpp in Sources */,
+				FAF140741E20934C00F898D2 /* intermOut.cpp in Sources */,
 				FA620A361AA2F8DB005DB4C2 /* wrap_Texture.cpp in Sources */,
 				FA0B7D0A1A95902C000E1D17 /* wrap_FileData.cpp in Sources */,
+				FAF140781E20934C00F898D2 /* iomapper.cpp in Sources */,
 				FA0B7ABE1A958EA3000E1D17 /* compress.c in Sources */,
 				FA0B7CF21A95902C000E1D17 /* DroppedFile.cpp in Sources */,
 				FA4F2C141DE936FE00CA37D7 /* usocket.c in Sources */,
 				FA0B7D8A1A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
+				FAF140831E20934C00F898D2 /* ParseContextBase.cpp in Sources */,
 				FA0B7AD21A958EA3000E1D17 /* protocol.c in Sources */,
+				FAF140A41E20934C00F898D2 /* Scan.cpp in Sources */,
 				FA0B7D1F1A95902C000E1D17 /* ImageRasterizer.cpp in Sources */,
 				FA0B7EA41A95902C000E1D17 /* SoundData.cpp in Sources */,
 				FA0B7D041A95902C000E1D17 /* wrap_DroppedFile.cpp in Sources */,
 				FA0B7B261A958EA3000E1D17 /* lutf8lib.c in Sources */,
 				FA0B7D461A95902C000E1D17 /* ParticleSystem.cpp in Sources */,
+				FAF1406A1E20934C00F898D2 /* glslang_tab.cpp in Sources */,
 				FA91591F1CF1ED7500A7053F /* halffloat.cpp in Sources */,
 				FA8951A31AA2EDF300EC385A /* wrap_Event.cpp in Sources */,
 				FA0B7A361A958EA3000E1D17 /* b2Distance.cpp in Sources */,
 				FA0B7D4C1A95902C000E1D17 /* Shader.cpp in Sources */,
 				FA0B792A1A958E3B000E1D17 /* Matrix.cpp in Sources */,
+				FAF140981E20934C00F898D2 /* PpTokens.cpp in Sources */,
+				FAF140AA1E20934C00F898D2 /* SymbolTable.cpp in Sources */,
 				FA0B7A8D1A958EA3000E1D17 /* b2DistanceJoint.cpp in Sources */,
 				FA0B7A841A958EA3000E1D17 /* b2EdgeAndPolygonContact.cpp in Sources */,
+				FAF140921E20934C00F898D2 /* PpMemory.cpp in Sources */,
 				FA0B7E191A95902C000E1D17 /* MotorJoint.cpp in Sources */,
+				FAF1406F1E20934C00F898D2 /* Initialize.cpp in Sources */,
 				FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */,
 				FA0B7EBF1A95902C000E1D17 /* Thread.cpp in Sources */,
+				FAF140811E20934C00F898D2 /* parseConst.cpp in Sources */,
 				FA4F2C121DE936FE00CA37D7 /* unixtcp.c in Sources */,
 				FA0B7EB91A95902C000E1D17 /* Channel.cpp in Sources */,
 				FA4B66CA1ABBCF1900558F15 /* Timer.cpp in Sources */,
@@ -3665,6 +4031,7 @@
 				FA0B7CFB1A95902C000E1D17 /* Filesystem.cpp in Sources */,
 				FA0B7D3D1A95902C000E1D17 /* Image.cpp in Sources */,
 				FA0B7B351A958EA3000E1D17 /* wuff_convert.c in Sources */,
+				FAF140941E20934C00F898D2 /* PpScanner.cpp in Sources */,
 				FA0B7E431A95902C000E1D17 /* wrap_CircleShape.cpp in Sources */,
 				FA0B7CE61A95902C000E1D17 /* wrap_Source.cpp in Sources */,
 				FA0B7AA21A958EA3000E1D17 /* b2PulleyJoint.cpp in Sources */,
@@ -3680,10 +4047,12 @@
 				FA0B7CDD1A95902C000E1D17 /* Source.cpp in Sources */,
 				FA0B7DC51A95902C000E1D17 /* wrap_JoystickModule.cpp in Sources */,
 				FA0B7E701A95902C000E1D17 /* wrap_RopeJoint.cpp in Sources */,
+				FAF140AD1E20934C00F898D2 /* Versions.cpp in Sources */,
 				FA0B7A7B1A958EA3000E1D17 /* b2Contact.cpp in Sources */,
 				FA0B7A6F1A958EA3000E1D17 /* b2WorldCallbacks.cpp in Sources */,
 				FA0B793C1A958E3B000E1D17 /* runtime.cpp in Sources */,
 				FA27B3C61B4985D8008A9DCE /* Video.cpp in Sources */,
+				FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */,
 				FA0B7DBC1A95902C000E1D17 /* Joystick.cpp in Sources */,
 				FA0B7DAF1A95902C000E1D17 /* wrap_CompressedImageData.cpp in Sources */,
 				FA0B7A481A958EA3000E1D17 /* b2PolygonShape.cpp in Sources */,
@@ -3694,6 +4063,7 @@
 				FA4F2BE71DE6650D00CA37D7 /* Transform.cpp in Sources */,
 				FA0B7D651A95902C000E1D17 /* wrap_Mesh.cpp in Sources */,
 				FA0B7A531A958EA3000E1D17 /* b2Math.cpp in Sources */,
+				FAF140A11E20934C00F898D2 /* RemoveTree.cpp in Sources */,
 				FA0B7CDA1A95902C000E1D17 /* Pool.cpp in Sources */,
 				FA0B7E161A95902C000E1D17 /* Joint.cpp in Sources */,
 				FA0B7EE91A95902D000E1D17 /* wrap_Window.cpp in Sources */,
@@ -3701,6 +4071,9 @@
 				FA0B7AB91A958EA3000E1D17 /* enet.cpp in Sources */,
 				FA0B7E281A95902C000E1D17 /* PulleyJoint.cpp in Sources */,
 				FA0B7A4C1A958EA3000E1D17 /* b2BlockAllocator.cpp in Sources */,
+				FAF1409E1E20934C00F898D2 /* reflection.cpp in Sources */,
+				FAF1408B1E20934C00F898D2 /* Pp.cpp in Sources */,
+				FA76344B1E28722A0066EF9E /* StreamBuffer.cpp in Sources */,
 				FA0B7E041A95902C000E1D17 /* Contact.cpp in Sources */,
 				FA0B7D831A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
 				FA0B7B311A958EA3000E1D17 /* wuff.c in Sources */,
@@ -3712,8 +4085,11 @@
 				FA0B7EB61A95902C000E1D17 /* wrap_System.cpp in Sources */,
 				FA0B7DAC1A95902C000E1D17 /* STBHandler.cpp in Sources */,
 				FA0B79301A958E3B000E1D17 /* Module.cpp in Sources */,
+				FAF1409B1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */,
 				FA0B7DDA1A95902C000E1D17 /* RandomGenerator.cpp in Sources */,
 				FA2AF6751DAD64970032B62C /* vertex.cpp in Sources */,
+				FAF140561E20934C00F898D2 /* Link.cpp in Sources */,
+				FAF140851E20934C00F898D2 /* ParseHelper.cpp in Sources */,
 				FA0B7D801A95902C000E1D17 /* Volatile.cpp in Sources */,
 				FA0B792D1A958E3B000E1D17 /* Memoizer.cpp in Sources */,
 				FA1BA0B21E16FD0800AA2803 /* Shader.cpp in Sources */,
@@ -3735,7 +4111,9 @@
 				FA0B7EC91A95902C000E1D17 /* threads.cpp in Sources */,
 				FA0B7A781A958EA3000E1D17 /* b2CircleContact.cpp in Sources */,
 				FA0B7D5F1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */,
+				FAF1408D1E20934C00F898D2 /* PpAtom.cpp in Sources */,
 				FA0B7A9C1A958EA3000E1D17 /* b2MouseJoint.cpp in Sources */,
+				FAF140721E20934C00F898D2 /* Intermediate.cpp in Sources */,
 				FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */,
 				FA0B7E551A95902C000E1D17 /* wrap_GearJoint.cpp in Sources */,
 				FA0B7E791A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */,
@@ -3781,6 +4159,8 @@
 				FA0B7DFE1A95902C000E1D17 /* ChainShape.cpp in Sources */,
 				FA0B7A451A958EA3000E1D17 /* b2EdgeShape.cpp in Sources */,
 				FA0B7D621A95902C000E1D17 /* wrap_Image.cpp in Sources */,
+				FAF1406D1E20934C00F898D2 /* InfoSink.cpp in Sources */,
+				FAF1407B1E20934C00F898D2 /* limits.cpp in Sources */,
 				FA0B7ABB1A958EA3000E1D17 /* callbacks.c in Sources */,
 				FA0B7A721A958EA3000E1D17 /* b2ChainAndCircleContact.cpp in Sources */,
 				FA0B7EAA1A95902C000E1D17 /* wrap_Sound.cpp in Sources */,
@@ -3795,12 +4175,14 @@
 				FA0B7ADF1A958EA3000E1D17 /* lodepng.cpp in Sources */,
 				FA0B7D711A95902C000E1D17 /* wrap_SpriteBatch.cpp in Sources */,
 				FA0B7D341A95902C000E1D17 /* Canvas.cpp in Sources */,
+				FAF140761E20934C00F898D2 /* IntermTraverse.cpp in Sources */,
 				FA0B7E8C1A95902C000E1D17 /* FLACDecoder.cpp in Sources */,
 				FA0B7A421A958EA3000E1D17 /* b2CircleShape.cpp in Sources */,
 				FA0B7D491A95902C000E1D17 /* Polyline.cpp in Sources */,
 				FA0B7CE31A95902C000E1D17 /* wrap_Audio.cpp in Sources */,
 				FA0B7B381A958EA3000E1D17 /* wuff_internal.c in Sources */,
 				FA0B7DF81A95902C000E1D17 /* Body.cpp in Sources */,
+				FAF140961E20934C00F898D2 /* PpSymbols.cpp in Sources */,
 				FA4F2BB41DE1E4BD00CA37D7 /* RecordingDevice.cpp in Sources */,
 				FA0B7DF51A95902C000E1D17 /* wrap_Mouse.cpp in Sources */,
 				FA0B7E861A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */,
@@ -3811,10 +4193,12 @@
 				FA57FB991AE1993600F2AD6D /* noise1234.cpp in Sources */,
 				FA0B7E221A95902C000E1D17 /* PolygonShape.cpp in Sources */,
 				FA0B7A651A958EA3000E1D17 /* b2Fixture.cpp in Sources */,
+				FA28EBD61E352DB5003446F4 /* BufferSync.cpp in Sources */,
 				FA0B7D521A95902C000E1D17 /* Text.cpp in Sources */,
 				FA0B7DA31A95902C000E1D17 /* PKMHandler.cpp in Sources */,
 				FA0B7AB21A958EA3000E1D17 /* b2Rope.cpp in Sources */,
 				FAB17BF61ABFC4B100F9BA27 /* lz4hc.c in Sources */,
+				FAF1408F1E20934C00F898D2 /* PpContext.cpp in Sources */,
 				FA0B7EA71A95902C000E1D17 /* wrap_Decoder.cpp in Sources */,
 				FA0B7E1C1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
 				FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */,
@@ -3881,9 +4265,11 @@
 				FA0B7A621A958EA3000E1D17 /* b2ContactManager.cpp in Sources */,
 				FA0B7A2F1A958EA3000E1D17 /* b2CollideEdge.cpp in Sources */,
 				FA0B7ADA1A958EA3000E1D17 /* glad.cpp in Sources */,
+				FAF140541E20934C00F898D2 /* CodeGen.cpp in Sources */,
 				FA0B7E1F1A95902C000E1D17 /* Physics.cpp in Sources */,
 				FA0B7E821A95902C000E1D17 /* Shape.cpp in Sources */,
 				FA0B7ACE1A958EA3000E1D17 /* packet.c in Sources */,
+				FAF140891E20934C00F898D2 /* PoolAlloc.cpp in Sources */,
 				FA19C4C61B4B0BD50059B0B3 /* wrap_Video.cpp in Sources */,
 				FA27B3B41B498151008A9DCE /* wrap_Video.cpp in Sources */,
 				FA1E88801DF363D400E808AA /* Filter.cpp in Sources */,
@@ -3921,12 +4307,16 @@
 				FA0B7EC11A95902C000E1D17 /* threads.cpp in Sources */,
 				FA0B79321A958E3B000E1D17 /* Object.cpp in Sources */,
 				FA0B7D001A95902C000E1D17 /* Filesystem.cpp in Sources */,
+				FAF140641E20934C00F898D2 /* Constant.cpp in Sources */,
 				FA0B7ED81A95902D000E1D17 /* wrap_Timer.cpp in Sources */,
+				FAF1407C1E20934C00F898D2 /* linkValidate.cpp in Sources */,
 				FA0B7DD01A95902C000E1D17 /* love.cpp in Sources */,
 				FA0B7A521A958EA3000E1D17 /* b2Math.cpp in Sources */,
 				FA0B7D211A95902C000E1D17 /* Rasterizer.cpp in Sources */,
 				FA0B7D7C1A95902C000E1D17 /* Texture.cpp in Sources */,
+				FAF140BB1E20934C00F898D2 /* ossource.cpp in Sources */,
 				FA0B7ECB1A95902C000E1D17 /* wrap_Channel.cpp in Sources */,
+				FAF140A71E20934C00F898D2 /* ShaderLang.cpp in Sources */,
 				FA1BA09D1E16CFCE00AA2803 /* Font.cpp in Sources */,
 				FA0B7E6C1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */,
 				FA0B7A5E1A958EA3000E1D17 /* b2Body.cpp in Sources */,
@@ -3946,28 +4336,38 @@
 				FA0B7DEB1A95902C000E1D17 /* Cursor.cpp in Sources */,
 				FA0B7D861A95902C000E1D17 /* ImageData.cpp in Sources */,
 				FA0B7A3E1A958EA3000E1D17 /* b2ChainShape.cpp in Sources */,
+				FAF140731E20934C00F898D2 /* intermOut.cpp in Sources */,
 				FA0B7E0F1A95902C000E1D17 /* FrictionJoint.cpp in Sources */,
 				FA620A351AA2F8DB005DB4C2 /* wrap_Texture.cpp in Sources */,
+				FAF140771E20934C00F898D2 /* iomapper.cpp in Sources */,
 				FA0B7D091A95902C000E1D17 /* wrap_FileData.cpp in Sources */,
 				FA0B7B341A958EA3000E1D17 /* wuff_convert.c in Sources */,
 				FA0B7CF11A95902C000E1D17 /* DroppedFile.cpp in Sources */,
 				FA0B7D891A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
+				FAF140821E20934C00F898D2 /* ParseContextBase.cpp in Sources */,
 				FA0B7D1E1A95902C000E1D17 /* ImageRasterizer.cpp in Sources */,
+				FAF140A31E20934C00F898D2 /* Scan.cpp in Sources */,
 				FA0B7EA31A95902C000E1D17 /* SoundData.cpp in Sources */,
 				FA0B7D031A95902C000E1D17 /* wrap_DroppedFile.cpp in Sources */,
 				FA0B79291A958E3B000E1D17 /* Matrix.cpp in Sources */,
 				FA0B7D451A95902C000E1D17 /* ParticleSystem.cpp in Sources */,
 				FA8951A21AA2EDF300EC385A /* wrap_Event.cpp in Sources */,
+				FAF140691E20934C00F898D2 /* glslang_tab.cpp in Sources */,
 				FA0B7ABF1A958EA3000E1D17 /* host.c in Sources */,
 				FA0B7D4B1A95902C000E1D17 /* Shader.cpp in Sources */,
 				FA0B7A581A958EA3000E1D17 /* b2StackAllocator.cpp in Sources */,
 				FA0B7A301A958EA3000E1D17 /* b2CollidePolygon.cpp in Sources */,
 				FA0B7A641A958EA3000E1D17 /* b2Fixture.cpp in Sources */,
+				FAF140971E20934C00F898D2 /* PpTokens.cpp in Sources */,
+				FAF140A91E20934C00F898D2 /* SymbolTable.cpp in Sources */,
 				FA0B7E181A95902C000E1D17 /* MotorJoint.cpp in Sources */,
 				FA0B7E4E1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */,
+				FAF140911E20934C00F898D2 /* PpMemory.cpp in Sources */,
 				FA0B7EBE1A95902C000E1D17 /* Thread.cpp in Sources */,
+				FAF1406E1E20934C00F898D2 /* Initialize.cpp in Sources */,
 				FA0B7EB81A95902C000E1D17 /* Channel.cpp in Sources */,
 				217DFC091D9F6D490055D849 /* unix.c in Sources */,
+				FAF140801E20934C00F898D2 /* parseConst.cpp in Sources */,
 				FA0B7AB11A958EA3000E1D17 /* b2Rope.cpp in Sources */,
 				FA4B66C91ABBCF1900558F15 /* Timer.cpp in Sources */,
 				FA0B7A351A958EA3000E1D17 /* b2Distance.cpp in Sources */,
@@ -3984,6 +4384,7 @@
 				FA0B7E421A95902C000E1D17 /* wrap_CircleShape.cpp in Sources */,
 				FA0B7CE51A95902C000E1D17 /* wrap_Source.cpp in Sources */,
 				FA0B792C1A958E3B000E1D17 /* Memoizer.cpp in Sources */,
+				FAF140931E20934C00F898D2 /* PpScanner.cpp in Sources */,
 				FA0B7CCD1A95902C000E1D17 /* Audio.cpp in Sources */,
 				FA0B7DCA1A95902C000E1D17 /* Keyboard.cpp in Sources */,
 				FA0B7AA41A958EA3000E1D17 /* b2RevoluteJoint.cpp in Sources */,
@@ -3999,10 +4400,12 @@
 				FA0B7DC41A95902C000E1D17 /* wrap_JoystickModule.cpp in Sources */,
 				FA0B7E6F1A95902C000E1D17 /* wrap_RopeJoint.cpp in Sources */,
 				FA0B7AB51A958EA3000E1D17 /* ddsparse.cpp in Sources */,
+				FAF140AC1E20934C00F898D2 /* Versions.cpp in Sources */,
 				FA0B7A441A958EA3000E1D17 /* b2EdgeShape.cpp in Sources */,
 				FA0B79461A958E3B000E1D17 /* Vector.cpp in Sources */,
 				FA27B3C51B4985D8008A9DCE /* Video.cpp in Sources */,
 				FA0B7DBB1A95902C000E1D17 /* Joystick.cpp in Sources */,
+				FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */,
 				FA0B7DAE1A95902C000E1D17 /* wrap_CompressedImageData.cpp in Sources */,
 				FA0B7A6E1A958EA3000E1D17 /* b2WorldCallbacks.cpp in Sources */,
 				FA0B7A831A958EA3000E1D17 /* b2EdgeAndPolygonContact.cpp in Sources */,
@@ -4013,6 +4416,7 @@
 				FA0B7D641A95902C000E1D17 /* wrap_Mesh.cpp in Sources */,
 				FA0B7A5B1A958EA3000E1D17 /* b2Timer.cpp in Sources */,
 				FA0B7CD91A95902C000E1D17 /* Pool.cpp in Sources */,
+				FAF140A01E20934C00F898D2 /* RemoveTree.cpp in Sources */,
 				FA0B7E151A95902C000E1D17 /* Joint.cpp in Sources */,
 				FA0B7EE81A95902D000E1D17 /* wrap_Window.cpp in Sources */,
 				FA0B7E271A95902C000E1D17 /* PulleyJoint.cpp in Sources */,
@@ -4020,6 +4424,9 @@
 				FA0B7B301A958EA3000E1D17 /* wuff.c in Sources */,
 				FA0B7E031A95902C000E1D17 /* Contact.cpp in Sources */,
 				FA0B7D821A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
+				FAF1409D1E20934C00F898D2 /* reflection.cpp in Sources */,
+				FAF1408A1E20934C00F898D2 /* Pp.cpp in Sources */,
+				FA76344A1E28722A0066EF9E /* StreamBuffer.cpp in Sources */,
 				FA0B7A7A1A958EA3000E1D17 /* b2Contact.cpp in Sources */,
 				FA0B7DF11A95902C000E1D17 /* wrap_Cursor.cpp in Sources */,
 				FA0B7E001A95902C000E1D17 /* CircleShape.cpp in Sources */,
@@ -4031,8 +4438,11 @@
 				FA0B7DAB1A95902C000E1D17 /* STBHandler.cpp in Sources */,
 				FA0B7AB81A958EA3000E1D17 /* enet.cpp in Sources */,
 				FA0B7DD91A95902C000E1D17 /* RandomGenerator.cpp in Sources */,
+				FAF1409A1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */,
 				FA0B7A9B1A958EA3000E1D17 /* b2MouseJoint.cpp in Sources */,
 				FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */,
+				FAF140551E20934C00F898D2 /* Link.cpp in Sources */,
+				FAF140841E20934C00F898D2 /* ParseHelper.cpp in Sources */,
 				FA0B7D7F1A95902C000E1D17 /* Volatile.cpp in Sources */,
 				FA0B7A3B1A958EA3000E1D17 /* b2TimeOfImpact.cpp in Sources */,
 				FA1BA0B11E16FD0800AA2803 /* Shader.cpp in Sources */,
@@ -4054,7 +4464,9 @@
 				217DFBF91D9F6D490055D849 /* select.c in Sources */,
 				FA0B7A6B1A958EA3000E1D17 /* b2World.cpp in Sources */,
 				FA0B7D5E1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */,
+				FAF1408C1E20934C00F898D2 /* PpAtom.cpp in Sources */,
 				FA0B7A801A958EA3000E1D17 /* b2EdgeAndCircleContact.cpp in Sources */,
+				FAF140711E20934C00F898D2 /* Intermediate.cpp in Sources */,
 				FA0B7E541A95902C000E1D17 /* wrap_GearJoint.cpp in Sources */,
 				FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */,
 				FA0B7E781A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */,
@@ -4100,6 +4512,8 @@
 				FA0B7E061A95902C000E1D17 /* DistanceJoint.cpp in Sources */,
 				FA620A321AA2F8DB005DB4C2 /* wrap_Quad.cpp in Sources */,
 				FA4F2BA61DE1E36400CA37D7 /* RecordingDevice.cpp in Sources */,
+				FAF1406C1E20934C00F898D2 /* InfoSink.cpp in Sources */,
+				FAF1407A1E20934C00F898D2 /* limits.cpp in Sources */,
 				FA0B793B1A958E3B000E1D17 /* runtime.cpp in Sources */,
 				FA0B7E5D1A95902C000E1D17 /* wrap_MouseJoint.cpp in Sources */,
 				FA0B7A741A958EA3000E1D17 /* b2ChainAndPolygonContact.cpp in Sources */,
@@ -4114,12 +4528,14 @@
 				FA0B7A381A958EA3000E1D17 /* b2DynamicTree.cpp in Sources */,
 				FA0B7D481A95902C000E1D17 /* Polyline.cpp in Sources */,
 				217DFC111D9F6D490055D849 /* usocket.c in Sources */,
+				FAF140751E20934C00F898D2 /* IntermTraverse.cpp in Sources */,
 				FA0B7CE21A95902C000E1D17 /* wrap_Audio.cpp in Sources */,
 				FA0B7AAA1A958EA3000E1D17 /* b2WeldJoint.cpp in Sources */,
 				FA0B7DF71A95902C000E1D17 /* Body.cpp in Sources */,
 				FA0B7DF41A95902C000E1D17 /* wrap_Mouse.cpp in Sources */,
 				FA0B7E851A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */,
 				FA0B7E751A95902C000E1D17 /* wrap_WeldJoint.cpp in Sources */,
+				FAF140951E20934C00F898D2 /* PpSymbols.cpp in Sources */,
 				FA0B7D551A95902C000E1D17 /* GLBuffer.cpp in Sources */,
 				FA57FB981AE1993600F2AD6D /* noise1234.cpp in Sources */,
 				FA0B7E211A95902C000E1D17 /* PolygonShape.cpp in Sources */,
@@ -4130,10 +4546,12 @@
 				FA0B7EA61A95902C000E1D17 /* wrap_Decoder.cpp in Sources */,
 				217DFBF21D9F6D490055D849 /* mime.c in Sources */,
 				217DFBDF1D9F6D490055D849 /* except.c in Sources */,
+				FA28EBD51E352DB5003446F4 /* BufferSync.cpp in Sources */,
 				FA0B7E1B1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
 				FA0B7CF41A95902C000E1D17 /* File.cpp in Sources */,
 				FA0B7E331A95902C000E1D17 /* WeldJoint.cpp in Sources */,
 				FA0B7D301A95902C000E1D17 /* Graphics.cpp in Sources */,
+				FAF1408E1E20934C00F898D2 /* PpContext.cpp in Sources */,
 				FA0B7E9D1A95902C000E1D17 /* WaveDecoder.cpp in Sources */,
 				FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */,
 				FA0B7EB21A95902C000E1D17 /* System.cpp in Sources */,
@@ -4200,9 +4618,11 @@
 				FA4F2BA81DE1E36400CA37D7 /* wrap_RecordingDevice.cpp in Sources */,
 				FA0B7B251A958EA3000E1D17 /* lutf8lib.c in Sources */,
 				FA19C4C51B4B0BD50059B0B3 /* wrap_Video.cpp in Sources */,
+				FAF140531E20934C00F898D2 /* CodeGen.cpp in Sources */,
 				FA27B3B31B498151008A9DCE /* wrap_Video.cpp in Sources */,
 				FA0B7A611A958EA3000E1D17 /* b2ContactManager.cpp in Sources */,
 				217DFC0B1D9F6D490055D849 /* unixtcp.c in Sources */,
+				FAF140881E20934C00F898D2 /* PoolAlloc.cpp in Sources */,
 				FA0B7AAD1A958EA3000E1D17 /* b2WheelJoint.cpp in Sources */,
 				FA0B7DEE1A95902C000E1D17 /* Mouse.cpp in Sources */,
 				FA1E887E1DF363CD00E808AA /* Filter.cpp in Sources */,

+ 155 - 0
src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp

@@ -0,0 +1,155 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#define SH_EXPORTING
+
+#include <cassert>
+
+#include "InitializeDll.h"
+#include "../glslang/Include/InitializeGlobals.h"
+
+#include "../glslang/Public/ShaderLang.h"
+
+namespace glslang {
+
+OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+bool InitProcess()
+{
+    glslang::GetGlobalLock();
+
+    if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
+        //
+        // Function is re-entrant.
+        //
+
+        glslang::ReleaseGlobalLock();
+        return true;
+    }
+
+    ThreadInitializeIndex = OS_AllocTLSIndex();
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+        assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    if (! InitializePoolIndex()) {
+        assert(0 && "InitProcess(): Failed to initialize global pool");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    if (! InitThread()) {
+        assert(0 && "InitProcess(): Failed to initialize thread");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    glslang::ReleaseGlobalLock();
+    return true;
+}
+
+
+bool InitThread()
+{
+    //
+    // This function is re-entrant
+    //
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+        assert(0 && "InitThread(): Process hasn't been initalised.");
+        return false;
+    }
+
+    if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
+        return true;
+
+    InitializeMemoryPools();
+
+    if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
+        assert(0 && "InitThread(): Unable to set init flag.");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool DetachThread()
+{
+    bool success = true;
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+        return true;
+
+    //
+    // Function is re-entrant and this thread may not have been initialized.
+    //
+    if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
+        if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
+            assert(0 && "DetachThread(): Unable to clear init flag.");
+            success = false;
+        }
+
+        FreeGlobalPools();
+
+    }
+
+    return success;
+}
+
+bool DetachProcess()
+{
+    bool success = true;
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+        return true;
+
+    ShFinalize();
+
+    success = DetachThread();
+
+    FreePoolIndex();
+
+    OS_FreeTLSIndex(ThreadInitializeIndex);
+    ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+    return success;
+}
+
+} // end namespace glslang

+ 49 - 0
src/libraries/glslang/OGLCompilersDLL/InitializeDll.h

@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+#include "../glslang/OSDependent/osinclude.h"
+
+namespace glslang {
+
+bool InitProcess();
+bool InitThread();
+bool DetachThread();
+bool DetachProcess();
+
+} // end namespace glslang
+
+#endif // __INITIALIZEDLL_H
+

+ 76 - 0
src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp

@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+#include "../MachineIndependent/Versions.h"
+
+//
+// Here is where real machine specific high-level data would be defined.
+//
+class TGenericCompiler : public TCompiler {
+public:
+    TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { }
+    virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile);
+    TInfoSink infoSink;
+    int debugOptions;
+};
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code.  It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(EShLanguage language, int debugOptions)
+{
+    return new TGenericCompiler(language, debugOptions);
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+    delete compiler;
+}
+
+//
+//  Generate code from the given parse tree
+//
+bool TGenericCompiler::compile(TIntermNode* /*root*/, int /*version*/, EProfile /*profile*/)
+{
+    haveValidObjectCode = true;
+
+    return haveValidObjectCode;
+}

+ 91 - 0
src/libraries/glslang/glslang/GenericCodeGen/Link.cpp

@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// The top level algorithms for linking multiple
+// shaders together.
+//
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+
+//
+// Actual link object, derived from the shader handle base classes.
+//
+class TGenericLinker : public TLinker {
+public:
+    TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { }
+    bool link(TCompilerList&, TUniformMap*) { return true; }
+    void getAttributeBindings(ShBindingTable const **) const { }
+    TInfoSink infoSink;
+    int debugOptions;
+};
+
+//
+// The internal view of a uniform/float object exchanged with the driver.
+//
+class TUniformLinkedMap : public TUniformMap {
+public:
+    TUniformLinkedMap() { }
+    virtual int getLocation(const char*) { return 0; }
+};
+
+TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions)
+{
+    return new TGenericLinker(executable, debugOptions);
+}
+
+void DeleteLinker(TShHandleBase* linker)
+{
+    delete linker;
+}
+
+TUniformMap* ConstructUniformMap()
+{
+    return new TUniformLinkedMap();
+}
+
+void DeleteUniformMap(TUniformMap* map)
+{
+    delete map;
+}
+
+TShHandleBase* ConstructBindings()
+{
+    return 0;
+}
+
+void DeleteBindingList(TShHandleBase* bindingList)
+{
+    delete bindingList;
+}

+ 355 - 0
src/libraries/glslang/glslang/Include/BaseTypes.h

@@ -0,0 +1,355 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+namespace glslang {
+
+//
+// Basic type.  Arrays, vectors, sampler details, etc., are orthogonal to this.
+//
+enum TBasicType {
+    EbtVoid,
+    EbtFloat,
+    EbtDouble,
+#ifdef AMD_EXTENSIONS
+    EbtFloat16,
+#endif
+    EbtInt,
+    EbtUint,
+    EbtInt64,
+    EbtUint64,
+    EbtBool,
+    EbtAtomicUint,
+    EbtSampler,
+    EbtStruct,
+    EbtBlock,
+
+    // HLSL types that live only temporarily.
+    EbtString,
+
+    EbtNumTypes
+};
+
+//
+// Storage qualifiers.  Should align with different kinds of storage or
+// resource or GLSL storage qualifier.  Expansion is deprecated.
+//
+// N.B.: You probably DON'T want to add anything here, but rather just add it
+// to the built-in variables.  See the comment above TBuiltInVariable.
+//
+// A new built-in variable will normally be an existing qualifier, like 'in', 'out', etc.
+// DO NOT follow the design pattern of, say EvqInstanceId, etc.
+//
+enum TStorageQualifier {
+    EvqTemporary,     // For temporaries (within a function), read/write
+    EvqGlobal,        // For globals read/write
+    EvqConst,         // User-defined constant values, will be semantically constant and constant folded
+    EvqVaryingIn,     // pipeline input, read only, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
+    EvqVaryingOut,    // pipeline output, read/write, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
+    EvqUniform,       // read only, shared with app
+    EvqBuffer,        // read/write, shared with app
+    EvqShared,        // compute shader's read/write 'shared' qualifier
+
+    // parameters
+    EvqIn,            // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
+    EvqOut,           // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter
+    EvqInOut,
+    EvqConstReadOnly, // input; also other read-only types having neither a constant value nor constant-value semantics
+
+    // built-ins read by vertex shader
+    EvqVertexId,
+    EvqInstanceId,
+
+    // built-ins written by vertex shader
+    EvqPosition,
+    EvqPointSize,
+    EvqClipVertex,
+
+    // built-ins read by fragment shader
+    EvqFace,
+    EvqFragCoord,
+    EvqPointCoord,
+
+    // built-ins written by fragment shader
+    EvqFragColor,
+    EvqFragDepth,
+
+    // end of list
+    EvqLast
+};
+
+//
+// Subcategories of the TStorageQualifier, simply to give a direct mapping
+// between built-in variable names and an numerical value (the enum).
+//
+// For backward compatibility, there is some redundancy between the
+// TStorageQualifier and these.  Existing members should both be maintained accurately.
+// However, any new built-in variable (and any existing non-redundant one)
+// must follow the pattern that the specific built-in is here, and only its
+// general qualifier is in TStorageQualifier.
+//
+// Something like gl_Position, which is sometimes 'in' and sometimes 'out'
+// shows up as two different built-in variables in a single stage, but
+// only has a single enum in TBuiltInVariable, so both the
+// TStorageQualifier and the TBuitinVariable are needed to distinguish
+// between them.
+//
+enum TBuiltInVariable {
+    EbvNone,
+    EbvNumWorkGroups,
+    EbvWorkGroupSize,
+    EbvWorkGroupId,
+    EbvLocalInvocationId,
+    EbvGlobalInvocationId,
+    EbvLocalInvocationIndex,
+    EbvSubGroupSize,
+    EbvSubGroupInvocation,
+    EbvSubGroupEqMask,
+    EbvSubGroupGeMask,
+    EbvSubGroupGtMask,
+    EbvSubGroupLeMask,
+    EbvSubGroupLtMask,
+    EbvVertexId,
+    EbvInstanceId,
+    EbvVertexIndex,
+    EbvInstanceIndex,
+    EbvBaseVertex,
+    EbvBaseInstance,
+    EbvDrawId,
+    EbvPosition,
+    EbvPointSize,
+    EbvClipVertex,
+    EbvClipDistance,
+    EbvCullDistance,
+    EbvNormal,
+    EbvVertex,
+    EbvMultiTexCoord0,
+    EbvMultiTexCoord1,
+    EbvMultiTexCoord2,
+    EbvMultiTexCoord3,
+    EbvMultiTexCoord4,
+    EbvMultiTexCoord5,
+    EbvMultiTexCoord6,
+    EbvMultiTexCoord7,
+    EbvFrontColor,
+    EbvBackColor,
+    EbvFrontSecondaryColor,
+    EbvBackSecondaryColor,
+    EbvTexCoord,
+    EbvFogFragCoord,
+    EbvInvocationId,
+    EbvPrimitiveId,
+    EbvLayer,
+    EbvViewportIndex,
+    EbvPatchVertices,
+    EbvTessLevelOuter,
+    EbvTessLevelInner,
+    EbvBoundingBox,
+    EbvTessCoord,
+    EbvColor,
+    EbvSecondaryColor,
+    EbvFace,
+    EbvFragCoord,
+    EbvPointCoord,
+    EbvFragColor,
+    EbvFragData,
+    EbvFragDepth,
+    EbvSampleId,
+    EbvSamplePosition,
+    EbvSampleMask,
+    EbvHelperInvocation,
+#ifdef AMD_EXTENSIONS
+    EbvBaryCoordNoPersp,
+    EbvBaryCoordNoPerspCentroid,
+    EbvBaryCoordNoPerspSample,
+    EbvBaryCoordSmooth,
+    EbvBaryCoordSmoothCentroid,
+    EbvBaryCoordSmoothSample,
+    EbvBaryCoordPullModel,
+#endif
+
+#ifdef NV_EXTENSIONS
+    EbvViewportMaskNV,
+    EbvSecondaryPositionNV,
+    EbvSecondaryViewportMaskNV,
+#endif 
+    // HLSL built-ins that live only temporarily, until they get remapped
+    // to one of the above.
+    EbvFragDepthGreater,
+    EbvFragDepthLesser,
+
+    EbvLast
+};
+
+// These will show up in error messages
+__inline const char* GetStorageQualifierString(TStorageQualifier q)
+{
+    switch (q) {
+    case EvqTemporary:      return "temp";           break;
+    case EvqGlobal:         return "global";         break;
+    case EvqConst:          return "const";          break;
+    case EvqConstReadOnly:  return "const (read only)"; break;
+    case EvqVaryingIn:      return "in";             break;
+    case EvqVaryingOut:     return "out";            break;
+    case EvqUniform:        return "uniform";        break;
+    case EvqBuffer:         return "buffer";         break;
+    case EvqShared:         return "shared";         break;
+    case EvqIn:             return "in";             break;
+    case EvqOut:            return "out";            break;
+    case EvqInOut:          return "inout";          break;
+    case EvqVertexId:       return "gl_VertexId";    break;
+    case EvqInstanceId:     return "gl_InstanceId";  break;
+    case EvqPosition:       return "gl_Position";    break;
+    case EvqPointSize:      return "gl_PointSize";   break;
+    case EvqClipVertex:     return "gl_ClipVertex";  break;
+    case EvqFace:           return "gl_FrontFacing"; break;
+    case EvqFragCoord:      return "gl_FragCoord";   break;
+    case EvqPointCoord:     return "gl_PointCoord";  break;
+    case EvqFragColor:      return "fragColor";      break;
+    case EvqFragDepth:      return "gl_FragDepth";   break;
+    default:                return "unknown qualifier";
+    }
+}
+
+__inline const char* GetBuiltInVariableString(TBuiltInVariable v)
+{
+    switch (v) {
+    case EbvNone:                 return "";
+    case EbvNumWorkGroups:        return "NumWorkGroups";
+    case EbvWorkGroupSize:        return "WorkGroupSize";
+    case EbvWorkGroupId:          return "WorkGroupID";
+    case EbvLocalInvocationId:    return "LocalInvocationID";
+    case EbvGlobalInvocationId:   return "GlobalInvocationID";
+    case EbvLocalInvocationIndex: return "LocalInvocationIndex";
+    case EbvSubGroupSize:         return "SubGroupSize";
+    case EbvSubGroupInvocation:   return "SubGroupInvocation";
+    case EbvSubGroupEqMask:       return "SubGroupEqMask";
+    case EbvSubGroupGeMask:       return "SubGroupGeMask";
+    case EbvSubGroupGtMask:       return "SubGroupGtMask";
+    case EbvSubGroupLeMask:       return "SubGroupLeMask";
+    case EbvSubGroupLtMask:       return "SubGroupLtMask";
+    case EbvVertexId:             return "VertexId";
+    case EbvInstanceId:           return "InstanceId";
+    case EbvVertexIndex:          return "VertexIndex";
+    case EbvInstanceIndex:        return "InstanceIndex";
+    case EbvBaseVertex:           return "BaseVertex";
+    case EbvBaseInstance:         return "BaseInstance";
+    case EbvDrawId:               return "DrawId";
+    case EbvPosition:             return "Position";
+    case EbvPointSize:            return "PointSize";
+    case EbvClipVertex:           return "ClipVertex";
+    case EbvClipDistance:         return "ClipDistance";
+    case EbvCullDistance:         return "CullDistance";
+    case EbvNormal:               return "Normal";
+    case EbvVertex:               return "Vertex";
+    case EbvMultiTexCoord0:       return "MultiTexCoord0";
+    case EbvMultiTexCoord1:       return "MultiTexCoord1";
+    case EbvMultiTexCoord2:       return "MultiTexCoord2";
+    case EbvMultiTexCoord3:       return "MultiTexCoord3";
+    case EbvMultiTexCoord4:       return "MultiTexCoord4";
+    case EbvMultiTexCoord5:       return "MultiTexCoord5";
+    case EbvMultiTexCoord6:       return "MultiTexCoord6";
+    case EbvMultiTexCoord7:       return "MultiTexCoord7";
+    case EbvFrontColor:           return "FrontColor";
+    case EbvBackColor:            return "BackColor";
+    case EbvFrontSecondaryColor:  return "FrontSecondaryColor";
+    case EbvBackSecondaryColor:   return "BackSecondaryColor";
+    case EbvTexCoord:             return "TexCoord";
+    case EbvFogFragCoord:         return "FogFragCoord";
+    case EbvInvocationId:         return "InvocationID";
+    case EbvPrimitiveId:          return "PrimitiveID";
+    case EbvLayer:                return "Layer";
+    case EbvViewportIndex:        return "ViewportIndex";
+    case EbvPatchVertices:        return "PatchVertices";
+    case EbvTessLevelOuter:       return "TessLevelOuter";
+    case EbvTessLevelInner:       return "TessLevelInner";
+    case EbvBoundingBox:          return "BoundingBox";
+    case EbvTessCoord:            return "TessCoord";
+    case EbvColor:                return "Color";
+    case EbvSecondaryColor:       return "SecondaryColor";
+    case EbvFace:                 return "Face";
+    case EbvFragCoord:            return "FragCoord";
+    case EbvPointCoord:           return "PointCoord";
+    case EbvFragColor:            return "FragColor";
+    case EbvFragData:             return "FragData";
+    case EbvFragDepth:            return "FragDepth";
+    case EbvSampleId:             return "SampleId";
+    case EbvSamplePosition:       return "SamplePosition";
+    case EbvSampleMask:           return "SampleMaskIn";
+    case EbvHelperInvocation:     return "HelperInvocation";
+#ifdef AMD_EXTENSIONS
+    case EbvBaryCoordNoPersp:           return "BaryCoordNoPersp";
+    case EbvBaryCoordNoPerspCentroid:   return "BaryCoordNoPerspCentroid";
+    case EbvBaryCoordNoPerspSample:     return "BaryCoordNoPerspSample";
+    case EbvBaryCoordSmooth:            return "BaryCoordSmooth";
+    case EbvBaryCoordSmoothCentroid:    return "BaryCoordSmoothCentroid";
+    case EbvBaryCoordSmoothSample:      return "BaryCoordSmoothSample";
+    case EbvBaryCoordPullModel:         return "BaryCoordPullModel";
+#endif
+#ifdef NV_EXTENSIONS
+    case EbvViewportMaskNV:             return "ViewportMaskNV";
+    case EbvSecondaryPositionNV:        return "SecondaryPositionNV";
+    case EbvSecondaryViewportMaskNV:    return "SecondaryViewportMaskNV";
+#endif 
+    default:                      return "unknown built-in variable";
+    }
+}
+
+// In this enum, order matters; users can assume higher precision is a bigger value
+// and EpqNone is 0.
+enum TPrecisionQualifier {
+    EpqNone = 0,
+    EpqLow,
+    EpqMedium,
+    EpqHigh
+};
+
+__inline const char* GetPrecisionQualifierString(TPrecisionQualifier p)
+{
+    switch(p) {
+    case EpqNone:   return "";        break;
+    case EpqLow:    return "lowp";    break;
+    case EpqMedium: return "mediump"; break;
+    case EpqHigh:   return "highp";   break;
+    default:        return "unknown precision qualifier";
+    }
+}
+
+} // end namespace glslang
+
+#endif // _BASICTYPES_INCLUDED_

+ 266 - 0
src/libraries/glslang/glslang/Include/Common.h

@@ -0,0 +1,266 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || defined MINGW_HAS_SECURE_API
+    #include <basetsd.h>
+    #define snprintf sprintf_s
+    #define safe_vsprintf(buf,max,format,args) vsnprintf_s((buf), (max), (max), (format), (args))
+#elif defined (solaris)
+    #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
+    #include <sys/int_types.h>
+    #define UINT_PTR uintptr_t
+#else
+    #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
+    #include <stdint.h>
+    #define UINT_PTR uintptr_t
+#endif
+
+#if defined(__ANDROID__) || _MSC_VER < 1700
+#include <sstream>
+namespace std {
+template<typename T>
+std::string to_string(const T& val) {
+  std::ostringstream os;
+  os << val;
+  return os.str();
+}
+}
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1700
+inline long long int strtoll (const char* str, char** endptr, int base)
+{
+  return _strtoi64(str, endptr, base);
+}
+inline unsigned long long int strtoull (const char* str, char** endptr, int base)
+{
+  return _strtoui64(str, endptr, base);
+}
+inline long long int atoll (const char* str)
+{
+  return strtoll(str, NULL, 10);
+}
+#endif
+
+/* windows only pragma */
+#ifdef _MSC_VER
+    #pragma warning(disable : 4786) // Don't warn about too long identifiers
+    #pragma warning(disable : 4514) // unused inline method
+    #pragma warning(disable : 4201) // nameless union
+#endif
+
+#include <set>
+#include <unordered_set>
+#include <vector>
+#include <map>
+#include <unordered_map>
+#include <list>
+#include <algorithm>
+#include <string>
+#include <cstdio>
+#include <cassert>
+
+#include "PoolAlloc.h"
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE(A)                                  \
+    void* operator new(size_t s) { return (A).allocate(s); }          \
+    void* operator new(size_t, void *_Where) { return (_Where); }     \
+    void operator delete(void*) { }                                   \
+    void operator delete(void *, void *) { }                          \
+    void* operator new[](size_t s) { return (A).allocate(s); }        \
+    void* operator new[](size_t, void *_Where) { return (_Where); }   \
+    void operator delete[](void*) { }                                 \
+    void operator delete[](void *, void *) { }
+
+namespace glslang {
+
+    //
+    // Pool version of string.
+    //
+    typedef pool_allocator<char> TStringAllocator;
+    typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+
+} // end namespace glslang
+
+// Repackage the std::hash for use by unordered map/set with a TString key.
+namespace std {
+
+    template<> struct hash<glslang::TString> {
+        std::size_t operator()(const glslang::TString& s) const
+        {
+            const unsigned _FNV_offset_basis = 2166136261U;
+            const unsigned _FNV_prime = 16777619U;
+            unsigned _Val = _FNV_offset_basis;
+            size_t _Count = s.size();
+            const char* _First = s.c_str();
+            for (size_t _Next = 0; _Next < _Count; ++_Next)
+            {
+                _Val ^= (unsigned)_First[_Next];
+                _Val *= _FNV_prime;
+            }
+
+            return _Val;
+        }
+    };
+}
+
+namespace glslang {
+
+inline TString* NewPoolTString(const char* s)
+{
+    void* memory = GetThreadPoolAllocator().allocate(sizeof(TString));
+    return new(memory) TString(s);
+}
+
+template<class T> inline T* NewPoolObject(T)
+{
+    return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
+}
+
+template<class T> inline T* NewPoolObject(T, int instances)
+{
+    return new(GetThreadPoolAllocator().allocate(instances * sizeof(T))) T[instances];
+}
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    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) {}
+    TVector(size_type i, const T& val) : std::vector<T, pool_allocator<T> >(i, val) {}
+};
+
+template <class T> class TList  : public std::list<T, pool_allocator<T> > {
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<K const, D> > > {
+};
+
+template <class K, class D, class HASH = std::hash<K>, class PRED = std::equal_to<K> >
+class TUnorderedMap : public std::unordered_map<K, D, HASH, PRED, pool_allocator<std::pair<K const, D> > > {
+};
+
+//
+// Persistent string memory.  Should only be used for strings that survive
+// across compiles/links.
+//
+typedef std::basic_string<char> TPersistString;
+
+//
+// templatized min and max functions.
+//
+template <class T> T Min(const T a, const T b) { return a < b ? a : b; }
+template <class T> T Max(const T a, const T b) { return a > b ? a : b; }
+
+//
+// Create a TString object from an integer.
+//
+#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
+inline const TString String(const int i, const int base = 10)
+{
+    char text[16];     // 32 bit ints are at most 10 digits in base 10
+    _itoa_s(i, text, sizeof(text), base);
+    return text;
+}
+#else
+inline const TString String(const int i, const int /*base*/ = 10)
+{
+    char text[16];     // 32 bit ints are at most 10 digits in base 10
+
+    // we assume base 10 for all cases
+    snprintf(text, sizeof(text), "%d", i);
+
+    return text;
+}
+#endif
+
+struct TSourceLoc {
+    void init() { name = nullptr; string = 0; line = 0; column = 0; }
+    // Returns the name if it exists. Otherwise, returns the string number.
+    std::string getStringNameOrNum(bool quoteStringName = true) const
+    {
+        if (name != nullptr)
+            return quoteStringName ? ("\"" + std::string(name) + "\"") : name;
+        return std::to_string((long long)string);
+    }
+    const char* name; // descriptive name for this string
+    int string;
+    int line;
+    int column;
+};
+
+typedef TMap<TString, TString> TPragmaTable;
+
+const int MaxTokenLength = 1024;
+
+template <class T> bool IsPow2(T powerOf2)
+{
+    if (powerOf2 <= 0)
+        return false;
+
+    return (powerOf2 & (powerOf2 - 1)) == 0;
+}
+
+// Round number up to a multiple of the given powerOf2, which is not
+// a power, just a number that must be a power of 2.
+template <class T> void RoundToPow2(T& number, int powerOf2)
+{
+    assert(IsPow2(powerOf2));
+    number = (number + powerOf2 - 1) & ~(powerOf2 - 1);
+}
+
+template <class T> bool IsMultipleOfPow2(T number, int powerOf2)
+{
+    assert(IsPow2(powerOf2));
+    return ! (number & (powerOf2 - 1));
+}
+
+} // end namespace glslang
+
+#endif // _COMMON_INCLUDED_

+ 617 - 0
src/libraries/glslang/glslang/Include/ConstantUnion.h

@@ -0,0 +1,617 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+namespace glslang {
+
+class TConstUnion {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TConstUnion() : iConst(0), type(EbtInt) { }
+
+    void setIConst(int i)
+    {
+        iConst = i;
+        type = EbtInt;
+    }
+
+    void setUConst(unsigned int u)
+    {
+        uConst = u;
+        type = EbtUint;
+    }
+
+    void setI64Const(long long i64)
+    {
+        i64Const = i64;
+        type = EbtInt64;
+    }
+
+    void setU64Const(unsigned long long u64)
+    {
+        u64Const = u64;
+        type = EbtUint64;
+    }
+
+    void setDConst(double d)
+    {
+        dConst = d;
+        type = EbtDouble;
+    }
+
+    void setBConst(bool b)
+    {
+        bConst = b;
+        type = EbtBool;
+    }
+
+    int                getIConst() const   { return iConst; }
+    unsigned int       getUConst() const   { return uConst; }
+    long long          getI64Const() const { return i64Const; }
+    unsigned long long getU64Const() const { return u64Const; }
+    double             getDConst() const   { return dConst; }
+    bool               getBConst() const   { return bConst; }
+
+    bool operator==(const int i) const
+    {
+        if (i == iConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const unsigned int u) const
+    {
+        if (u == uConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const long long i64) const
+    {
+        if (i64 == i64Const)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const unsigned long long u64) const
+    {
+        if (u64 == u64Const)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const double d) const
+    {
+        if (d == dConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const bool b) const
+    {
+        if (b == bConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const TConstUnion& constant) const
+    {
+        if (constant.type != type)
+            return false;
+
+        switch (type) {
+        case EbtInt:
+            if (constant.iConst == iConst)
+                return true;
+
+            break;
+        case EbtUint:
+            if (constant.uConst == uConst)
+                return true;
+
+            break;
+        case EbtInt64:
+            if (constant.i64Const == i64Const)
+                return true;
+
+            break;
+        case EbtUint64:
+            if (constant.u64Const == u64Const)
+                return true;
+
+            break;
+        case EbtDouble:
+            if (constant.dConst == dConst)
+                return true;
+
+            break;
+        case EbtBool:
+            if (constant.bConst == bConst)
+                return true;
+
+            break;
+        default:
+            assert(false && "Default missing");
+        }
+
+        return false;
+    }
+
+    bool operator!=(const int i) const
+    {
+        return !operator==(i);
+    }
+
+    bool operator!=(const unsigned int u) const
+    {
+        return !operator==(u);
+    }
+
+    bool operator!=(const long long i) const
+    {
+        return !operator==(i);
+    }
+
+    bool operator!=(const unsigned long long u) const
+    {
+        return !operator==(u);
+    }
+
+    bool operator!=(const float f) const
+    {
+        return !operator==(f);
+    }
+
+    bool operator!=(const bool b) const
+    {
+        return !operator==(b);
+    }
+
+    bool operator!=(const TConstUnion& constant) const
+    {
+        return !operator==(constant);
+    }
+
+    bool operator>(const TConstUnion& constant) const
+    {
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:
+            if (iConst > constant.iConst)
+                return true;
+
+            return false;
+        case EbtUint:
+            if (uConst > constant.uConst)
+                return true;
+
+            return false;
+        case EbtInt64:
+            if (i64Const > constant.i64Const)
+                return true;
+
+            return false;
+        case EbtUint64:
+            if (u64Const > constant.u64Const)
+                return true;
+
+            return false;
+        case EbtDouble:
+            if (dConst > constant.dConst)
+                return true;
+
+            return false;
+        default:
+            assert(false && "Default missing");
+            return false;
+        }
+    }
+
+    bool operator<(const TConstUnion& constant) const
+    {
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:
+            if (iConst < constant.iConst)
+                return true;
+
+            return false;
+        case EbtUint:
+            if (uConst < constant.uConst)
+                return true;
+
+            return false;
+        case EbtInt64:
+            if (i64Const < constant.i64Const)
+                return true;
+
+            return false;
+        case EbtUint64:
+            if (u64Const < constant.u64Const)
+                return true;
+
+            return false;
+        case EbtDouble:
+            if (dConst < constant.dConst)
+                return true;
+
+            return false;
+        default:
+            assert(false && "Default missing");
+            return false;
+        }
+    }
+
+    TConstUnion operator+(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst + constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const + constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst + constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator-(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst - constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const - constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst - constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator*(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst * constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const * constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator%(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst % constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const % constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator>>(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setIConst(iConst >> constant.iConst);   break;
+            case EbtUint:   returnValue.setIConst(iConst >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setIConst(iConst >> constant.i64Const); break;
+            case EbtUint64: returnValue.setIConst(iConst >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setUConst(uConst >> constant.iConst);   break;
+            case EbtUint:   returnValue.setUConst(uConst >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setUConst(uConst >> constant.i64Const); break;
+            case EbtUint64: returnValue.setUConst(uConst >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+         case EbtInt64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setI64Const(i64Const >> constant.iConst);   break;
+            case EbtUint:   returnValue.setI64Const(i64Const >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setI64Const(i64Const >> constant.i64Const); break;
+            case EbtUint64: returnValue.setI64Const(i64Const >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setU64Const(u64Const >> constant.iConst);   break;
+            case EbtUint:   returnValue.setU64Const(u64Const >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setU64Const(u64Const >> constant.i64Const); break;
+            case EbtUint64: returnValue.setU64Const(u64Const >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator<<(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setIConst(iConst << constant.iConst);   break;
+            case EbtUint:   returnValue.setIConst(iConst << constant.uConst);   break;
+            case EbtInt64:  returnValue.setIConst(iConst << constant.i64Const); break;
+            case EbtUint64: returnValue.setIConst(iConst << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setUConst(uConst << constant.iConst);   break;
+            case EbtUint:   returnValue.setUConst(uConst << constant.uConst);   break;
+            case EbtInt64:  returnValue.setUConst(uConst << constant.i64Const); break;
+            case EbtUint64: returnValue.setUConst(uConst << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtInt64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setI64Const(i64Const << constant.iConst);   break;
+            case EbtUint:   returnValue.setI64Const(i64Const << constant.uConst);   break;
+            case EbtInt64:  returnValue.setI64Const(i64Const << constant.i64Const); break;
+            case EbtUint64: returnValue.setI64Const(i64Const << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setU64Const(u64Const << constant.iConst);   break;
+            case EbtUint:   returnValue.setU64Const(u64Const << constant.uConst);   break;
+            case EbtInt64:  returnValue.setU64Const(u64Const << constant.i64Const); break;
+            case EbtUint64: returnValue.setU64Const(u64Const << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator&(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst & constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst & constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const & constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const & constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator|(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst | constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst | constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const | constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const | constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator^(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst ^ constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const ^ constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const ^ constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator~() const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(~iConst); break;
+        case EbtUint: returnValue.setUConst(~uConst); break;
+        case EbtInt64:  returnValue.setI64Const(~i64Const); break;
+        case EbtUint64: returnValue.setU64Const(~u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator&&(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator||(const TConstUnion& constant) const
+    {
+        TConstUnion 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
+        unsigned int       uConst;      // used for uvec, scalar uints
+        long long          i64Const;    // used for i64vec, scalar int64s
+        unsigned long long u64Const;    // used for u64vec, scalar uint64s
+        bool               bConst;      // used for bvec, scalar bools
+        double             dConst;      // used for vec, dvec, mat, dmat, scalar floats and doubles
+    };
+
+    TBasicType type;
+};
+
+// Encapsulate having a pointer to an array of TConstUnion,
+// which only needs to be allocated if its size is going to be
+// bigger than 0.
+//
+// One convenience is being able to use [] to go inside the array, instead
+// of C++ assuming it as an array of pointers to vectors.
+//
+// General usage is that the size is known up front, and it is
+// created once with the proper size.
+//
+class TConstUnionArray {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TConstUnionArray() : unionArray(nullptr) { }
+    virtual ~TConstUnionArray() { }
+
+    explicit TConstUnionArray(int size)
+    {
+        if (size == 0)
+            unionArray = nullptr;
+        else
+            unionArray =  new TConstUnionVector(size);
+    }
+    TConstUnionArray(const TConstUnionArray& a) : unionArray(a.unionArray) { }
+    TConstUnionArray(const TConstUnionArray& a, int start, int size)
+    {
+        unionArray = new TConstUnionVector(size);
+        for (int i = 0; i < size; ++i)
+            (*unionArray)[i] = a[start + i];
+    }
+
+    // Use this constructor for a smear operation
+    TConstUnionArray(int size, const TConstUnion& val)
+    {
+        unionArray = new TConstUnionVector(size, val);
+    }
+
+    int size() const { return unionArray ? (int)unionArray->size() : 0; }
+    TConstUnion& operator[](size_t index) { return (*unionArray)[index]; }
+    const TConstUnion& operator[](size_t index) const { return (*unionArray)[index]; }
+    bool operator==(const TConstUnionArray& rhs) const
+    {
+        // this includes the case that both are unallocated
+        if (unionArray == rhs.unionArray)
+            return true;
+
+        if (! unionArray || ! rhs.unionArray)
+            return false;
+
+        if (! unionArray || ! rhs.unionArray)
+            return false;
+
+        return *unionArray == *rhs.unionArray;
+    }
+    bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); }
+
+    double dot(const TConstUnionArray& rhs)
+    {
+        assert(rhs.unionArray->size() == unionArray->size());
+        double sum = 0.0;
+
+        for (size_t comp = 0; comp < unionArray->size(); ++comp)
+            sum += (*this)[comp].getDConst() * rhs[comp].getDConst();
+
+        return sum;
+    }
+
+    bool empty() const { return unionArray == nullptr; }
+
+protected:
+    typedef TVector<TConstUnion> TConstUnionVector;
+    TConstUnionVector* unionArray;
+};
+
+} // end namespace glslang
+
+#endif // _CONSTANT_UNION_INCLUDED_

+ 144 - 0
src/libraries/glslang/glslang/Include/InfoSink.h

@@ -0,0 +1,144 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include "../Include/Common.h"
+#include <cmath>
+
+namespace glslang {
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+    EPrefixNone,
+    EPrefixWarning,
+    EPrefixError,
+    EPrefixInternalError,
+    EPrefixUnimplemented,
+    EPrefixNote
+};
+
+enum TOutputStream {
+    ENull = 0,
+    EDebugger = 0x01,
+    EStdOut = 0x02,
+    EString = 0x04,
+};
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+    TInfoSinkBase() : outputStream(4) {}
+    void erase() { sink.erase(); }
+    TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; }
+    TInfoSinkBase& operator<<(char c)                  { append(1, c); return *this; }
+    TInfoSinkBase& operator<<(const char* s)           { append(s); return *this; }
+    TInfoSinkBase& operator<<(int n)                   { append(String(n)); return *this; }
+    TInfoSinkBase& operator<<(unsigned int n)          { append(String(n)); return *this; }
+    TInfoSinkBase& operator<<(float n)                 { const int size = 40; char buf[size];
+                                                         snprintf(buf, size, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? "%f" : "%g", n);
+                                                         append(buf);
+                                                         return *this; }
+    TInfoSinkBase& operator+(const TPersistString& t)  { append(t); return *this; }
+    TInfoSinkBase& operator+(const TString& t)         { append(t); return *this; }
+    TInfoSinkBase& operator<<(const TString& t)        { append(t); return *this; }
+    TInfoSinkBase& operator+(const char* s)            { append(s); return *this; }
+    const char* c_str() const { return sink.c_str(); }
+    void prefix(TPrefixType message) {
+        switch(message) {
+        case EPrefixNone:                                      break;
+        case EPrefixWarning:       append("WARNING: ");        break;
+        case EPrefixError:         append("ERROR: ");          break;
+        case EPrefixInternalError: append("INTERNAL ERROR: "); break;
+        case EPrefixUnimplemented: append("UNIMPLEMENTED: ");  break;
+        case EPrefixNote:          append("NOTE: ");           break;
+        default:                   append("UNKNOWN ERROR: ");   break;
+        }
+    }
+    void location(const TSourceLoc& loc) {
+        const int maxSize = 24;
+        char locText[maxSize];
+        snprintf(locText, maxSize, ":%d", loc.line);
+        append(loc.getStringNameOrNum(false).c_str());
+        append(locText);
+        append(": ");
+    }
+    void message(TPrefixType message, const char* s) {
+        prefix(message);
+        append(s);
+        append("\n");
+    }
+    void message(TPrefixType message, const char* s, const TSourceLoc& loc) {
+        prefix(message);
+        location(loc);
+        append(s);
+        append("\n");
+    }
+
+    void setOutputStream(int output = 4)
+    {
+        outputStream = output;
+    }
+
+protected:
+    void append(const char* s);
+
+    void append(int count, char c);
+    void append(const TPersistString& t);
+    void append(const TString& t);
+
+    void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2)
+                                       sink.reserve(sink.capacity() +  sink.capacity() / 2); }
+    void appendToStream(const char* s);
+    TPersistString sink;
+    int outputStream;
+};
+
+} // end namespace glslang
+
+class TInfoSink {
+public:
+    glslang::TInfoSinkBase info;
+    glslang::TInfoSinkBase debug;
+};
+
+#endif // _INFOSINK_INCLUDED_

+ 47 - 0
src/libraries/glslang/glslang/Include/InitializeGlobals.h

@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+namespace glslang {
+
+void InitializeMemoryPools();
+void FreeGlobalPools();
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+} // end namespace glslang
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_

+ 324 - 0
src/libraries/glslang/glslang/Include/PoolAlloc.h

@@ -0,0 +1,324 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#  define GUARD_BLOCKS  // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+//     typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+namespace glslang {
+
+// If we are using guard blocks, we must track each individual
+// allocation.  If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+    TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+        size(size), mem(mem), prevAlloc(prev) {
+        // Allocations are bracketed:
+        //    [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+        // This would be cleaner with if (guardBlockSize)..., but that
+        // makes the compiler print warnings about 0 length memsets,
+        // even with the if() protecting them.
+#       ifdef GUARD_BLOCKS
+            memset(preGuard(),  guardBlockBeginVal, guardBlockSize);
+            memset(data(),      userDataFill,       size);
+            memset(postGuard(), guardBlockEndVal,   guardBlockSize);
+#       endif
+    }
+
+    void check() const {
+        checkGuardBlock(preGuard(),  guardBlockBeginVal, "before");
+        checkGuardBlock(postGuard(), guardBlockEndVal,   "after");
+    }
+
+    void checkAllocList() const;
+
+    // Return total size needed to accommodate user buffer of 'size',
+    // plus our tracking data.
+    inline static size_t allocationSize(size_t size) {
+        return size + 2 * guardBlockSize + headerSize();
+    }
+
+    // Offset from surrounding buffer to get to user data buffer.
+    inline static unsigned char* offsetAllocation(unsigned char* m) {
+        return m + guardBlockSize + headerSize();
+    }
+
+private:
+    void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+    // Find offsets to pre and post guard blocks, and user data buffer
+    unsigned char* preGuard()  const { return mem + headerSize(); }
+    unsigned char* data()      const { return preGuard() + guardBlockSize; }
+    unsigned char* postGuard() const { return data() + size; }
+
+    size_t size;                  // size of the user data area
+    unsigned char* mem;           // beginning of our allocation (pts to header)
+    TAllocation* prevAlloc;       // prior allocation in the chain
+
+    const static unsigned char guardBlockBeginVal;
+    const static unsigned char guardBlockEndVal;
+    const static unsigned char userDataFill;
+
+    const static size_t guardBlockSize;
+#   ifdef GUARD_BLOCKS
+    inline static size_t headerSize() { return sizeof(TAllocation); }
+#   else
+    inline static size_t headerSize() { return 0; }
+#   endif
+};
+
+//
+// There are several stacks.  One is to track the pushing and popping
+// of the user, and not yet implemented.  The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS.  Multi-page allocations
+// are returned to the OS.  Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size.  But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+    TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+    //
+    // Don't call the destructor just to free up the memory, call pop()
+    //
+    ~TPoolAllocator();
+
+    //
+    // Call push() to establish a new place to pop memory too.  Does not
+    // have to be called to get things started.
+    //
+    void push();
+
+    //
+    // Call pop() to free all memory allocated since the last call to push(),
+    // or if no last call to push, frees all memory since first allocation.
+    //
+    void pop();
+
+    //
+    // Call popAll() to free all memory allocated.
+    //
+    void popAll();
+
+    //
+    // Call allocate() to actually acquire memory.  Returns 0 if no memory
+    // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+    //
+    void* allocate(size_t numBytes);
+
+    //
+    // There is no deallocate.  The point of this class is that
+    // deallocation can be skipped by the user of it, as the model
+    // of use is to simultaneously deallocate everything at once
+    // by calling pop(), and to not have to solve memory leak problems.
+    //
+
+protected:
+    friend struct tHeader;
+
+    struct tHeader {
+        tHeader(tHeader* nextPage, size_t pageCount) :
+#ifdef GUARD_BLOCKS
+        lastAllocation(0),
+#endif
+        nextPage(nextPage), pageCount(pageCount) { }
+
+        ~tHeader() {
+#ifdef GUARD_BLOCKS
+            if (lastAllocation)
+                lastAllocation->checkAllocList();
+#endif
+        }
+
+#ifdef GUARD_BLOCKS
+        TAllocation* lastAllocation;
+#endif
+        tHeader* nextPage;
+        size_t pageCount;
+    };
+
+    struct tAllocState {
+        size_t offset;
+        tHeader* page;
+    };
+    typedef std::vector<tAllocState> tAllocStack;
+
+    // Track allocations if and only if we're using guard blocks
+#ifndef GUARD_BLOCKS
+    void* initializeAllocation(tHeader*, unsigned char* memory, size_t) {
+#else
+    void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+        new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+        block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+
+        // This is optimized entirely away if GUARD_BLOCKS is not defined.
+        return TAllocation::offsetAllocation(memory);
+    }
+
+    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
+
+    int numCalls;           // just an interesting statistic
+    size_t totalBytes;      // just an interesting statistic
+private:
+    TPoolAllocator& operator=(const TPoolAllocator&);  // don't allow assignment operator
+    TPoolAllocator(const TPoolAllocator&);  // don't allow default copy constructor
+};
+
+//
+// There could potentially be many pools with pops happening at
+// different times.  But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+typedef TPoolAllocator* PoolAllocatorPointer;
+extern TPoolAllocator& GetThreadPoolAllocator();
+
+struct TThreadMemoryPools
+{
+        TPoolAllocator* threadPoolAllocator;
+};
+
+void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+    typedef T *pointer;
+    typedef const T *const_pointer;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef T value_type;
+    template<class Other>
+        struct rebind {
+            typedef pool_allocator<Other> other;
+        };
+    pointer address(reference x) const { return &x; }
+    const_pointer address(const_reference x) const { return &x; }
+
+    pool_allocator() : allocator(GetThreadPoolAllocator()) { }
+    pool_allocator(TPoolAllocator& a) : allocator(a) { }
+    pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+    template<class Other>
+        pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
+
+    pointer allocate(size_type n) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
+    pointer allocate(size_type n, const void*) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
+
+    void deallocate(void*, size_type) { }
+    void deallocate(pointer, size_type) { }
+
+    pointer _Charalloc(size_t n) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n)); }
+
+    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(); }
+
+    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:
+    pool_allocator& operator=(const pool_allocator&) { return *this; }
+    TPoolAllocator& allocator;
+};
+
+} // end namespace glslang
+
+#endif // _POOLALLOC_INCLUDED_

+ 140 - 0
src/libraries/glslang/glslang/Include/ResourceLimits.h

@@ -0,0 +1,140 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _RESOURCE_LIMITS_INCLUDED_
+#define _RESOURCE_LIMITS_INCLUDED_
+
+struct TLimits {
+    bool nonInductiveForLoops;
+    bool whileLoops;
+    bool doWhileLoops;
+    bool generalUniformIndexing;
+    bool generalAttributeMatrixVectorIndexing;
+    bool generalVaryingIndexing;
+    bool generalSamplerIndexing;
+    bool generalVariableIndexing;
+    bool generalConstantMatrixVectorIndexing;
+};
+
+struct TBuiltInResource {
+    int maxLights;
+    int maxClipPlanes;
+    int maxTextureUnits;
+    int maxTextureCoords;
+    int maxVertexAttribs;
+    int maxVertexUniformComponents;
+    int maxVaryingFloats;
+    int maxVertexTextureImageUnits;
+    int maxCombinedTextureImageUnits;
+    int maxTextureImageUnits;
+    int maxFragmentUniformComponents;
+    int maxDrawBuffers;
+    int maxVertexUniformVectors;
+    int maxVaryingVectors;
+    int maxFragmentUniformVectors;
+    int maxVertexOutputVectors;
+    int maxFragmentInputVectors;
+    int minProgramTexelOffset;
+    int maxProgramTexelOffset;
+    int maxClipDistances;
+    int maxComputeWorkGroupCountX;
+    int maxComputeWorkGroupCountY;
+    int maxComputeWorkGroupCountZ;
+    int maxComputeWorkGroupSizeX;
+    int maxComputeWorkGroupSizeY;
+    int maxComputeWorkGroupSizeZ;
+    int maxComputeUniformComponents;
+    int maxComputeTextureImageUnits;
+    int maxComputeImageUniforms;
+    int maxComputeAtomicCounters;
+    int maxComputeAtomicCounterBuffers;
+    int maxVaryingComponents;
+    int maxVertexOutputComponents;
+    int maxGeometryInputComponents;
+    int maxGeometryOutputComponents;
+    int maxFragmentInputComponents;
+    int maxImageUnits;
+    int maxCombinedImageUnitsAndFragmentOutputs;
+    int maxCombinedShaderOutputResources;
+    int maxImageSamples;
+    int maxVertexImageUniforms;
+    int maxTessControlImageUniforms;
+    int maxTessEvaluationImageUniforms;
+    int maxGeometryImageUniforms;
+    int maxFragmentImageUniforms;
+    int maxCombinedImageUniforms;
+    int maxGeometryTextureImageUnits;
+    int maxGeometryOutputVertices;
+    int maxGeometryTotalOutputComponents;
+    int maxGeometryUniformComponents;
+    int maxGeometryVaryingComponents;
+    int maxTessControlInputComponents;
+    int maxTessControlOutputComponents;
+    int maxTessControlTextureImageUnits;
+    int maxTessControlUniformComponents;
+    int maxTessControlTotalOutputComponents;
+    int maxTessEvaluationInputComponents;
+    int maxTessEvaluationOutputComponents;
+    int maxTessEvaluationTextureImageUnits;
+    int maxTessEvaluationUniformComponents;
+    int maxTessPatchComponents;
+    int maxPatchVertices;
+    int maxTessGenLevel;
+    int maxViewports;
+    int maxVertexAtomicCounters;
+    int maxTessControlAtomicCounters;
+    int maxTessEvaluationAtomicCounters;
+    int maxGeometryAtomicCounters;
+    int maxFragmentAtomicCounters;
+    int maxCombinedAtomicCounters;
+    int maxAtomicCounterBindings;
+    int maxVertexAtomicCounterBuffers;
+    int maxTessControlAtomicCounterBuffers;
+    int maxTessEvaluationAtomicCounterBuffers;
+    int maxGeometryAtomicCounterBuffers;
+    int maxFragmentAtomicCounterBuffers;
+    int maxCombinedAtomicCounterBuffers;
+    int maxAtomicCounterBufferSize;
+    int maxTransformFeedbackBuffers;
+    int maxTransformFeedbackInterleavedComponents;
+    int maxCullDistances;
+    int maxCombinedClipAndCullDistances;
+    int maxSamples;
+
+    TLimits limits;
+};
+
+#endif // _RESOURCE_LIMITS_INCLUDED_

+ 173 - 0
src/libraries/glslang/glslang/Include/ShHandle.h

@@ -0,0 +1,173 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#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.
+//
+
+#define SH_EXPORTING
+#include "../Public/ShaderLang.h"
+#include "../MachineIndependent/Versions.h"
+#include "InfoSink.h"
+
+class TCompiler;
+class TLinker;
+class TUniformMap;
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+    TShHandleBase() { }
+    virtual ~TShHandleBase() { }
+    virtual TCompiler* getAsCompiler() { return 0; }
+    virtual TLinker* getAsLinker() { return 0; }
+    virtual TUniformMap* getAsUniformMap() { return 0; }
+};
+
+//
+// The base class for the machine dependent linker to derive from
+// for managing where uniforms live.
+//
+class TUniformMap : public TShHandleBase {
+public:
+    TUniformMap() { }
+    virtual ~TUniformMap() { }
+    virtual TUniformMap* getAsUniformMap() { return this; }
+    virtual int getLocation(const char* name) = 0;
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+    TInfoSink infoSink;
+};
+
+class TIntermNode;
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+    TCompiler(EShLanguage l, TInfoSink& sink) : infoSink(sink) , language(l), haveValidObjectCode(false) { }
+    virtual ~TCompiler() { }
+    EShLanguage getLanguage() { return language; }
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+
+    virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile) = 0;
+
+    virtual TCompiler* getAsCompiler() { return this; }
+    virtual bool linkable() { return haveValidObjectCode; }
+
+    TInfoSink& infoSink;
+protected:
+    TCompiler& operator=(TCompiler&);
+
+    EShLanguage language;
+    bool haveValidObjectCode;
+};
+
+//
+// Link operations are based on a list of compile results...
+//
+typedef glslang::TVector<TCompiler*> TCompilerList;
+typedef glslang::TVector<TShHandleBase*> THandleList;
+
+//
+// The base class for the machine dependent linker to derive from
+// to manage the resulting executable.
+//
+
+class TLinker : public TShHandleBase {
+public:
+    TLinker(EShExecutable e, TInfoSink& iSink) :
+        infoSink(iSink),
+        executable(e),
+        haveReturnableObjectCode(false),
+        appAttributeBindings(0),
+        fixedAttributeBindings(0),
+        excludedAttributes(0),
+        excludedCount(0),
+        uniformBindings(0) { }
+    virtual TLinker* getAsLinker() { return this; }
+    virtual ~TLinker() { }
+    virtual bool link(TCompilerList&, TUniformMap*) = 0;
+    virtual bool link(THandleList&) { return false; }
+    virtual void setAppAttributeBindings(const ShBindingTable* t)   { appAttributeBindings = t; }
+    virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; }
+    virtual void getAttributeBindings(ShBindingTable const **t) const = 0;
+    virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; }
+    virtual ShBindingTable* getUniformBindings() const  { return uniformBindings; }
+    virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+    TInfoSink& infoSink;
+protected:
+    TLinker& operator=(TLinker&);
+    EShExecutable executable;
+    bool haveReturnableObjectCode;  // true when objectCode is acceptable to send to driver
+
+    const ShBindingTable* appAttributeBindings;
+    const ShBindingTable* fixedAttributeBindings;
+    const int* excludedAttributes;
+    int excludedCount;
+    ShBindingTable* uniformBindings;                // created by the linker
+};
+
+//
+// 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(EShLanguage, int);
+
+TShHandleBase* ConstructLinker(EShExecutable, int);
+TShHandleBase* ConstructBindings();
+void DeleteLinker(TShHandleBase*);
+void DeleteBindingList(TShHandleBase* bindingList);
+
+TUniformMap* ConstructUniformMap();
+void DeleteCompiler(TCompiler*);
+
+void DeleteUniformMap(TUniformMap*);
+
+#endif // _SHHANDLE_INCLUDED_

+ 1855 - 0
src/libraries/glslang/glslang/Include/Types.h

@@ -0,0 +1,1855 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "../Include/Common.h"
+#include "../Include/BaseTypes.h"
+#include "../Public/ShaderLang.h"
+#include "arrays.h"
+
+namespace glslang {
+
+const int GlslangMaxTypeLength = 200;  // TODO: need to print block/struct one member per line, so this can stay bounded
+
+const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
+inline bool IsAnonymous(const TString& name)
+{
+    return name.compare(0, 5, AnonymousPrefix) == 0;
+}
+
+//
+// Details within a sampler type
+//
+enum TSamplerDim {
+    EsdNone,
+    Esd1D,
+    Esd2D,
+    Esd3D,
+    EsdCube,
+    EsdRect,
+    EsdBuffer,
+    EsdSubpass,  // goes only with non-sampled image (image is true)
+    EsdNumDims
+};
+
+struct TSampler {   // misnomer now; includes images, textures without sampler, and textures with sampler
+    TBasicType type : 8;  // type returned by sampler
+    TSamplerDim dim : 8;
+    bool    arrayed : 1;
+    bool     shadow : 1;
+    bool         ms : 1;
+    bool      image : 1;  // image, combined should be false
+    bool   combined : 1;  // true means texture is combined with a sampler, false means texture with no sampler
+    bool    sampler : 1;  // true means a pure sampler, other fields should be clear()
+    bool   external : 1;  // GL_OES_EGL_image_external
+    unsigned int vectorSize : 3;  // return vector size.  TODO: support arbitrary types.
+
+    bool isImage()       const { return image && dim != EsdSubpass; }
+    bool isSubpass()     const { return dim == EsdSubpass; }
+    bool isCombined()    const { return combined; }
+    bool isPureSampler() const { return sampler; }
+    bool isTexture()     const { return !sampler && !image; }
+    bool isShadow()      const { return shadow; }
+    bool isArrayed()     const { return arrayed; }
+    bool isMultiSample() const { return ms; }
+
+    void clear()
+    {
+        type = EbtVoid;
+        dim = EsdNone;
+        arrayed = false;
+        shadow = false;
+        ms = false;
+        image = false;
+        combined = false;
+        sampler = false;
+        external = false;
+        vectorSize = 4;
+    }
+
+    // make a combined sampler and texture
+    void set(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+        combined = true;
+    }
+
+    // make an image
+    void setImage(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+        image = true;
+    }
+
+    // make a texture with no sampler
+    void setTexture(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+    }
+
+    // make a subpass input attachment
+    void setSubpass(TBasicType t, bool m = false)
+    {
+        clear();
+        type = t;
+        image = true;
+        dim = EsdSubpass;
+        ms = m;
+    }
+
+    // make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
+    void setPureSampler(bool s)
+    {
+        clear();
+        sampler = true;
+        shadow = s;
+    }
+
+    bool operator==(const TSampler& right) const
+    {
+        return type == right.type &&
+                dim == right.dim &&
+            arrayed == right.arrayed &&
+             shadow == right.shadow &&
+                 ms == right.ms &&
+              image == right.image &&
+           combined == right.combined &&
+            sampler == right.sampler &&
+           external == right.external &&
+         vectorSize == right.vectorSize;
+    }
+
+    bool operator!=(const TSampler& right) const
+    {
+        return ! operator==(right);
+    }
+
+    TString getString() const
+    {
+        TString s;
+
+        if (sampler) {
+            s.append("sampler");
+            return s;
+        }
+
+        switch (type) {
+        case EbtFloat:               break;
+        case EbtInt:  s.append("i"); break;
+        case EbtUint: s.append("u"); break;
+        default:  break;  // some compilers want this
+        }
+        if (image) {
+            if (dim == EsdSubpass)
+                s.append("subpass");
+            else
+                s.append("image");
+        } else if (combined) {
+            s.append("sampler");
+        } else {
+            s.append("texture");
+        }
+        if (external) {
+            s.append("ExternalOES");
+            return s;
+        }
+        switch (dim) {
+        case Esd1D:      s.append("1D");      break;
+        case Esd2D:      s.append("2D");      break;
+        case Esd3D:      s.append("3D");      break;
+        case EsdCube:    s.append("Cube");    break;
+        case EsdRect:    s.append("2DRect");  break;
+        case EsdBuffer:  s.append("Buffer");  break;
+        case EsdSubpass: s.append("Input"); break;
+        default:  break;  // some compilers want this
+        }
+        if (ms)
+            s.append("MS");
+        if (arrayed)
+            s.append("Array");
+        if (shadow)
+            s.append("Shadow");
+
+        return s;
+    }
+};
+
+//
+// Need to have association of line numbers to types in a list for building structs.
+//
+class TType;
+struct TTypeLoc {
+    TType* type;
+    TSourceLoc loc;
+};
+typedef TVector<TTypeLoc> TTypeList;
+
+typedef TVector<TString*> TIdentifierList;
+
+//
+// Following are a series of helper enums for managing layouts and qualifiers,
+// used for TPublicType, TType, others.
+//
+
+enum TLayoutPacking {
+    ElpNone,
+    ElpShared,      // default, but different than saying nothing
+    ElpStd140,
+    ElpStd430,
+    ElpPacked,
+    ElpCount        // If expanding, see bitfield width below
+};
+
+enum TLayoutMatrix {
+    ElmNone,
+    ElmRowMajor,
+    ElmColumnMajor, // default, but different than saying nothing
+    ElmCount        // If expanding, see bitfield width below
+};
+
+// Union of geometry shader and tessellation shader geometry types.
+// They don't go into TType, but rather have current state per shader or
+// active parser type (TPublicType).
+enum TLayoutGeometry {
+    ElgNone,
+    ElgPoints,
+    ElgLines,
+    ElgLinesAdjacency,
+    ElgLineStrip,
+    ElgTriangles,
+    ElgTrianglesAdjacency,
+    ElgTriangleStrip,
+    ElgQuads,
+    ElgIsolines,
+};
+
+enum TVertexSpacing {
+    EvsNone,
+    EvsEqual,
+    EvsFractionalEven,
+    EvsFractionalOdd
+};
+
+enum TVertexOrder {
+    EvoNone,
+    EvoCw,
+    EvoCcw
+};
+
+// Note: order matters, as type of format is done by comparison.
+enum TLayoutFormat {
+    ElfNone,
+
+    // Float image
+    ElfRgba32f,
+    ElfRgba16f,
+    ElfR32f,
+    ElfRgba8,
+    ElfRgba8Snorm,
+
+    ElfEsFloatGuard,    // to help with comparisons
+
+    ElfRg32f,
+    ElfRg16f,
+    ElfR11fG11fB10f,
+    ElfR16f,
+    ElfRgba16,
+    ElfRgb10A2,
+    ElfRg16,
+    ElfRg8,
+    ElfR16,
+    ElfR8,
+    ElfRgba16Snorm,
+    ElfRg16Snorm,
+    ElfRg8Snorm,
+    ElfR16Snorm,
+    ElfR8Snorm,
+
+    ElfFloatGuard,      // to help with comparisons
+
+    // Int image
+    ElfRgba32i,
+    ElfRgba16i,
+    ElfRgba8i,
+    ElfR32i,
+
+    ElfEsIntGuard,     // to help with comparisons
+
+    ElfRg32i,
+    ElfRg16i,
+    ElfRg8i,
+    ElfR16i,
+    ElfR8i,
+
+    ElfIntGuard,       // to help with comparisons
+
+    // Uint image
+    ElfRgba32ui,
+    ElfRgba16ui,
+    ElfRgba8ui,
+    ElfR32ui,
+
+    ElfEsUintGuard,    // to help with comparisons
+
+    ElfRg32ui,
+    ElfRg16ui,
+    ElfRgb10a2ui,
+    ElfRg8ui,
+    ElfR16ui,
+    ElfR8ui,
+
+    ElfCount
+};
+
+enum TLayoutDepth {
+    EldNone,
+    EldAny,
+    EldGreater,
+    EldLess,
+    EldUnchanged,
+
+    EldCount
+};
+
+enum TBlendEquationShift {
+    // No 'EBlendNone':
+    // These are used as bit-shift amounts.  A mask of such shifts will have type 'int',
+    // and in that space, 0 means no bits set, or none.  In this enum, 0 means (1 << 0), a bit is set.
+    EBlendMultiply,
+    EBlendScreen,
+    EBlendOverlay,
+    EBlendDarken,
+    EBlendLighten,
+    EBlendColordodge,
+    EBlendColorburn,
+    EBlendHardlight,
+    EBlendSoftlight,
+    EBlendDifference,
+    EBlendExclusion,
+    EBlendHslHue,
+    EBlendHslSaturation,
+    EBlendHslColor,
+    EBlendHslLuminosity,
+    EBlendAllEquations,
+
+    EBlendCount
+};
+
+class TQualifier {
+public:
+    static const int layoutNotSet = -1;
+
+    void clear()
+    {
+        precision = EpqNone;
+        invariant = false;
+        noContraction = false;
+        makeTemporary();
+    }
+
+    // drop qualifiers that don't belong in a temporary variable
+    void makeTemporary()
+    {
+        storage      = EvqTemporary;
+        builtIn      = EbvNone;
+        centroid     = false;
+        smooth       = false;
+        flat         = false;
+        nopersp      = false;
+#ifdef AMD_EXTENSIONS
+        explicitInterp = false;
+#endif
+        patch        = false;
+        sample       = false;
+        coherent     = false;
+        volatil      = false;
+        restrict     = false;
+        readonly     = false;
+        writeonly    = false;
+        specConstant = false;
+        clearLayout();
+    }
+
+    // Drop just the storage qualification, which perhaps should
+    // never be done, as it is fundamentally inconsistent, but need to
+    // explore what downstream consumers need.
+    // E.g., in a deference, it is an inconsistency between:
+    // A) partially dereferenced resource is still in the storage class it started in
+    // B) partially dereferenced resource is a new temporary object
+    // If A, then nothing should change, if B, then everything should change, but this is half way.
+    void makePartialTemporary()
+    {
+        storage      = EvqTemporary;
+        specConstant = false;
+    }
+
+    TStorageQualifier   storage   : 6;
+    TBuiltInVariable    builtIn   : 8;
+    TPrecisionQualifier precision : 3;
+    bool invariant    : 1; // require canonical treatment for cross-shader invariance
+    bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
+    bool centroid     : 1;
+    bool smooth       : 1;
+    bool flat         : 1;
+    bool nopersp      : 1;
+#ifdef AMD_EXTENSIONS
+    bool explicitInterp : 1;
+#endif
+    bool patch        : 1;
+    bool sample       : 1;
+    bool coherent     : 1;
+    bool volatil      : 1;
+    bool restrict     : 1;
+    bool readonly     : 1;
+    bool writeonly    : 1;
+    bool specConstant : 1;  // having a constant_id is not sufficient: expressions have no id, but are still specConstant
+
+    bool isMemory() const
+    {
+        return coherent || volatil || restrict || readonly || writeonly;
+    }
+    bool isInterpolation() const
+    {
+#ifdef AMD_EXTENSIONS
+        return flat || smooth || nopersp || explicitInterp;
+#else
+        return flat || smooth || nopersp;
+#endif
+    }
+    bool isAuxiliary() const
+    {
+        return centroid || patch || sample;
+    }
+
+    bool isPipeInput() const
+    {
+        switch (storage) {
+        case EvqVaryingIn:
+        case EvqFragCoord:
+        case EvqPointCoord:
+        case EvqFace:
+        case EvqVertexId:
+        case EvqInstanceId:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isPipeOutput() const
+    {
+        switch (storage) {
+        case EvqPosition:
+        case EvqPointSize:
+        case EvqClipVertex:
+        case EvqVaryingOut:
+        case EvqFragColor:
+        case EvqFragDepth:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isParamInput() const
+    {
+        switch (storage) {
+        case EvqIn:
+        case EvqInOut:
+        case EvqConstReadOnly:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isParamOutput() const
+    {
+        switch (storage) {
+        case EvqOut:
+        case EvqInOut:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isUniformOrBuffer() const
+    {
+        switch (storage) {
+        case EvqUniform:
+        case EvqBuffer:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isIo() const
+    {
+        switch (storage) {
+        case EvqUniform:
+        case EvqBuffer:
+        case EvqVaryingIn:
+        case EvqFragCoord:
+        case EvqPointCoord:
+        case EvqFace:
+        case EvqVertexId:
+        case EvqInstanceId:
+        case EvqPosition:
+        case EvqPointSize:
+        case EvqClipVertex:
+        case EvqVaryingOut:
+        case EvqFragColor:
+        case EvqFragDepth:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // True if this type of IO is supposed to be arrayed with extra level for per-vertex data
+    bool isArrayedIo(EShLanguage language) const
+    {
+        switch (language) {
+        case EShLangGeometry:
+            return isPipeInput();
+        case EShLangTessControl:
+            return ! patch && (isPipeInput() || isPipeOutput());
+        case EShLangTessEvaluation:
+            return ! patch && isPipeInput();
+        default:
+            return false;
+        }
+    }
+
+    // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
+    void clearLayout()
+    {
+        layoutMatrix = ElmNone;
+        layoutPacking = ElpNone;
+        layoutOffset = layoutNotSet;
+        layoutAlign = layoutNotSet;
+
+        layoutLocation = layoutLocationEnd;
+        layoutComponent = layoutComponentEnd;
+        layoutSet = layoutSetEnd;
+        layoutBinding = layoutBindingEnd;
+        layoutIndex = layoutIndexEnd;
+
+        layoutStream = layoutStreamEnd;
+
+        layoutXfbBuffer = layoutXfbBufferEnd;
+        layoutXfbStride = layoutXfbStrideEnd;
+        layoutXfbOffset = layoutXfbOffsetEnd;
+        layoutAttachment = layoutAttachmentEnd;
+        layoutSpecConstantId = layoutSpecConstantIdEnd;
+
+        layoutFormat = ElfNone;
+
+        layoutPushConstant = false;
+#ifdef NV_EXTENSIONS
+        layoutPassthrough = false;
+        layoutViewportRelative = false;
+        // -2048 as the default vaule indicating layoutSecondaryViewportRelative is not set
+        layoutSecondaryViewportRelativeOffset = -2048;
+#endif
+    }
+    bool hasLayout() const
+    {
+        return hasUniformLayout() ||
+               hasAnyLocation() ||
+               hasBinding() ||
+               hasStream() ||
+               hasXfb() ||
+               hasFormat() ||
+               layoutPushConstant;
+    }
+    TLayoutMatrix  layoutMatrix  : 3;
+    TLayoutPacking layoutPacking : 4;
+    int layoutOffset;
+    int layoutAlign;
+
+                 unsigned int layoutLocation            :12;
+    static const unsigned int layoutLocationEnd    =  0xFFF;
+
+                 unsigned int layoutComponent           : 3;
+    static const unsigned int layoutComponentEnd    =     4;
+
+                 unsigned int layoutSet                 : 7;
+    static const unsigned int layoutSetEnd         =   0x3F;
+
+                 unsigned int layoutBinding            : 16;
+    static const unsigned int layoutBindingEnd    =  0xFFFF;
+
+                 unsigned int layoutIndex              :  8;
+    static const unsigned int layoutIndexEnd    =      0xFF;
+
+                 unsigned int layoutStream              : 8;
+    static const unsigned int layoutStreamEnd    =     0xFF;
+
+                 unsigned int layoutXfbBuffer           : 4;
+    static const unsigned int layoutXfbBufferEnd    =   0xF;
+
+                 unsigned int layoutXfbStride          : 10;
+    static const unsigned int layoutXfbStrideEnd    = 0x3FF;
+
+                 unsigned int layoutXfbOffset          : 10;
+    static const unsigned int layoutXfbOffsetEnd    = 0x3FF;
+
+                 unsigned int layoutAttachment          : 8;  // for input_attachment_index
+    static const unsigned int layoutAttachmentEnd    = 0XFF;
+
+                 unsigned int layoutSpecConstantId       : 11;
+    static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
+
+    TLayoutFormat layoutFormat                         :  8;
+
+    bool layoutPushConstant;
+
+#ifdef NV_EXTENSIONS
+    bool layoutPassthrough;
+    bool layoutViewportRelative;
+    int layoutSecondaryViewportRelativeOffset;
+#endif
+
+    bool hasUniformLayout() const
+    {
+        return hasMatrix() ||
+               hasPacking() ||
+               hasOffset() ||
+               hasBinding() ||
+               hasAlign();
+    }
+    bool hasMatrix() const
+    {
+        return layoutMatrix != ElmNone;
+    }
+    bool hasPacking() const
+    {
+        return layoutPacking != ElpNone;
+    }
+    bool hasOffset() const
+    {
+        return layoutOffset != layoutNotSet;
+    }
+    bool hasAlign() const
+    {
+        return layoutAlign != layoutNotSet;
+    }
+    bool hasAnyLocation() const
+    {
+        return hasLocation() ||
+               hasComponent() ||
+               hasIndex();
+    }
+    bool hasLocation() const
+    {
+        return layoutLocation != layoutLocationEnd;
+    }
+    bool hasComponent() const
+    {
+        return layoutComponent != layoutComponentEnd;
+    }
+    bool hasIndex() const
+    {
+        return layoutIndex != layoutIndexEnd;
+    }
+    bool hasSet() const
+    {
+        return layoutSet != layoutSetEnd;
+    }
+    bool hasBinding() const
+    {
+        return layoutBinding != layoutBindingEnd;
+    }
+    bool hasStream() const
+    {
+        return layoutStream != layoutStreamEnd;
+    }
+    bool hasFormat() const
+    {
+        return layoutFormat != ElfNone;
+    }
+    bool hasXfb() const
+    {
+        return hasXfbBuffer() ||
+               hasXfbStride() ||
+               hasXfbOffset();
+    }
+    bool hasXfbBuffer() const
+    {
+        return layoutXfbBuffer != layoutXfbBufferEnd;
+    }
+    bool hasXfbStride() const
+    {
+        return layoutXfbStride != layoutXfbStrideEnd;
+    }
+    bool hasXfbOffset() const
+    {
+        return layoutXfbOffset != layoutXfbOffsetEnd;
+    }
+    bool hasAttachment() const
+    {
+        return layoutAttachment != layoutAttachmentEnd;
+    }
+    bool hasSpecConstantId() const
+    {
+        // Not the same thing as being a specialization constant, this
+        // is just whether or not it was declared with an ID.
+        return layoutSpecConstantId != layoutSpecConstantIdEnd;
+    }
+    bool isSpecConstant() const
+    {
+        // True if type is a specialization constant, whether or not it
+        // had a specialization-constant ID, and false if it is not a
+        // true front-end constant.
+        return specConstant;
+    }
+    bool isFrontEndConstant() const
+    {
+        // True if the front-end knows the final constant value.
+        // This allows front-end constant folding.
+        return storage == EvqConst && ! specConstant;
+    }
+    bool isConstant() const
+    {
+        // True if is either kind of constant; specialization or regular.
+        return isFrontEndConstant() || isSpecConstant();
+    }
+    void makeSpecConstant()
+    {
+        storage = EvqConst;
+        specConstant = true;
+    }
+    static const char* getLayoutPackingString(TLayoutPacking packing)
+    {
+        switch (packing) {
+        case ElpPacked:   return "packed";
+        case ElpShared:   return "shared";
+        case ElpStd140:   return "std140";
+        case ElpStd430:   return "std430";
+        default:          return "none";
+        }
+    }
+    static const char* getLayoutMatrixString(TLayoutMatrix m)
+    {
+        switch (m) {
+        case ElmColumnMajor: return "column_major";
+        case ElmRowMajor:    return "row_major";
+        default:             return "none";
+        }
+    }
+    static const char* getLayoutFormatString(TLayoutFormat f)
+    {
+        switch (f) {
+        case ElfRgba32f:      return "rgba32f";
+        case ElfRgba16f:      return "rgba16f";
+        case ElfRg32f:        return "rg32f";
+        case ElfRg16f:        return "rg16f";
+        case ElfR11fG11fB10f: return "r11f_g11f_b10f";
+        case ElfR32f:         return "r32f";
+        case ElfR16f:         return "r16f";
+        case ElfRgba16:       return "rgba16";
+        case ElfRgb10A2:      return "rgb10_a2";
+        case ElfRgba8:        return "rgba8";
+        case ElfRg16:         return "rg16";
+        case ElfRg8:          return "rg8";
+        case ElfR16:          return "r16";
+        case ElfR8:           return "r8";
+        case ElfRgba16Snorm:  return "rgba16_snorm";
+        case ElfRgba8Snorm:   return "rgba8_snorm";
+        case ElfRg16Snorm:    return "rg16_snorm";
+        case ElfRg8Snorm:     return "rg8_snorm";
+        case ElfR16Snorm:     return "r16_snorm";
+        case ElfR8Snorm:      return "r8_snorm";
+
+        case ElfRgba32i:      return "rgba32i";
+        case ElfRgba16i:      return "rgba16i";
+        case ElfRgba8i:       return "rgba8i";
+        case ElfRg32i:        return "rg32i";
+        case ElfRg16i:        return "rg16i";
+        case ElfRg8i:         return "rg8i";
+        case ElfR32i:         return "r32i";
+        case ElfR16i:         return "r16i";
+        case ElfR8i:          return "r8i";
+
+        case ElfRgba32ui:     return "rgba32ui";
+        case ElfRgba16ui:     return "rgba16ui";
+        case ElfRgba8ui:      return "rgba8ui";
+        case ElfRg32ui:       return "rg32ui";
+        case ElfRg16ui:       return "rg16ui";
+        case ElfRgb10a2ui:    return "rgb10_a2ui";
+        case ElfRg8ui:        return "rg8ui";
+        case ElfR32ui:        return "r32ui";
+        case ElfR16ui:        return "r16ui";
+        case ElfR8ui:         return "r8ui";
+        default:              return "none";
+        }
+    }
+    static const char* getLayoutDepthString(TLayoutDepth d)
+    {
+        switch (d) {
+        case EldAny:       return "depth_any";
+        case EldGreater:   return "depth_greater";
+        case EldLess:      return "depth_less";
+        case EldUnchanged: return "depth_unchanged";
+        default:           return "none";
+        }
+    }
+    static const char* getBlendEquationString(TBlendEquationShift e)
+    {
+        switch (e) {
+        case EBlendMultiply:      return "blend_support_multiply";
+        case EBlendScreen:        return "blend_support_screen";
+        case EBlendOverlay:       return "blend_support_overlay";
+        case EBlendDarken:        return "blend_support_darken";
+        case EBlendLighten:       return "blend_support_lighten";
+        case EBlendColordodge:    return "blend_support_colordodge";
+        case EBlendColorburn:     return "blend_support_colorburn";
+        case EBlendHardlight:     return "blend_support_hardlight";
+        case EBlendSoftlight:     return "blend_support_softlight";
+        case EBlendDifference:    return "blend_support_difference";
+        case EBlendExclusion:     return "blend_support_exclusion";
+        case EBlendHslHue:        return "blend_support_hsl_hue";
+        case EBlendHslSaturation: return "blend_support_hsl_saturation";
+        case EBlendHslColor:      return "blend_support_hsl_color";
+        case EBlendHslLuminosity: return "blend_support_hsl_luminosity";
+        case EBlendAllEquations:  return "blend_support_all_equations";
+        default:                  return "unknown";
+        }
+    }
+    static const char* getGeometryString(TLayoutGeometry geometry)
+    {
+        switch (geometry) {
+        case ElgPoints:             return "points";
+        case ElgLines:              return "lines";
+        case ElgLinesAdjacency:     return "lines_adjacency";
+        case ElgLineStrip:          return "line_strip";
+        case ElgTriangles:          return "triangles";
+        case ElgTrianglesAdjacency: return "triangles_adjacency";
+        case ElgTriangleStrip:      return "triangle_strip";
+        case ElgQuads:              return "quads";
+        case ElgIsolines:           return "isolines";
+        default:                    return "none";
+        }
+    }
+    static const char* getVertexSpacingString(TVertexSpacing spacing)
+    {
+        switch (spacing) {
+        case EvsEqual:              return "equal_spacing";
+        case EvsFractionalEven:     return "fractional_even_spacing";
+        case EvsFractionalOdd:      return "fractional_odd_spacing";
+        default:                    return "none";
+        }
+    }
+    static const char* getVertexOrderString(TVertexOrder order)
+    {
+        switch (order) {
+        case EvoCw:                 return "cw";
+        case EvoCcw:                return "ccw";
+        default:                    return "none";
+        }
+    }
+    static int mapGeometryToSize(TLayoutGeometry geometry)
+    {
+        switch (geometry) {
+        case ElgPoints:             return 1;
+        case ElgLines:              return 2;
+        case ElgLinesAdjacency:     return 4;
+        case ElgTriangles:          return 3;
+        case ElgTrianglesAdjacency: return 6;
+        default:                    return 0;
+        }
+    }
+};
+
+// Qualifiers that don't need to be keep per object.  They have shader scope, not object scope.
+// So, they will not be part of TType, TQualifier, etc.
+struct TShaderQualifiers {
+    TLayoutGeometry geometry; // geometry/tessellation shader in/out primitives
+    bool pixelCenterInteger;  // fragment shader
+    bool originUpperLeft;     // fragment shader
+    int invocations;
+    int vertices;             // both for tessellation "vertices" and geometry "max_vertices"
+    TVertexSpacing spacing;
+    TVertexOrder order;
+    bool pointMode;
+    int localSize[3];         // compute shader
+    int localSizeSpecId[3];   // compute shader specialization id for gl_WorkGroupSize
+    bool earlyFragmentTests;  // fragment input
+    TLayoutDepth layoutDepth;
+    bool blendEquation;       // true if any blend equation was specified
+
+#ifdef NV_EXTENSIONS
+    bool layoutOverrideCoverage;    // true if layout override_coverage set
+#endif
+
+    void init()
+    {
+        geometry = ElgNone;
+        originUpperLeft = false;
+        pixelCenterInteger = false;
+        invocations = TQualifier::layoutNotSet;
+        vertices = TQualifier::layoutNotSet;
+        spacing = EvsNone;
+        order = EvoNone;
+        pointMode = false;
+        localSize[0] = 1;
+        localSize[1] = 1;
+        localSize[2] = 1;
+        localSizeSpecId[0] = TQualifier::layoutNotSet;
+        localSizeSpecId[1] = TQualifier::layoutNotSet;
+        localSizeSpecId[2] = TQualifier::layoutNotSet;
+        earlyFragmentTests = false;
+        layoutDepth = EldNone;
+        blendEquation = false;
+#ifdef NV_EXTENSIONS
+        layoutOverrideCoverage = false;
+#endif
+    }
+
+    // Merge in characteristics from the 'src' qualifier.  They can override when
+    // set, but never erase when not set.
+    void merge(const TShaderQualifiers& src)
+    {
+        if (src.geometry != ElgNone)
+            geometry = src.geometry;
+        if (src.pixelCenterInteger)
+            pixelCenterInteger = src.pixelCenterInteger;
+        if (src.originUpperLeft)
+            originUpperLeft = src.originUpperLeft;
+        if (src.invocations != TQualifier::layoutNotSet)
+            invocations = src.invocations;
+        if (src.vertices != TQualifier::layoutNotSet)
+            vertices = src.vertices;
+        if (src.spacing != EvsNone)
+            spacing = src.spacing;
+        if (src.order != EvoNone)
+            order = src.order;
+        if (src.pointMode)
+            pointMode = true;
+        for (int i = 0; i < 3; ++i) {
+            if (src.localSize[i] > 1)
+                localSize[i] = src.localSize[i];
+        }
+        for (int i = 0; i < 3; ++i) {
+            if (src.localSizeSpecId[i] != TQualifier::layoutNotSet)
+                localSizeSpecId[i] = src.localSizeSpecId[i];
+        }
+        if (src.earlyFragmentTests)
+            earlyFragmentTests = true;
+        if (src.layoutDepth)
+            layoutDepth = src.layoutDepth;
+        if (src.blendEquation)
+            blendEquation = src.blendEquation;
+#ifdef NV_EXTENSIONS
+        if (src.layoutOverrideCoverage)
+            layoutOverrideCoverage = src.layoutOverrideCoverage;
+#endif
+    }
+};
+
+//
+// TPublicType is just temporarily used while parsing and not quite the same
+// information kept per node in TType.  Due to the bison 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.
+// Once enough is known about the situation, the proper information
+// moved into a TType, or the parse context, etc.
+//
+class TPublicType {
+public:
+    TBasicType basicType;
+    TSampler sampler;
+    TQualifier qualifier;
+    TShaderQualifiers shaderQualifiers;
+    int vectorSize : 4;
+    int matrixCols : 4;
+    int matrixRows : 4;
+    TArraySizes* arraySizes;
+    const TType* userDef;
+    TSourceLoc loc;
+
+    void initType(const TSourceLoc& l)
+    {
+        basicType = EbtVoid;
+        vectorSize = 1;
+        matrixRows = 0;
+        matrixCols = 0;
+        arraySizes = nullptr;
+        userDef = nullptr;
+        loc = l;
+    }
+
+    void initQualifiers(bool global = false)
+    {
+        qualifier.clear();
+        if (global)
+            qualifier.storage = EvqGlobal;
+    }
+
+    void init(const TSourceLoc& l, bool global = false)
+    {
+        initType(l);
+        sampler.clear();
+        initQualifiers(global);
+        shaderQualifiers.init();
+    }
+
+    void setVector(int s)
+    {
+        matrixRows = 0;
+        matrixCols = 0;
+        vectorSize = s;
+    }
+
+    void setMatrix(int c, int r)
+    {
+        matrixRows = r;
+        matrixCols = c;
+        vectorSize = 0;
+    }
+
+    bool isScalar() const
+    {
+        return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr;
+    }
+
+    // "Image" is a superset of "Subpass"
+    bool isImage()   const { return basicType == EbtSampler && sampler.isImage(); }
+    bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); }
+};
+
+//
+// Base class for things that have a type.
+//
+class TType {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    // for "empty" type (no args) or simple scalar/vector/matrix
+    explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
+                   bool isVector = false) :
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                qualifier.storage = q;
+                            }
+    // for explicit precision qualifier
+    TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
+          bool isVector = false) :
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                qualifier.storage = q;
+                                qualifier.precision = p;
+                                assert(p >= EpqNone && p <= EpqHigh);
+                            }
+    // for turning a TPublicType into a TType, using a shallow copy
+    explicit TType(const TPublicType& p) :
+                            basicType(p.basicType),
+                            vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
+                            arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                if (basicType == EbtSampler)
+                                    sampler = p.sampler;
+                                else
+                                    sampler.clear();
+                                qualifier = p.qualifier;
+                                if (p.userDef) {
+                                    structure = p.userDef->getWritableStruct();  // public type is short-lived; there are no sharing issues
+                                    typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+                                }
+                            }
+    // for construction of sampler types
+    TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
+        basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+        arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
+        sampler(sampler)
+    {
+        qualifier.clear();
+        qualifier.storage = q;
+    }
+    // to efficiently make a dereferenced type
+    // without ever duplicating the outer structure that will be thrown away
+    // and using only shallow copy
+    TType(const TType& type, int derefIndex, bool rowMajor = false)
+                            {
+                                if (type.isArray()) {
+                                    shallowCopy(type);
+                                    if (type.getArraySizes()->getNumDims() == 1) {
+                                        arraySizes = nullptr;
+                                    } else {
+                                        // want our own copy of the array, so we can edit it
+                                        arraySizes = new TArraySizes;
+                                        arraySizes->copyDereferenced(*type.arraySizes);
+                                    }
+                                } else if (type.basicType == EbtStruct || type.basicType == EbtBlock) {
+                                    // do a structure dereference
+                                    const TTypeList& memberList = *type.getStruct();
+                                    shallowCopy(*memberList[derefIndex].type);
+                                    return;
+                                } else {
+                                    // do a vector/matrix dereference
+                                    shallowCopy(type);
+                                    if (matrixCols > 0) {
+                                        // dereference from matrix to vector
+                                        if (rowMajor)
+                                            vectorSize = matrixCols;
+                                        else
+                                            vectorSize = matrixRows;
+                                        matrixCols = 0;
+                                        matrixRows = 0;
+                                        if (vectorSize == 1)
+                                            vector1 = true;
+                                    } else if (isVector()) {
+                                        // dereference from vector to scalar
+                                        vectorSize = 1;
+                                        vector1 = false;
+                                    }
+                                }
+                            }
+    // for making structures, ...
+    TType(TTypeList* userDef, const TString& n) :
+                            basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+                            arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                typeName = NewPoolTString(n.c_str());
+                            }
+    // For interface blocks
+    TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
+                            basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+                            qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+                            {
+                                sampler.clear();
+                                typeName = NewPoolTString(n.c_str());
+                            }
+    virtual ~TType() {}
+
+    // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
+    // This only works if that information (like a structure's list of types) does not change and
+    // the instances are sharing the same pool.
+    void shallowCopy(const TType& copyOf)
+    {
+        basicType = copyOf.basicType;
+        sampler = copyOf.sampler;
+        qualifier = copyOf.qualifier;
+        vectorSize = copyOf.vectorSize;
+        matrixCols = copyOf.matrixCols;
+        matrixRows = copyOf.matrixRows;
+        vector1 = copyOf.vector1;
+        arraySizes = copyOf.arraySizes;  // copying the pointer only, not the contents
+        structure = copyOf.structure;
+        fieldName = copyOf.fieldName;
+        typeName = copyOf.typeName;
+    }
+
+    void deepCopy(const TType& copyOf)
+    {
+        shallowCopy(copyOf);
+
+        if (copyOf.arraySizes) {
+            arraySizes = new TArraySizes;
+            *arraySizes = *copyOf.arraySizes;
+        }
+
+        if (copyOf.structure) {
+            structure = new TTypeList;
+            for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
+                TTypeLoc typeLoc;
+                typeLoc.loc = (*copyOf.structure)[i].loc;
+                typeLoc.type = new TType();
+                typeLoc.type->deepCopy(*(*copyOf.structure)[i].type);
+                structure->push_back(typeLoc);
+            }
+        }
+
+        if (copyOf.fieldName)
+            fieldName = NewPoolTString(copyOf.fieldName->c_str());
+        if (copyOf.typeName)
+            typeName = NewPoolTString(copyOf.typeName->c_str());
+    }
+
+    // Recursively make temporary
+    void makeTemporary()
+    {
+        getQualifier().makeTemporary();
+
+        if (isStruct())
+            for (unsigned int i = 0; i < structure->size(); ++i)
+                (*structure)[i].type->makeTemporary();
+    }
+
+    TType* clone() const
+    {
+        TType *newType = new TType();
+        newType->deepCopy(*this);
+
+        return newType;
+    }
+
+    void makeVector() { vector1 = true; }
+
+    // Merge type from parent, where a parentType is at the beginning of a declaration,
+    // establishing some characteristics for all subsequent names, while this type
+    // is on the individual names.
+    void mergeType(const TPublicType& parentType)
+    {
+        // arrayness is currently the only child aspect that has to be preserved
+        basicType = parentType.basicType;
+        vectorSize = parentType.vectorSize;
+        matrixCols = parentType.matrixCols;
+        matrixRows = parentType.matrixRows;
+        vector1 = false;                      // TPublicType is only GLSL which so far has no vec1
+        qualifier = parentType.qualifier;
+        sampler = parentType.sampler;
+        if (parentType.arraySizes)
+            newArraySizes(*parentType.arraySizes);
+        if (parentType.userDef) {
+            structure = parentType.userDef->getWritableStruct();
+            setTypeName(parentType.userDef->getTypeName());
+        }
+    }
+
+    virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; }
+    virtual bool hiddenMember() const { return basicType == EbtVoid; }
+
+    virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
+    virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
+    virtual const TString& getTypeName() const
+    {
+        assert(typeName);
+        return *typeName;
+    }
+
+    virtual const TString& getFieldName() const
+    {
+        assert(fieldName);
+        return *fieldName;
+    }
+
+    virtual TBasicType getBasicType() const { return basicType; }
+    virtual const TSampler& getSampler() const { return sampler; }
+
+    virtual       TQualifier& getQualifier()       { return qualifier; }
+    virtual const TQualifier& getQualifier() const { return qualifier; }
+
+    virtual int getVectorSize() const { return vectorSize; }  // returns 1 for either scalar or vector of size 1, valid for both
+    virtual int getMatrixCols() const { return matrixCols; }
+    virtual int getMatrixRows() const { return matrixRows; }
+    virtual int getOuterArraySize()  const { return arraySizes->getOuterSize(); }
+    virtual TIntermTyped*  getOuterArrayNode() const { return arraySizes->getOuterNode(); }
+    virtual int getCumulativeArraySize()  const { return arraySizes->getCumulativeSize(); }
+    virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
+    virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
+    virtual const TArraySizes* getArraySizes() const { return arraySizes; }
+    virtual       TArraySizes& getArraySizes()       { assert(arraySizes != nullptr); return *arraySizes; }
+
+    virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
+    virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
+    virtual bool isVector() const { return vectorSize > 1 || vector1; }
+    virtual bool isMatrix() const { return matrixCols ? true : false; }
+    virtual bool isArray()  const { return arraySizes != nullptr; }
+    virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; }
+    virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
+    virtual bool isRuntimeSizedArray()    const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
+    virtual bool isStruct() const { return structure != nullptr; }
+#ifdef AMD_EXTENSIONS
+    virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
+#else
+    virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; }
+#endif
+
+    virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; }
+
+    // "Image" is a superset of "Subpass"
+    virtual bool isImage() const   { return basicType == EbtSampler && getSampler().isImage(); }
+    virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
+
+    virtual bool isBuiltInInterstageIO(EShLanguage language) const
+    {
+        return isPerVertexAndBuiltIn(language) || isLooseAndBuiltIn(language);
+    }
+
+    // Return true if this is an interstage IO builtin
+    virtual bool isPerVertexAndBuiltIn(EShLanguage language) const
+    {
+        if (language == EShLangFragment)
+            return false;
+
+        // Any non-fragment stage
+        switch (getQualifier().builtIn) {
+        case EbvPosition:
+        case EbvPointSize:
+        case EbvClipDistance:
+        case EbvCullDistance:
+#ifdef NV_EXTENSIONS
+        case EbvLayer:
+        case EbvViewportMaskNV:
+        case EbvSecondaryPositionNV:
+        case EbvSecondaryViewportMaskNV:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // Return true if this is a loose builtin
+    virtual bool isLooseAndBuiltIn(EShLanguage language) const
+    {
+        if (getQualifier().builtIn == EbvNone)
+            return false;
+
+        return !isPerVertexAndBuiltIn(language);
+    }
+    
+    // Recursively checks if the type contains the given basic type
+    virtual bool containsBasicType(TBasicType checkType) const
+    {
+        if (basicType == checkType)
+            return true;
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsBasicType(checkType))
+                return true;
+        }
+        return false;
+    }
+
+    // Recursively check the structure for any arrays, needed for some error checks
+    virtual bool containsArray() const
+    {
+        if (isArray())
+            return true;
+        if (structure == nullptr)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsArray())
+                return true;
+        }
+        return false;
+    }
+
+    // Check the structure for any structures, needed for some error checks
+    virtual bool containsStructure() const
+    {
+        if (structure == nullptr)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->structure)
+                return true;
+        }
+        return false;
+    }
+
+    // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp().
+    virtual bool containsImplicitlySizedArray() const
+    {
+        if (isImplicitlySizedArray())
+            return true;
+        if (structure == nullptr)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsImplicitlySizedArray())
+                return true;
+        }
+        return false;
+    }
+
+    virtual bool containsOpaque() const
+    {
+        if (isOpaque())
+            return true;
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsOpaque())
+                return true;
+        }
+        return false;
+    }
+
+    // Recursively checks if the type contains an interstage IO builtin
+    virtual bool containsBuiltInInterstageIO(EShLanguage language) const
+    {
+        if (isBuiltInInterstageIO(language))
+            return true;
+
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsBuiltInInterstageIO(language))
+                return true;
+        }
+        return false;
+    }
+
+    virtual bool containsNonOpaque() const
+    {
+        // list all non-opaque types
+        switch (basicType) {
+        case EbtVoid:
+        case EbtFloat:
+        case EbtDouble:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+        case EbtBool:
+            return true;
+        default:
+            break;
+        }
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsNonOpaque())
+                return true;
+        }
+        return false;
+    }
+
+    virtual bool containsSpecializationSize() const
+    {
+        if (isArray() && arraySizes->containsNode())
+            return true;
+        if (! structure)
+            return false;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->containsSpecializationSize())
+                return true;
+        }
+        return false;
+    }
+
+    // Array editing methods.  Array descriptors can be shared across
+    // type instances.  This allows all uses of the same array
+    // to be updated at once.  E.g., all nodes can be explicitly sized
+    // by tracking and correcting one implicit size.  Or, all nodes
+    // can get the explicit size on a redeclaration that gives size.
+    //
+    // N.B.:  Don't share with the shared symbol tables (symbols are
+    // marked as isReadOnly().  Such symbols with arrays that will be
+    // edited need to copyUp() on first use, so that
+    // A) the edits don't effect the shared symbol table, and
+    // B) the edits are shared across all users.
+    void updateArraySizes(const TType& type)
+    {
+        // For when we may already be sharing existing array descriptors,
+        // keeping the pointers the same, just updating the contents.
+        assert(arraySizes != nullptr);
+        assert(type.arraySizes != nullptr);
+        *arraySizes = *type.arraySizes;
+    }
+    void newArraySizes(const TArraySizes& s)
+    {
+        // For setting a fresh new set of array sizes, not yet worrying about sharing.
+        arraySizes = new TArraySizes;
+        *arraySizes = s;
+    }
+    void clearArraySizes()
+    {
+        arraySizes = 0;
+    }
+    void addArrayOuterSizes(const TArraySizes& s)
+    {
+        if (arraySizes == nullptr)
+            newArraySizes(s);
+        else
+            arraySizes->addOuterSizes(s);
+    }
+    void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
+    void setImplicitArraySize(int s) { arraySizes->setImplicitSize(s); }
+
+    // Recursively make the implicit array size the explicit array size, through the type tree.
+    void adoptImplicitArraySizes()
+    {
+        if (isImplicitlySizedArray())
+            changeOuterArraySize(getImplicitArraySize());
+        if (isStruct()) {
+            for (int i = 0; i < (int)structure->size(); ++i)
+                (*structure)[i].type->adoptImplicitArraySizes();
+        }
+    }
+
+    const char* getBasicString() const
+    {
+        return TType::getBasicString(basicType);
+    }
+
+    static const char* getBasicString(TBasicType t)
+    {
+        switch (t) {
+        case EbtVoid:              return "void";
+        case EbtFloat:             return "float";
+        case EbtDouble:            return "double";
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:           return "float16_t";
+#endif
+        case EbtInt:               return "int";
+        case EbtUint:              return "uint";
+        case EbtInt64:             return "int64_t";
+        case EbtUint64:            return "uint64_t";
+        case EbtBool:              return "bool";
+        case EbtAtomicUint:        return "atomic_uint";
+        case EbtSampler:           return "sampler/image";
+        case EbtStruct:            return "structure";
+        case EbtBlock:             return "block";
+        default:                   return "unknown type";
+        }
+    }
+
+    TString getCompleteString() const
+    {
+        const int maxSize = GlslangMaxTypeLength;
+        char buf[maxSize];
+        char* p = &buf[0];
+        char* end = &buf[maxSize];
+
+        if (qualifier.hasLayout()) {
+            // To reduce noise, skip this if the only layout is an xfb_buffer
+            // with no triggering xfb_offset.
+            TQualifier noXfbBuffer = qualifier;
+            noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd;
+            if (noXfbBuffer.hasLayout()) {
+                p += snprintf(p, end - p, "layout(");
+                if (qualifier.hasAnyLocation()) {
+                    p += snprintf(p, end - p, "location=%d ", qualifier.layoutLocation);
+                    if (qualifier.hasComponent())
+                        p += snprintf(p, end - p, "component=%d ", qualifier.layoutComponent);
+                    if (qualifier.hasIndex())
+                        p += snprintf(p, end - p, "index=%d ", qualifier.layoutIndex);
+                }
+                if (qualifier.hasSet())
+                    p += snprintf(p, end - p, "set=%d ", qualifier.layoutSet);
+                if (qualifier.hasBinding())
+                    p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
+                if (qualifier.hasStream())
+                    p += snprintf(p, end - p, "stream=%d ", qualifier.layoutStream);
+                if (qualifier.hasMatrix())
+                    p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
+                if (qualifier.hasPacking())
+                    p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking));
+                if (qualifier.hasOffset())
+                    p += snprintf(p, end - p, "offset=%d ", qualifier.layoutOffset);
+                if (qualifier.hasAlign())
+                    p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
+                if (qualifier.hasFormat())
+                    p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat));
+                if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset())
+                    p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
+                if (qualifier.hasXfbOffset())
+                    p += snprintf(p, end - p, "xfb_offset=%d ", qualifier.layoutXfbOffset);
+                if (qualifier.hasXfbStride())
+                    p += snprintf(p, end - p, "xfb_stride=%d ", qualifier.layoutXfbStride);
+                if (qualifier.hasAttachment())
+                    p += snprintf(p, end - p, "input_attachment_index=%d ", qualifier.layoutAttachment);
+                if (qualifier.hasSpecConstantId())
+                    p += snprintf(p, end - p, "constant_id=%d ", qualifier.layoutSpecConstantId);
+                if (qualifier.layoutPushConstant)
+                    p += snprintf(p, end - p, "push_constant ");
+
+#ifdef NV_EXTENSIONS
+                if (qualifier.layoutPassthrough)
+                    p += snprintf(p, end - p, "passthrough ");
+                if (qualifier.layoutViewportRelative)
+                    p += snprintf(p, end - p, "layoutViewportRelative ");
+                if (qualifier.layoutSecondaryViewportRelativeOffset != -2048)
+                    p += snprintf(p, end - p, "layoutSecondaryViewportRelativeOffset=%d ", qualifier.layoutSecondaryViewportRelativeOffset);
+#endif
+
+                p += snprintf(p, end - p, ") ");
+            }
+        }
+
+        if (qualifier.invariant)
+            p += snprintf(p, end - p, "invariant ");
+        if (qualifier.noContraction)
+            p += snprintf(p, end - p, "noContraction ");
+        if (qualifier.centroid)
+            p += snprintf(p, end - p, "centroid ");
+        if (qualifier.smooth)
+            p += snprintf(p, end - p, "smooth ");
+        if (qualifier.flat)
+            p += snprintf(p, end - p, "flat ");
+        if (qualifier.nopersp)
+            p += snprintf(p, end - p, "noperspective ");
+#ifdef AMD_EXTENSIONS
+        if (qualifier.explicitInterp)
+            p += snprintf(p, end - p, "__explicitInterpAMD ");
+#endif
+        if (qualifier.patch)
+            p += snprintf(p, end - p, "patch ");
+        if (qualifier.sample)
+            p += snprintf(p, end - p, "sample ");
+        if (qualifier.coherent)
+            p += snprintf(p, end - p, "coherent ");
+        if (qualifier.volatil)
+            p += snprintf(p, end - p, "volatile ");
+        if (qualifier.restrict)
+            p += snprintf(p, end - p, "restrict ");
+        if (qualifier.readonly)
+            p += snprintf(p, end - p, "readonly ");
+        if (qualifier.writeonly)
+            p += snprintf(p, end - p, "writeonly ");
+        if (qualifier.specConstant)
+            p += snprintf(p, end - p, "specialization-constant ");
+        p += snprintf(p, end - p, "%s ", getStorageQualifierString());
+        if (isArray()) {
+            for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
+                int size = arraySizes->getDimSize(i);
+                if (size == 0)
+                    p += snprintf(p, end - p, "implicitly-sized array of ");
+                else
+                    p += snprintf(p, end - p, "%d-element array of ", arraySizes->getDimSize(i));
+            }
+        }
+        if (qualifier.precision != EpqNone)
+            p += snprintf(p, end - p, "%s ", getPrecisionQualifierString());
+        if (isMatrix())
+            p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows);
+        else if (isVector())
+            p += snprintf(p, end - p, "%d-component vector of ", vectorSize);
+
+        *p = 0;
+        TString s(buf);
+        s.append(getBasicTypeString());
+
+        if (qualifier.builtIn != EbvNone) {
+            s.append(" ");
+            s.append(getBuiltInVariableString());
+        }
+
+        // Add struct/block members
+        if (structure) {
+            s.append("{");
+            for (size_t i = 0; i < structure->size(); ++i) {
+                if (s.size() > 3 * GlslangMaxTypeLength) {
+                    // If we are getting too long, cut it short,
+                    // just need to draw the line somewhere, as there is no limit to
+                    // how large a struct/block type can get.
+                    s.append("...");
+                    break;
+                }
+                if (! (*structure)[i].type->hiddenMember()) {
+                    s.append((*structure)[i].type->getCompleteString());
+                    s.append(" ");
+                    s.append((*structure)[i].type->getFieldName());
+                    if (i < structure->size() - 1)
+                        s.append(", ");
+                }
+            }
+            s.append("}");
+        }
+
+        return s;
+    }
+
+    TString getBasicTypeString() const
+    {
+        if (basicType == EbtSampler)
+            return sampler.getString();
+        else
+            return getBasicString();
+    }
+
+    const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
+    const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
+    const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
+    const TTypeList* getStruct() const { return structure; }
+    TTypeList* getWritableStruct() const { return structure; }  // This should only be used when known to not be sharing with other threads
+
+    int computeNumComponents() const
+    {
+        int components = 0;
+
+        if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
+            for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+                components += ((*tl).type)->computeNumComponents();
+        } else if (matrixCols)
+            components = matrixCols * matrixRows;
+        else
+            components = vectorSize;
+
+        if (arraySizes != nullptr) {
+            components *= arraySizes->getCumulativeSize();
+        }
+
+        return components;
+    }
+
+    // append this type's mangled name to the passed in 'name'
+    void appendMangledName(TString& name)
+    {
+        buildMangledName(name);
+        name += ';' ;
+    }
+
+    // Do two structure types match?  They could be declared independently,
+    // in different places, but still might satisfy the definition of matching.
+    // From the spec:
+    //
+    // "Structures must have the same name, sequence of type names, and
+    //  type definitions, and member names to be considered the same type.
+    //  This rule applies recursively for nested or embedded types."
+    //
+    bool sameStructType(const TType& right) const
+    {
+        // Most commonly, they are both nullptr, or the same pointer to the same actual structure
+        if (structure == right.structure)
+            return true;
+
+        // Both being nullptr was caught above, now they both have to be structures of the same number of elements
+        if (structure == nullptr || right.structure == nullptr ||
+            structure->size() != right.structure->size())
+            return false;
+
+        // Structure names have to match
+        if (*typeName != *right.typeName)
+            return false;
+
+        // Compare the names and types of all the members, which have to match
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->getFieldName() != (*right.structure)[i].type->getFieldName())
+                return false;
+
+            if (*(*structure)[i].type != *(*right.structure)[i].type)
+                return false;
+        }
+
+        return true;
+    }
+
+    // See if two types match, in all aspects except arrayness
+    bool sameElementType(const TType& right) const
+    {
+        return basicType == right.basicType && sameElementShape(right);
+    }
+
+    // See if two type's arrayness match
+    bool sameArrayness(const TType& right) const
+    {
+        return ((arraySizes == nullptr && right.arraySizes == nullptr) ||
+                (arraySizes != nullptr && right.arraySizes != nullptr && *arraySizes == *right.arraySizes));
+    }
+
+    // See if two type's arrayness match in everything except their outer dimension
+    bool sameInnerArrayness(const TType& right) const
+    {
+        assert(arraySizes != nullptr && right.arraySizes != nullptr);
+        return arraySizes->sameInnerArrayness(*right.arraySizes);
+    }
+
+    // See if two type's elements match in all ways except basic type
+    bool sameElementShape(const TType& right) const
+    {
+        return    sampler == right.sampler    &&
+               vectorSize == right.vectorSize &&
+               matrixCols == right.matrixCols &&
+               matrixRows == right.matrixRows &&
+                  vector1 == right.vector1    &&
+               sameStructType(right);
+    }
+
+    // See if two types match in all ways (just the actual type, not qualification)
+    bool operator==(const TType& right) const
+    {
+        return sameElementType(right) && sameArrayness(right);
+    }
+
+    bool operator!=(const TType& right) const
+    {
+        return ! operator==(right);
+    }
+
+protected:
+    // Require consumer to pick between deep copy and shallow copy.
+    TType(const TType& type);
+    TType& operator=(const TType& type);
+
+    void buildMangledName(TString&);
+
+    TBasicType basicType : 8;
+    int vectorSize       : 4;  // 1 means either scalar or 1-component vector; see vector1 to disambiguate.
+    int matrixCols       : 4;
+    int matrixRows       : 4;
+    bool vector1         : 1;  // Backward-compatible tracking of a 1-component vector distinguished from a scalar.
+                               // GLSL 4.5 never has a 1-component vector; so this will always be false until such
+                               // functionality is added.
+                               // HLSL does have a 1-component vectors, so this will be true to disambiguate
+                               // from a scalar.
+    TQualifier qualifier;
+
+    TArraySizes* arraySizes;    // nullptr unless an array; can be shared across types
+    TTypeList* structure;       // nullptr unless this is a struct; can be shared across types
+    TString *fieldName;         // for structure field names
+    TString *typeName;          // for structure type name
+    TSampler sampler;
+};
+
+} // end namespace glslang
+
+#endif // _TYPES_INCLUDED_

+ 318 - 0
src/libraries/glslang/glslang/Include/arrays.h

@@ -0,0 +1,318 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Implement types for tracking GLSL arrays, arrays of arrays, etc.
+//
+
+#ifndef _ARRAYS_INCLUDED
+#define _ARRAYS_INCLUDED
+
+namespace glslang {
+
+// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
+const int UnsizedArraySize = 0;
+
+class TIntermTyped;
+extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*);
+
+// Specialization constants need both a nominal size and a node that defines
+// the specialization constant being used.  Array types are the same when their
+// size and specialization constant nodes are the same.
+struct TArraySize {
+    unsigned int size;
+    TIntermTyped* node;  // nullptr means no specialization constant node
+    bool operator==(const TArraySize& rhs) const
+    {
+        if (size != rhs.size)
+            return false;
+        if (node == nullptr || rhs.node == nullptr)
+            return node == rhs.node;
+
+        return SameSpecializationConstants(node, rhs.node);
+    }
+};
+
+//
+// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
+// It has generic-container semantics, while TArraySizes has array-of-array semantics.
+// That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy.
+//
+struct TSmallArrayVector {
+    //
+    // TODO: memory: TSmallArrayVector is intended to be smaller.
+    // Almost all arrays could be handled by two sizes each fitting
+    // in 16 bits, needing a real vector only in the cases where there
+    // are more than 3 sizes or a size needing more than 16 bits.
+    //
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TSmallArrayVector() : sizes(nullptr) { }
+    virtual ~TSmallArrayVector() { dealloc(); }
+
+    // For breaking into two non-shared copies, independently modifiable.
+    TSmallArrayVector& operator=(const TSmallArrayVector& from)
+    {
+        if (from.sizes == nullptr)
+            sizes = nullptr;
+        else {
+            alloc();
+            *sizes = *from.sizes;
+        }
+
+        return *this;
+    }
+
+    int size() const
+    {
+        if (sizes == nullptr)
+            return 0;
+        return (int)sizes->size();
+    }
+
+    unsigned int frontSize() const
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        return sizes->front().size;
+    }
+
+    TIntermTyped* frontNode() const
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        return sizes->front().node;
+    }
+
+    void changeFront(unsigned int s)
+    {
+        assert(sizes != nullptr);
+        // this should only happen for implicitly sized arrays, not specialization constants
+        assert(sizes->front().node == nullptr);
+        sizes->front().size = s;
+    }
+
+    void push_back(unsigned int e, TIntermTyped* n)
+    {
+        alloc();
+        TArraySize pair = { e, n };
+        sizes->push_back(pair);
+    }
+
+    void push_front(const TSmallArrayVector& newDims)
+    {
+        alloc();
+        sizes->insert(sizes->begin(), newDims.sizes->begin(), newDims.sizes->end());
+    }
+
+    void pop_front()
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        if (sizes->size() == 1)
+            dealloc();
+        else
+            sizes->erase(sizes->begin());
+    }
+
+    // 'this' should currently not be holding anything, and copyNonFront
+    // will make it hold a copy of all but the first element of rhs.
+    // (This would be useful for making a type that is dereferenced by
+    // one dimension.)
+    void copyNonFront(const TSmallArrayVector& rhs)
+    {
+        assert(sizes == nullptr);
+        if (rhs.size() > 1) {
+            alloc();
+            sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end());
+        }
+    }
+
+    unsigned int getDimSize(int i) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        return (*sizes)[i].size;
+    }
+
+    void setDimSize(int i, unsigned int size) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        assert((*sizes)[i].node == nullptr);
+        (*sizes)[i].size = size;
+    }
+
+    TIntermTyped* getDimNode(int i) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        return (*sizes)[i].node;
+    }
+
+    bool operator==(const TSmallArrayVector& rhs) const
+    {
+        if (sizes == nullptr && rhs.sizes == nullptr)
+            return true;
+        if (sizes == nullptr || rhs.sizes == nullptr)
+            return false;
+        return *sizes == *rhs.sizes;
+    }
+    bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
+
+protected:
+    TSmallArrayVector(const TSmallArrayVector&);
+
+    void alloc()
+    {
+        if (sizes == nullptr)
+            sizes = new TVector<TArraySize>;
+    }
+    void dealloc()
+    {
+        delete sizes;
+        sizes = nullptr;
+    }
+
+    TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
+};
+
+//
+// Represent an array, or array of arrays, to arbitrary depth.  This is not
+// done through a hierarchy of types in a type tree, rather all contiguous arrayness
+// in the type hierarchy is localized into this single cumulative object.
+//
+// The arrayness in TTtype is a pointer, so that it can be non-allocated and zero
+// for the vast majority of types that are non-array types.
+//
+// Order Policy: these are all identical:
+//  - left to right order within a contiguous set of ...[..][..][..]... in the source language
+//  - index order 0, 1, 2, ... within the 'sizes' member below
+//  - outer-most to inner-most
+//
+struct TArraySizes {
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TArraySizes() : implicitArraySize(1) { }
+
+    // For breaking into two non-shared copies, independently modifiable.
+    TArraySizes& operator=(const TArraySizes& from)
+    {
+        implicitArraySize = from.implicitArraySize;
+        sizes = from.sizes;
+
+        return *this;
+    }
+
+    // translate from array-of-array semantics to container semantics
+    int getNumDims() const { return sizes.size(); }
+    int getDimSize(int dim) const { return sizes.getDimSize(dim); }
+    TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); }
+    void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); }
+    int getOuterSize() const { return sizes.frontSize(); }
+    TIntermTyped* getOuterNode() const { return sizes.frontNode(); }
+    int getCumulativeSize() const
+    {
+        int size = 1;
+        for (int d = 0; d < sizes.size(); ++d) {
+            // this only makes sense in paths that have a known array size
+            assert(sizes.getDimSize(d) != UnsizedArraySize);
+            size *= sizes.getDimSize(d);
+        }
+        return size;
+    }
+    void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
+    void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
+    void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
+    void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); }
+    void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
+    int getImplicitSize() const { return (int)implicitArraySize; }
+    void setImplicitSize(int s) { implicitArraySize = s; }
+    bool isInnerImplicit() const
+    {
+        for (int d = 1; d < sizes.size(); ++d) {
+            if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
+                return true;
+        }
+
+        return false;
+    }
+    bool isImplicit() const { return getOuterSize() == UnsizedArraySize || isInnerImplicit(); }
+    void addOuterSizes(const TArraySizes& s) { sizes.push_front(s.sizes); }
+    void dereference() { sizes.pop_front(); }
+    void copyDereferenced(const TArraySizes& rhs)
+    {
+        assert(sizes.size() == 0);
+        if (rhs.sizes.size() > 1)
+            sizes.copyNonFront(rhs.sizes);
+    }
+
+    bool sameInnerArrayness(const TArraySizes& rhs) const
+    {
+        if (sizes.size() != rhs.sizes.size())
+            return false;
+
+        for (int d = 1; d < sizes.size(); ++d) {
+            if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) ||
+                sizes.getDimNode(d) != rhs.sizes.getDimNode(d))
+                return false;
+        }
+
+        return true;
+    }
+
+    // Returns true if any of the dimensions of the array is sized with a node
+    // instead of a front-end compile-time constant.
+    bool containsNode()
+    {
+        for (int d = 0; d < sizes.size(); ++d) {
+            if (sizes.getDimNode(d) != nullptr)
+                return true;
+        }
+
+        return false;
+    }
+
+    bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
+    bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
+
+protected:
+    TSmallArrayVector sizes;
+
+    TArraySizes(const TArraySizes&);
+
+    // for tracking maximum referenced index, before an explicit size is given
+    // applies only to the outer-most dimension
+    int implicitArraySize;
+};
+
+} // end namespace glslang
+
+#endif // _ARRAYS_INCLUDED_

+ 1253 - 0
src/libraries/glslang/glslang/Include/intermediate.h

@@ -0,0 +1,1253 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// 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
+
+#if _MSC_VER >= 1900
+    #pragma warning(disable : 4464) // relative include path contains '..'
+    #pragma warning(disable : 5026) // 'glslang::TIntermUnary': move constructor was implicitly defined as deleted
+#endif
+
+#include "../Include/Common.h"
+#include "../Include/Types.h"
+#include "../Include/ConstantUnion.h"
+
+namespace glslang {
+
+class TIntermediate;
+
+//
+// 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.
+    EOpLinkerObjects,   // for aggregate node of objects the linker may need, if not reference by the rest of the AST
+    EOpFunctionCall,
+    EOpFunction,        // For function definition
+    EOpParameters,      // an aggregate listing the parameters to a function
+
+    //
+    // Unary operators
+    //
+
+    EOpNegative,
+    EOpLogicalNot,
+    EOpVectorLogicalNot,
+    EOpBitwiseNot,
+
+    EOpPostIncrement,
+    EOpPostDecrement,
+    EOpPreIncrement,
+    EOpPreDecrement,
+
+    EOpConvIntToBool,
+    EOpConvUintToBool,
+    EOpConvFloatToBool,
+    EOpConvDoubleToBool,
+    EOpConvInt64ToBool,
+    EOpConvUint64ToBool,
+    EOpConvBoolToFloat,
+    EOpConvIntToFloat,
+    EOpConvUintToFloat,
+    EOpConvDoubleToFloat,
+    EOpConvInt64ToFloat,
+    EOpConvUint64ToFloat,
+    EOpConvUintToInt,
+    EOpConvFloatToInt,
+    EOpConvBoolToInt,
+    EOpConvDoubleToInt,
+    EOpConvInt64ToInt,
+    EOpConvUint64ToInt,
+    EOpConvIntToUint,
+    EOpConvFloatToUint,
+    EOpConvBoolToUint,
+    EOpConvDoubleToUint,
+    EOpConvInt64ToUint,
+    EOpConvUint64ToUint,
+    EOpConvIntToDouble,
+    EOpConvUintToDouble,
+    EOpConvFloatToDouble,
+    EOpConvBoolToDouble,
+    EOpConvInt64ToDouble,
+    EOpConvUint64ToDouble,
+    EOpConvBoolToInt64,
+    EOpConvIntToInt64,
+    EOpConvUintToInt64,
+    EOpConvFloatToInt64,
+    EOpConvDoubleToInt64,
+    EOpConvUint64ToInt64,
+    EOpConvBoolToUint64,
+    EOpConvIntToUint64,
+    EOpConvUintToUint64,
+    EOpConvFloatToUint64,
+    EOpConvDoubleToUint64,
+    EOpConvInt64ToUint64,
+#ifdef AMD_EXTENSIONS
+    EOpConvBoolToFloat16,
+    EOpConvIntToFloat16,
+    EOpConvUintToFloat16,
+    EOpConvFloatToFloat16,
+    EOpConvDoubleToFloat16,
+    EOpConvInt64ToFloat16,
+    EOpConvUint64ToFloat16,
+    EOpConvFloat16ToBool,
+    EOpConvFloat16ToInt,
+    EOpConvFloat16ToUint,
+    EOpConvFloat16ToFloat,
+    EOpConvFloat16ToDouble,
+    EOpConvFloat16ToInt64,
+    EOpConvFloat16ToUint64,
+#endif
+
+    //
+    // binary operations
+    //
+
+    EOpAdd,
+    EOpSub,
+    EOpMul,
+    EOpDiv,
+    EOpMod,
+    EOpRightShift,
+    EOpLeftShift,
+    EOpAnd,
+    EOpInclusiveOr,
+    EOpExclusiveOr,
+    EOpEqual,
+    EOpNotEqual,
+    EOpVectorEqual,
+    EOpVectorNotEqual,
+    EOpLessThan,
+    EOpGreaterThan,
+    EOpLessThanEqual,
+    EOpGreaterThanEqual,
+    EOpComma,
+
+    EOpVectorTimesScalar,
+    EOpVectorTimesMatrix,
+    EOpMatrixTimesVector,
+    EOpMatrixTimesScalar,
+
+    EOpLogicalOr,
+    EOpLogicalXor,
+    EOpLogicalAnd,
+
+    EOpIndexDirect,
+    EOpIndexIndirect,
+    EOpIndexDirectStruct,
+
+    EOpVectorSwizzle,
+
+    EOpMethod,
+
+    //
+    // Built-in functions 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,
+    EOpModf,
+    EOpMin,
+    EOpMax,
+    EOpClamp,
+    EOpMix,
+    EOpStep,
+    EOpSmoothStep,
+
+    EOpIsNan,
+    EOpIsInf,
+
+    EOpFma,
+
+    EOpFrexp,
+    EOpLdexp,
+
+    EOpFloatBitsToInt,
+    EOpFloatBitsToUint,
+    EOpIntBitsToFloat,
+    EOpUintBitsToFloat,
+    EOpDoubleBitsToInt64,
+    EOpDoubleBitsToUint64,
+    EOpInt64BitsToDouble,
+    EOpUint64BitsToDouble,
+    EOpPackSnorm2x16,
+    EOpUnpackSnorm2x16,
+    EOpPackUnorm2x16,
+    EOpUnpackUnorm2x16,
+    EOpPackSnorm4x8,
+    EOpUnpackSnorm4x8,
+    EOpPackUnorm4x8,
+    EOpUnpackUnorm4x8,
+    EOpPackHalf2x16,
+    EOpUnpackHalf2x16,
+    EOpPackDouble2x32,
+    EOpUnpackDouble2x32,
+    EOpPackInt2x32,
+    EOpUnpackInt2x32,
+    EOpPackUint2x32,
+    EOpUnpackUint2x32,
+#ifdef AMD_EXTENSIONS
+    EOpPackFloat2x16,
+    EOpUnpackFloat2x16,
+#endif
+
+    EOpLength,
+    EOpDistance,
+    EOpDot,
+    EOpCross,
+    EOpNormalize,
+    EOpFaceForward,
+    EOpReflect,
+    EOpRefract,
+
+#ifdef AMD_EXTENSIONS
+    EOpMin3,
+    EOpMax3,
+    EOpMid3,
+#endif
+
+    EOpDPdx,            // Fragment only
+    EOpDPdy,            // Fragment only
+    EOpFwidth,          // Fragment only
+    EOpDPdxFine,        // Fragment only
+    EOpDPdyFine,        // Fragment only
+    EOpFwidthFine,      // Fragment only
+    EOpDPdxCoarse,      // Fragment only
+    EOpDPdyCoarse,      // Fragment only
+    EOpFwidthCoarse,    // Fragment only
+
+    EOpInterpolateAtCentroid, // Fragment only
+    EOpInterpolateAtSample,   // Fragment only
+    EOpInterpolateAtOffset,   // Fragment only
+
+#ifdef AMD_EXTENSIONS
+    EOpInterpolateAtVertex,
+#endif
+
+    EOpMatrixTimesMatrix,
+    EOpOuterProduct,
+    EOpDeterminant,
+    EOpMatrixInverse,
+    EOpTranspose,
+
+    EOpFtransform,
+
+    EOpNoise,
+
+    EOpEmitVertex,           // geometry only
+    EOpEndPrimitive,         // geometry only
+    EOpEmitStreamVertex,     // geometry only
+    EOpEndStreamPrimitive,   // geometry only
+
+    EOpBarrier,
+    EOpMemoryBarrier,
+    EOpMemoryBarrierAtomicCounter,
+    EOpMemoryBarrierBuffer,
+    EOpMemoryBarrierImage,
+    EOpMemoryBarrierShared,  // compute only
+    EOpGroupMemoryBarrier,   // compute only
+
+    EOpBallot,
+    EOpReadInvocation,
+    EOpReadFirstInvocation,
+
+    EOpAnyInvocation,
+    EOpAllInvocations,
+    EOpAllInvocationsEqual,
+
+#ifdef AMD_EXTENSIONS
+    EOpMinInvocations,
+    EOpMaxInvocations,
+    EOpAddInvocations,
+    EOpMinInvocationsNonUniform,
+    EOpMaxInvocationsNonUniform,
+    EOpAddInvocationsNonUniform,
+    EOpMinInvocationsInclusiveScan,
+    EOpMaxInvocationsInclusiveScan,
+    EOpAddInvocationsInclusiveScan,
+    EOpMinInvocationsInclusiveScanNonUniform,
+    EOpMaxInvocationsInclusiveScanNonUniform,
+    EOpAddInvocationsInclusiveScanNonUniform,
+    EOpMinInvocationsExclusiveScan,
+    EOpMaxInvocationsExclusiveScan,
+    EOpAddInvocationsExclusiveScan,
+    EOpMinInvocationsExclusiveScanNonUniform,
+    EOpMaxInvocationsExclusiveScanNonUniform,
+    EOpAddInvocationsExclusiveScanNonUniform,
+    EOpSwizzleInvocations,
+    EOpSwizzleInvocationsMasked,
+    EOpWriteInvocation,
+    EOpMbcnt,
+
+    EOpCubeFaceIndex,
+    EOpCubeFaceCoord,
+    EOpTime,
+#endif
+
+    EOpAtomicAdd,
+    EOpAtomicMin,
+    EOpAtomicMax,
+    EOpAtomicAnd,
+    EOpAtomicOr,
+    EOpAtomicXor,
+    EOpAtomicExchange,
+    EOpAtomicCompSwap,
+
+    EOpAtomicCounterIncrement,
+    EOpAtomicCounterDecrement,
+    EOpAtomicCounter,
+
+    EOpAny,
+    EOpAll,
+
+    //
+    // Branch
+    //
+
+    EOpKill,            // Fragment only
+    EOpReturn,
+    EOpBreak,
+    EOpContinue,
+    EOpCase,
+    EOpDefault,
+
+    //
+    // Constructors
+    //
+
+    EOpConstructGuardStart,
+    EOpConstructInt,          // these first scalar forms also identify what implicit conversion is needed
+    EOpConstructUint,
+    EOpConstructInt64,
+    EOpConstructUint64,
+    EOpConstructBool,
+    EOpConstructFloat,
+    EOpConstructDouble,
+    EOpConstructVec2,
+    EOpConstructVec3,
+    EOpConstructVec4,
+    EOpConstructDVec2,
+    EOpConstructDVec3,
+    EOpConstructDVec4,
+    EOpConstructBVec2,
+    EOpConstructBVec3,
+    EOpConstructBVec4,
+    EOpConstructIVec2,
+    EOpConstructIVec3,
+    EOpConstructIVec4,
+    EOpConstructUVec2,
+    EOpConstructUVec3,
+    EOpConstructUVec4,
+    EOpConstructI64Vec2,
+    EOpConstructI64Vec3,
+    EOpConstructI64Vec4,
+    EOpConstructU64Vec2,
+    EOpConstructU64Vec3,
+    EOpConstructU64Vec4,
+    EOpConstructMat2x2,
+    EOpConstructMat2x3,
+    EOpConstructMat2x4,
+    EOpConstructMat3x2,
+    EOpConstructMat3x3,
+    EOpConstructMat3x4,
+    EOpConstructMat4x2,
+    EOpConstructMat4x3,
+    EOpConstructMat4x4,
+    EOpConstructDMat2x2,
+    EOpConstructDMat2x3,
+    EOpConstructDMat2x4,
+    EOpConstructDMat3x2,
+    EOpConstructDMat3x3,
+    EOpConstructDMat3x4,
+    EOpConstructDMat4x2,
+    EOpConstructDMat4x3,
+    EOpConstructDMat4x4,
+#ifdef AMD_EXTENSIONS
+    EOpConstructFloat16,
+    EOpConstructF16Vec2,
+    EOpConstructF16Vec3,
+    EOpConstructF16Vec4,
+    EOpConstructF16Mat2x2,
+    EOpConstructF16Mat2x3,
+    EOpConstructF16Mat2x4,
+    EOpConstructF16Mat3x2,
+    EOpConstructF16Mat3x3,
+    EOpConstructF16Mat3x4,
+    EOpConstructF16Mat4x2,
+    EOpConstructF16Mat4x3,
+    EOpConstructF16Mat4x4,
+#endif
+    EOpConstructStruct,
+    EOpConstructTextureSampler,
+    EOpConstructGuardEnd,
+
+    //
+    // moves
+    //
+
+    EOpAssign,
+    EOpAddAssign,
+    EOpSubAssign,
+    EOpMulAssign,
+    EOpVectorTimesMatrixAssign,
+    EOpVectorTimesScalarAssign,
+    EOpMatrixTimesScalarAssign,
+    EOpMatrixTimesMatrixAssign,
+    EOpDivAssign,
+    EOpModAssign,
+    EOpAndAssign,
+    EOpInclusiveOrAssign,
+    EOpExclusiveOrAssign,
+    EOpLeftShiftAssign,
+    EOpRightShiftAssign,
+
+    //
+    // Array operators
+    //
+
+    EOpArrayLength,      // "Array" distinguishes from length(v) built-in function, but it applies to vectors and matrices as well.
+
+    //
+    // Image operations
+    //
+
+    EOpImageGuardBegin,
+
+    EOpImageQuerySize,
+    EOpImageQuerySamples,
+    EOpImageLoad,
+    EOpImageStore,
+    EOpImageAtomicAdd,
+    EOpImageAtomicMin,
+    EOpImageAtomicMax,
+    EOpImageAtomicAnd,
+    EOpImageAtomicOr,
+    EOpImageAtomicXor,
+    EOpImageAtomicExchange,
+    EOpImageAtomicCompSwap,
+
+    EOpSubpassLoad,
+    EOpSubpassLoadMS,
+    EOpSparseImageLoad,
+
+    EOpImageGuardEnd,
+
+    //
+    // Texture operations
+    //
+
+    EOpTextureGuardBegin,
+
+    EOpTextureQuerySize,
+    EOpTextureQueryLod,
+    EOpTextureQueryLevels,
+    EOpTextureQuerySamples,
+
+    EOpSamplingGuardBegin,
+
+    EOpTexture,
+    EOpTextureProj,
+    EOpTextureLod,
+    EOpTextureOffset,
+    EOpTextureFetch,
+    EOpTextureFetchOffset,
+    EOpTextureProjOffset,
+    EOpTextureLodOffset,
+    EOpTextureProjLod,
+    EOpTextureProjLodOffset,
+    EOpTextureGrad,
+    EOpTextureGradOffset,
+    EOpTextureProjGrad,
+    EOpTextureProjGradOffset,
+    EOpTextureGather,
+    EOpTextureGatherOffset,
+    EOpTextureGatherOffsets,
+    EOpTextureClamp,
+    EOpTextureOffsetClamp,
+    EOpTextureGradClamp,
+    EOpTextureGradOffsetClamp,
+
+    EOpSparseTextureGuardBegin,
+
+    EOpSparseTexture,
+    EOpSparseTextureLod,
+    EOpSparseTextureOffset,
+    EOpSparseTextureFetch,
+    EOpSparseTextureFetchOffset,
+    EOpSparseTextureLodOffset,
+    EOpSparseTextureGrad,
+    EOpSparseTextureGradOffset,
+    EOpSparseTextureGather,
+    EOpSparseTextureGatherOffset,
+    EOpSparseTextureGatherOffsets,
+    EOpSparseTexelsResident,
+    EOpSparseTextureClamp,
+    EOpSparseTextureOffsetClamp,
+    EOpSparseTextureGradClamp,
+    EOpSparseTextureGradOffsetClamp,
+
+    EOpSparseTextureGuardEnd,
+    EOpSamplingGuardEnd,
+    EOpTextureGuardEnd,
+
+    //
+    // Integer operations
+    //
+
+    EOpAddCarry,
+    EOpSubBorrow,
+    EOpUMulExtended,
+    EOpIMulExtended,
+    EOpBitfieldExtract,
+    EOpBitfieldInsert,
+    EOpBitFieldReverse,
+    EOpBitCount,
+    EOpFindLSB,
+    EOpFindMSB,
+
+    //
+    // HLSL operations
+    //
+
+    EOpClip,                // discard if input value < 0
+    EOpIsFinite,
+    EOpLog10,               // base 10 log
+    EOpRcp,                 // 1/x
+    EOpSaturate,            // clamp from 0 to 1
+    EOpSinCos,              // sin and cos in out parameters
+    EOpGenMul,              // mul(x,y) on any of mat/vec/scalars
+    EOpDst,                 // x = 1, y=src0.y * src1.y, z=src0.z, w=src1.w
+    EOpInterlockedAdd,      // atomic ops, but uses [optional] out arg instead of return
+    EOpInterlockedAnd,      // ...
+    EOpInterlockedCompareExchange, // ...
+    EOpInterlockedCompareStore,    // ...
+    EOpInterlockedExchange, // ...
+    EOpInterlockedMax,      // ...
+    EOpInterlockedMin,      // ...
+    EOpInterlockedOr,       // ...
+    EOpInterlockedXor,      // ...
+    EOpAllMemoryBarrierWithGroupSync,    // memory barriers without non-hlsl AST equivalents
+    EOpGroupMemoryBarrierWithGroupSync,  // ...
+    EOpWorkgroupMemoryBarrier,           // ...
+    EOpWorkgroupMemoryBarrierWithGroupSync, // ...
+    EOpEvaluateAttributeSnapped,         // InterpolateAtOffset with int position on 16x16 grid
+    EOpF32tof16,                         // HLSL conversion: half of a PackHalf2x16
+    EOpF16tof32,                         // HLSL conversion: half of an UnpackHalf2x16
+    EOpLit,                              // HLSL lighting coefficient vector
+    EOpTextureBias,                      // HLSL texture bias: will be lowered to EOpTexture
+    EOpAsDouble,                         // slightly different from EOpUint64BitsToDouble
+    EOpD3DCOLORtoUBYTE4,                 // convert and swizzle 4-component color to UBYTE4 range
+
+    EOpMethodSample,                     // Texture object methods.  These are translated to existing
+    EOpMethodSampleBias,                 // AST methods, and exist to represent HLSL semantics until that
+    EOpMethodSampleCmp,                  // translation is performed.  See HlslParseContext::decomposeSampleMethods().
+    EOpMethodSampleCmpLevelZero,         // ...
+    EOpMethodSampleGrad,                 // ...
+    EOpMethodSampleLevel,                // ...
+    EOpMethodLoad,                       // ...
+    EOpMethodGetDimensions,              // ...
+    EOpMethodGetSamplePosition,          // ...
+    EOpMethodGather,                     // ...
+    EOpMethodCalculateLevelOfDetail,     // ...
+    EOpMethodCalculateLevelOfDetailUnclamped,     // ...
+
+    // SM5 texture methods
+    EOpMethodGatherRed,                  // These are covered under the above EOpMethodSample comment about
+    EOpMethodGatherGreen,                // translation to existing AST opcodes.  They exist temporarily
+    EOpMethodGatherBlue,                 // because HLSL arguments are slightly different.
+    EOpMethodGatherAlpha,                // ...
+    EOpMethodGatherCmp,                  // ...
+    EOpMethodGatherCmpRed,               // ...
+    EOpMethodGatherCmpGreen,             // ...
+    EOpMethodGatherCmpBlue,              // ...
+    EOpMethodGatherCmpAlpha,             // ...
+
+    // geometry methods
+    EOpMethodAppend,                     // Geometry shader methods
+    EOpMethodRestartStrip,               // ...
+
+    // matrix
+    EOpMatrixSwizzle,                    // select multiple matrix components (non-column)
+};
+
+class TIntermTraverser;
+class TIntermOperator;
+class TIntermAggregate;
+class TIntermUnary;
+class TIntermBinary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermSwitch;
+class TIntermBranch;
+class TIntermTyped;
+class TIntermMethod;
+class TIntermSymbol;
+
+} // end namespace glslang
+
+//
+// Base class for the tree nodes
+//
+// (Put outside the glslang namespace, as it's used as part of the external interface.)
+//
+class TIntermNode {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(glslang::GetThreadPoolAllocator())
+
+    TIntermNode() { loc.init(); }
+    virtual const glslang::TSourceLoc& getLoc() const { return loc; }
+    virtual void setLoc(const glslang::TSourceLoc& l) { loc = l; }
+    virtual void traverse(glslang::TIntermTraverser*) = 0;
+    virtual       glslang::TIntermTyped*         getAsTyped()               { return 0; }
+    virtual       glslang::TIntermOperator*      getAsOperator()            { return 0; }
+    virtual       glslang::TIntermConstantUnion* getAsConstantUnion()       { return 0; }
+    virtual       glslang::TIntermAggregate*     getAsAggregate()           { return 0; }
+    virtual       glslang::TIntermUnary*         getAsUnaryNode()           { return 0; }
+    virtual       glslang::TIntermBinary*        getAsBinaryNode()          { return 0; }
+    virtual       glslang::TIntermSelection*     getAsSelectionNode()       { return 0; }
+    virtual       glslang::TIntermSwitch*        getAsSwitchNode()          { return 0; }
+    virtual       glslang::TIntermMethod*        getAsMethodNode()          { return 0; }
+    virtual       glslang::TIntermSymbol*        getAsSymbolNode()          { return 0; }
+    virtual       glslang::TIntermBranch*        getAsBranchNode()          { return 0; }
+
+    virtual const glslang::TIntermTyped*         getAsTyped()         const { return 0; }
+    virtual const glslang::TIntermOperator*      getAsOperator()      const { return 0; }
+    virtual const glslang::TIntermConstantUnion* getAsConstantUnion() const { return 0; }
+    virtual const glslang::TIntermAggregate*     getAsAggregate()     const { return 0; }
+    virtual const glslang::TIntermUnary*         getAsUnaryNode()     const { return 0; }
+    virtual const glslang::TIntermBinary*        getAsBinaryNode()    const { return 0; }
+    virtual const glslang::TIntermSelection*     getAsSelectionNode() const { return 0; }
+    virtual const glslang::TIntermSwitch*        getAsSwitchNode()    const { return 0; }
+    virtual const glslang::TIntermMethod*        getAsMethodNode()    const { return 0; }
+    virtual const glslang::TIntermSymbol*        getAsSymbolNode()    const { return 0; }
+    virtual const glslang::TIntermBranch*        getAsBranchNode()    const { return 0; }
+    virtual ~TIntermNode() { }
+
+protected:
+    TIntermNode(const TIntermNode&);
+    TIntermNode& operator=(const TIntermNode&);
+    glslang::TSourceLoc loc;
+};
+
+namespace glslang {
+
+//
+// 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.shallowCopy(t); }
+    TIntermTyped(TBasicType basicType) { TType bt(basicType); type.shallowCopy(bt); }
+    virtual       TIntermTyped* getAsTyped()       { return this; }
+    virtual const TIntermTyped* getAsTyped() const { return this; }
+    virtual void setType(const TType& t) { type.shallowCopy(t); }
+    virtual const TType& getType() const { return type; }
+    virtual TType& getWritableType() { return type; }
+
+    virtual TBasicType getBasicType() const { return type.getBasicType(); }
+    virtual TQualifier& getQualifier() { return type.getQualifier(); }
+    virtual const TQualifier& getQualifier() const { return type.getQualifier(); }
+    virtual void propagatePrecision(TPrecisionQualifier);
+    virtual int getVectorSize() const { return type.getVectorSize(); }
+    virtual int getMatrixCols() const { return type.getMatrixCols(); }
+    virtual int getMatrixRows() const { return type.getMatrixRows(); }
+    virtual bool isMatrix() const { return type.isMatrix(); }
+    virtual bool isArray()  const { return type.isArray(); }
+    virtual bool isVector() const { return type.isVector(); }
+    virtual bool isScalar() const { return type.isScalar(); }
+    virtual bool isStruct() const { return type.isStruct(); }
+    TString getCompleteString() const { return type.getCompleteString(); }
+
+protected:
+    TIntermTyped& operator=(const TIntermTyped&);
+    TType type;
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+class TIntermLoop : public TIntermNode {
+public:
+    TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) :
+        body(aBody),
+        test(aTest),
+        terminal(aTerminal),
+        first(testFirst) { }
+    virtual void traverse(TIntermTraverser*);
+    TIntermNode*  getBody() const { return body; }
+    TIntermTyped* getTest() const { return test; }
+    TIntermTyped* getTerminal() const { return terminal; }
+    bool testFirst() const { return first; }
+protected:
+    TIntermNode* body;       // code to loop over
+    TIntermTyped* test;      // exit condition associated with loop, could be 0 for 'for' loops
+    TIntermTyped* terminal;  // exists for for-loops
+    bool first;              // true for while and for, not for do-while
+};
+
+//
+// Handle case, break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+    TIntermBranch(TOperator op, TIntermTyped* e) :
+        flowOp(op),
+        expression(e) { }
+    virtual       TIntermBranch* getAsBranchNode()       { return this; }
+    virtual const TIntermBranch* getAsBranchNode() const { return this; }
+    virtual void traverse(TIntermTraverser*);
+    TOperator getFlowOp() const { return flowOp; }
+    TIntermTyped* getExpression() const { return expression; }
+protected:
+    TOperator flowOp;
+    TIntermTyped* expression;
+};
+
+//
+// Represent method names before seeing their calling signature
+// or resolving them to operations.  Just an expression as the base object
+// and a textural name.
+//
+class TIntermMethod : public TIntermTyped {
+public:
+    TIntermMethod(TIntermTyped* o, const TType& t, const TString& m) : TIntermTyped(t), object(o), method(m) { }
+    virtual       TIntermMethod* getAsMethodNode()       { return this; }
+    virtual const TIntermMethod* getAsMethodNode() const { return this; }
+    virtual const TString& getMethodName() const { return method; }
+    virtual TIntermTyped* getObject() const { return object; }
+    virtual void traverse(TIntermTraverser*);
+protected:
+    TIntermTyped* object;
+    TString method;
+};
+
+//
+// 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 pool allocator of sym. If sym comes from
+    // per process threadPoolAllocator, then it causes increased memory usage per compile
+    // it is essential to use "symbol = sym" to assign to symbol
+    TIntermSymbol(int i, const TString& n, const TType& t)
+        : TIntermTyped(t), id(i), constSubtree(nullptr)
+          { name = n; }
+    virtual int getId() const { return id; }
+    virtual const TString& getName() const { return name; }
+    virtual void traverse(TIntermTraverser*);
+    virtual       TIntermSymbol* getAsSymbolNode()       { return this; }
+    virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
+    void setConstArray(const TConstUnionArray& c) { constArray = c; }
+    const TConstUnionArray& getConstArray() const { return constArray; }
+    void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
+    TIntermTyped* getConstSubtree() const { return constSubtree; }
+
+protected:
+    int id;                      // the unique id of the symbol this node represents
+    TString name;                // the name of the symbol this node represents
+    TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value
+    TIntermTyped* constSubtree;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+    TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), constArray(ua), literal(false) { }
+    const TConstUnionArray& getConstArray() const { return constArray; }
+    virtual       TIntermConstantUnion* getAsConstantUnion()       { return this; }
+    virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
+    virtual void traverse(TIntermTraverser*);
+    virtual TIntermTyped* fold(TOperator, const TIntermTyped*) const;
+    virtual TIntermTyped* fold(TOperator, const TType&) const;
+    void setLiteral() { literal = true; }
+    void setExpression() { literal = false; }
+    bool isLiteral() const { return literal; }
+
+protected:
+    TIntermConstantUnion& operator=(const TIntermConstantUnion&);
+
+    const TConstUnionArray constArray;
+    bool literal;  // true if node represents a literal in the source code
+};
+
+// Represent the independent aspects of a texturing TOperator
+struct TCrackedTextureOp {
+    bool query;
+    bool proj;
+    bool lod;
+    bool fetch;
+    bool offset;
+    bool offsets;
+    bool gather;
+    bool grad;
+    bool subpass;
+    bool lodClamp;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+    virtual       TIntermOperator* getAsOperator()       { return this; }
+    virtual const TIntermOperator* getAsOperator() const { return this; }
+    TOperator getOp() const { return op; }
+    void setOp(TOperator newOp) { op = newOp; }
+    bool modifiesState() const;
+    bool isConstructor() const;
+    bool isTexture()  const { return op > EOpTextureGuardBegin  && op < EOpTextureGuardEnd; }
+    bool isSampling() const { return op > EOpSamplingGuardBegin && op < EOpSamplingGuardEnd; }
+    bool isImage()    const { return op > EOpImageGuardBegin    && op < EOpImageGuardEnd; }
+    bool isSparseTexture() const { return op > EOpSparseTextureGuardBegin && op < EOpSparseTextureGuardEnd; }
+    bool isSparseImage()   const { return op == EOpSparseImageLoad; }
+
+    void setOperationPrecision(TPrecisionQualifier p) { operationPrecision = p; }
+    TPrecisionQualifier getOperationPrecision() const { return operationPrecision != EpqNone ?
+                                                                                     operationPrecision :
+                                                                                     type.getQualifier().precision; }
+    TString getCompleteString() const
+    {
+        TString cs = type.getCompleteString();
+        if (getOperationPrecision() != type.getQualifier().precision) {
+            cs += ", operation at ";
+            cs += GetPrecisionQualifierString(getOperationPrecision());
+        }
+
+        return cs;
+    }
+
+    // Crack the op into the individual dimensions of texturing operation.
+    void crackTexture(TSampler sampler, TCrackedTextureOp& cracked) const
+    {
+        cracked.query = false;
+        cracked.proj = false;
+        cracked.lod = false;
+        cracked.fetch = false;
+        cracked.offset = false;
+        cracked.offsets = false;
+        cracked.gather = false;
+        cracked.grad = false;
+        cracked.subpass = false;
+        cracked.lodClamp = false;
+
+        switch (op) {
+        case EOpImageQuerySize:
+        case EOpImageQuerySamples:
+        case EOpTextureQuerySize:
+        case EOpTextureQueryLod:
+        case EOpTextureQueryLevels:
+        case EOpTextureQuerySamples:
+        case EOpSparseTexelsResident:
+            cracked.query = true;
+            break;
+        case EOpTexture:
+        case EOpSparseTexture:
+            break;
+        case EOpTextureClamp:
+        case EOpSparseTextureClamp:
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureProj:
+            cracked.proj = true;
+            break;
+        case EOpTextureLod:
+        case EOpSparseTextureLod:
+            cracked.lod = true;
+            break;
+        case EOpTextureOffset:
+        case EOpSparseTextureOffset:
+            cracked.offset = true;
+            break;
+        case EOpTextureOffsetClamp:
+        case EOpSparseTextureOffsetClamp:
+            cracked.offset = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureFetch:
+        case EOpSparseTextureFetch:
+            cracked.fetch = true;
+            if (sampler.dim == Esd1D || (sampler.dim == Esd2D && ! sampler.ms) || sampler.dim == Esd3D)
+                cracked.lod = true;
+            break;
+        case EOpTextureFetchOffset:
+        case EOpSparseTextureFetchOffset:
+            cracked.fetch = true;
+            cracked.offset = true;
+            if (sampler.dim == Esd1D || (sampler.dim == Esd2D && ! sampler.ms) || sampler.dim == Esd3D)
+                cracked.lod = true;
+            break;
+        case EOpTextureProjOffset:
+            cracked.offset = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureLodOffset:
+        case EOpSparseTextureLodOffset:
+            cracked.offset = true;
+            cracked.lod = true;
+            break;
+        case EOpTextureProjLod:
+            cracked.lod = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureProjLodOffset:
+            cracked.offset = true;
+            cracked.lod = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureGrad:
+        case EOpSparseTextureGrad:
+            cracked.grad = true;
+            break;
+        case EOpTextureGradClamp:
+        case EOpSparseTextureGradClamp:
+            cracked.grad = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureGradOffset:
+        case EOpSparseTextureGradOffset:
+            cracked.grad = true;
+            cracked.offset = true;
+            break;
+        case EOpTextureProjGrad:
+            cracked.grad = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureProjGradOffset:
+            cracked.grad = true;
+            cracked.offset = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureGradOffsetClamp:
+        case EOpSparseTextureGradOffsetClamp:
+            cracked.grad = true;
+            cracked.offset = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureGather:
+        case EOpSparseTextureGather:
+            cracked.gather = true;
+            break;
+        case EOpTextureGatherOffset:
+        case EOpSparseTextureGatherOffset:
+            cracked.gather = true;
+            cracked.offset = true;
+            break;
+        case EOpTextureGatherOffsets:
+        case EOpSparseTextureGatherOffsets:
+            cracked.gather = true;
+            cracked.offsets = true;
+            break;
+        case EOpSubpassLoad:
+        case EOpSubpassLoadMS:
+            cracked.subpass = true;
+            break;
+        default:
+            break;
+        }
+    }
+
+protected:
+    TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o), operationPrecision(EpqNone) {}
+    TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o), operationPrecision(EpqNone) {}
+    TOperator op;
+    // The result precision is in the inherited TType, and is usually meant to be both
+    // the operation precision and the result precision. However, some more complex things,
+    // like built-in function calls, distinguish between the two, in which case non-EqpNone
+    // 'operationPrecision' overrides the result precision as far as operation precision
+    // is concerned.
+    TPrecisionQualifier operationPrecision;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+    TIntermBinary(TOperator o) : TIntermOperator(o) {}
+    virtual void traverse(TIntermTraverser*);
+    virtual void setLeft(TIntermTyped* n) { left = n; }
+    virtual void setRight(TIntermTyped* n) { right = n; }
+    virtual TIntermTyped* getLeft() const { return left; }
+    virtual TIntermTyped* getRight() const { return right; }
+    virtual       TIntermBinary* getAsBinaryNode()       { return this; }
+    virtual const TIntermBinary* getAsBinaryNode() const { return this; }
+    virtual void updatePrecision();
+protected:
+    TIntermTyped* left;
+    TIntermTyped* right;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+    TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {}
+    TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {}
+    virtual void traverse(TIntermTraverser*);
+    virtual void setOperand(TIntermTyped* o) { operand = o; }
+    virtual       TIntermTyped* getOperand() { return operand; }
+    virtual const TIntermTyped* getOperand() const { return operand; }
+    virtual       TIntermUnary* getAsUnaryNode()       { return this; }
+    virtual const TIntermUnary* getAsUnaryNode() const { return this; }
+    virtual void updatePrecision();
+protected:
+    TIntermTyped* operand;
+};
+
+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), pragmaTable(0) { }
+    TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { }
+    ~TIntermAggregate() { delete pragmaTable; }
+    virtual       TIntermAggregate* getAsAggregate()       { return this; }
+    virtual const TIntermAggregate* getAsAggregate() const { return this; }
+    virtual void setOperator(TOperator o) { op = o; }
+    virtual       TIntermSequence& getSequence()       { return sequence; }
+    virtual const TIntermSequence& getSequence() const { return sequence; }
+    virtual void setName(const TString& n) { name = n; }
+    virtual const TString& getName() const { return name; }
+    virtual void traverse(TIntermTraverser*);
+    virtual void setUserDefined() { userDefined = true; }
+    virtual bool isUserDefined() { return userDefined; }
+    virtual TQualifierList& getQualifierList() { return qualifier; }
+    virtual const TQualifierList& getQualifierList() const { return qualifier; }
+    void setOptimize(bool o) { optimize = o; }
+    void setDebug(bool d) { debug = d; }
+    bool getOptimize() const { return optimize; }
+    bool getDebug() const { return debug; }
+    void addToPragmaTable(const TPragmaTable& pTable);
+    const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
+protected:
+    TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+    TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+    TIntermSequence sequence;
+    TQualifierList qualifier;
+    TString name;
+    bool userDefined; // used for user defined function names
+    bool optimize;
+    bool debug;
+    TPragmaTable* pragmaTable;
+};
+
+//
+// For if tests.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+    TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+        TIntermTyped(EbtVoid), 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 TIntermTyped* getCondition() const { return condition; }
+    virtual TIntermNode* getTrueBlock() const { return trueBlock; }
+    virtual TIntermNode* getFalseBlock() const { return falseBlock; }
+    virtual       TIntermSelection* getAsSelectionNode()       { return this; }
+    virtual const TIntermSelection* getAsSelectionNode() const { return this; }
+protected:
+    TIntermTyped* condition;
+    TIntermNode* trueBlock;
+    TIntermNode* falseBlock;
+};
+
+//
+// For switch statements.  Designed use is that a switch will have sequence of nodes
+// that are either case/default nodes or a *single* node that represents all the code
+// in between (if any) consecutive case/defaults.  So, a traversal need only deal with
+// 0 or 1 nodes per case/default statement.
+//
+class TIntermSwitch : public TIntermNode {
+public:
+    TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { }
+    virtual void traverse(TIntermTraverser*);
+    virtual TIntermNode* getCondition() const { return condition; }
+    virtual TIntermAggregate* getBody() const { return body; }
+    virtual       TIntermSwitch* getAsSwitchNode()       { return this; }
+    virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
+protected:
+    TIntermTyped* condition;
+    TIntermAggregate* body;
+};
+
+enum TVisit
+{
+    EvPreVisit,
+    EvInVisit,
+    EvPostVisit
+};
+
+//
+// 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.
+//
+// Explicitly set postVisit to true if you want post visiting, otherwise,
+// filled in methods will only be called at pre-visit time (before processing
+// the subtree).  Similarly for inVisit for in-order visiting of nodes with
+// multiple children.
+//
+// If you only want post-visits, explicitly turn off preVisit (and inVisit)
+// and turn on postVisit.
+//
+// In general, for the visit*() methods, return true from interior nodes
+// to have the traversal continue on to children.
+//
+// If you process children yourself, or don't want them processed, return false.
+//
+class TIntermTraverser {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(glslang::GetThreadPoolAllocator())
+    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(TVisit, TIntermBinary*)       { return true; }
+    virtual bool visitUnary(TVisit, TIntermUnary*)         { return true; }
+    virtual bool visitSelection(TVisit, TIntermSelection*) { return true; }
+    virtual bool visitAggregate(TVisit, TIntermAggregate*) { return true; }
+    virtual bool visitLoop(TVisit, TIntermLoop*)           { return true; }
+    virtual bool visitBranch(TVisit, TIntermBranch*)       { return true; }
+    virtual bool visitSwitch(TVisit, TIntermSwitch*)       { 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();
+    }
+
+    const bool preVisit;
+    const bool inVisit;
+    const bool postVisit;
+    const bool rightToLeft;
+
+protected:
+    TIntermTraverser& operator=(TIntermTraverser&);
+
+    int depth;
+    int maxDepth;
+
+    // All the nodes from root to the current node's parent during traversing.
+    TVector<TIntermNode *> path;
+};
+
+// KHR_vulkan_glsl says "Two arrays sized with specialization constants are the same type only if
+// sized with the same symbol, involving no operations"
+inline bool SameSpecializationConstants(TIntermTyped* node1, TIntermTyped* node2)
+{
+    return node1->getAsSymbolNode() && node2->getAsSymbolNode() &&
+           node1->getAsSymbolNode()->getId() == node2->getAsSymbolNode()->getId();
+}
+
+} // end namespace glslang
+
+#endif // __INTERMEDIATE_H

+ 6 - 0
src/libraries/glslang/glslang/Include/revision.h

@@ -0,0 +1,6 @@
+// This header is generated by the make-revision script.
+// For the version, it uses the latest git tag followed by the number of commits.
+// For the date, it uses the current date (when then script is run).
+
+#define GLSLANG_REVISION "Overload400-PrecQual.1773"
+#define GLSLANG_DATE "19-Jan-2017"

+ 995 - 0
src/libraries/glslang/glslang/MachineIndependent/Constant.cpp

@@ -0,0 +1,995 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "localintermediate.h"
+#include <cmath>
+#include <cfloat>
+#include <cstdlib>
+
+namespace {
+
+using namespace glslang;
+
+typedef union {
+    double d;
+    int i[2];
+} DoubleIntUnion;
+
+// Some helper functions
+
+bool isNan(double x)
+{
+    DoubleIntUnion u;
+    // tough to find a platform independent library function, do it directly
+    u.d = x;
+    int bitPatternL = u.i[0];
+    int bitPatternH = u.i[1];
+    return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
+           ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
+}
+
+bool isInf(double x)
+{
+    DoubleIntUnion u;
+    // tough to find a platform independent library function, do it directly
+    u.d = x;
+    int bitPatternL = u.i[0];
+    int bitPatternH = u.i[1];
+    return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
+           (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
+}
+
+const double pi = 3.1415926535897932384626433832795;
+
+} // end anonymous namespace
+
+
+namespace glslang {
+
+//
+// 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.
+//
+// Note: As of version 1.2, all constant operations must be folded.  It is
+// not opportunistic, but rather a semantic requirement.
+//
+
+//
+// Do folding between a pair of nodes.
+// 'this' is the left-hand operand and 'rightConstantNode' is the right-hand operand.
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* rightConstantNode) const
+{
+    // For most cases, the return type matches the argument type, so set that
+    // up and just code to exceptions below.
+    TType returnType;
+    returnType.shallowCopy(getType());
+
+    //
+    // A pair of nodes is to be folded together
+    //
+
+    const TIntermConstantUnion *rightNode = rightConstantNode->getAsConstantUnion();
+    TConstUnionArray leftUnionArray = getConstArray();
+    TConstUnionArray rightUnionArray = rightNode->getConstArray();
+
+    // Figure out the size of the result
+    int newComps;
+    int constComps;
+    switch(op) {
+    case EOpMatrixTimesMatrix:
+        newComps = rightNode->getMatrixCols() * getMatrixRows();
+        break;
+    case EOpMatrixTimesVector:
+        newComps = getMatrixRows();
+        break;
+    case EOpVectorTimesMatrix:
+        newComps = rightNode->getMatrixCols();
+        break;
+    default:
+        newComps = getType().computeNumComponents();
+        constComps = rightConstantNode->getType().computeNumComponents();
+        if (constComps == 1 && newComps > 1) {
+            // for a case like vec4 f = vec4(2,3,4,5) + 1.2;
+            TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]);
+            rightUnionArray = smearedArray;
+        } else if (constComps > 1 && newComps == 1) {
+            // for a case like vec4 f = 1.2 + vec4(2,3,4,5);
+            newComps = constComps;
+            rightUnionArray = rightNode->getConstArray();
+            TConstUnionArray smearedArray(newComps, getConstArray()[0]);
+            leftUnionArray = smearedArray;
+            returnType.shallowCopy(rightNode->getType());
+        }
+        break;
+    }
+
+    TConstUnionArray newConstArray(newComps);
+    TType constBool(EbtBool, EvqConst);
+
+    switch(op) {
+    case EOpAdd:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] + rightUnionArray[i];
+        break;
+    case EOpSub:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] - rightUnionArray[i];
+        break;
+
+    case EOpMul:
+    case EOpVectorTimesScalar:
+    case EOpMatrixTimesScalar:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] * rightUnionArray[i];
+        break;
+    case EOpMatrixTimesMatrix:
+        for (int row = 0; row < getMatrixRows(); row++) {
+            for (int column = 0; column < rightNode->getMatrixCols(); column++) {
+                double sum = 0.0f;
+                for (int i = 0; i < rightNode->getMatrixRows(); i++)
+                    sum += leftUnionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * rightNode->getMatrixRows() + i].getDConst();
+                newConstArray[column * getMatrixRows() + row].setDConst(sum);
+            }
+        }
+        returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, rightNode->getMatrixCols(), getMatrixRows()));
+        break;
+    case EOpDiv:
+        for (int i = 0; i < newComps; i++) {
+            switch (getType().getBasicType()) {
+            case EbtDouble:
+            case EbtFloat:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
+                break;
+
+            case EbtInt:
+                if (rightUnionArray[i] == 0)
+                    newConstArray[i].setIConst(0x7FFFFFFF);
+                else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == (int)0x80000000)
+                    newConstArray[i].setIConst(0x80000000);
+                else
+                    newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
+                break;
+
+            case EbtUint:
+                if (rightUnionArray[i] == 0) {
+                    newConstArray[i].setUConst(0xFFFFFFFF);
+                } else
+                    newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
+                break;
+
+            case EbtInt64:
+                if (rightUnionArray[i] == 0)
+                    newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll);
+                else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == (long long)0x8000000000000000)
+                    newConstArray[i].setI64Const(0x8000000000000000);
+                else
+                    newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const());
+                break;
+
+            case EbtUint64:
+                if (rightUnionArray[i] == 0) {
+                    newConstArray[i].setU64Const(0xFFFFFFFFFFFFFFFFull);
+                } else
+                    newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const());
+                break;
+            default:
+                return 0;
+            }
+        }
+        break;
+
+    case EOpMatrixTimesVector:
+        for (int i = 0; i < getMatrixRows(); i++) {
+            double sum = 0.0f;
+            for (int j = 0; j < rightNode->getVectorSize(); j++) {
+                sum += leftUnionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst();
+            }
+            newConstArray[i].setDConst(sum);
+        }
+
+        returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
+        break;
+
+    case EOpVectorTimesMatrix:
+        for (int i = 0; i < rightNode->getMatrixCols(); i++) {
+            double sum = 0.0f;
+            for (int j = 0; j < getVectorSize(); j++)
+                sum += leftUnionArray[j].getDConst() * rightUnionArray[i*rightNode->getMatrixRows() + j].getDConst();
+            newConstArray[i].setDConst(sum);
+        }
+
+        returnType.shallowCopy(TType(getBasicType(), EvqConst, rightNode->getMatrixCols()));
+        break;
+
+    case EOpMod:
+        for (int i = 0; i < newComps; i++) {
+            if (rightUnionArray[i] == 0)
+                newConstArray[i] = leftUnionArray[i];
+            else
+                newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
+        }
+        break;
+
+    case EOpRightShift:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] >> rightUnionArray[i];
+        break;
+
+    case EOpLeftShift:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] << rightUnionArray[i];
+        break;
+
+    case EOpAnd:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] & rightUnionArray[i];
+        break;
+    case EOpInclusiveOr:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] | rightUnionArray[i];
+        break;
+    case EOpExclusiveOr:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] ^ rightUnionArray[i];
+        break;
+
+    case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] && rightUnionArray[i];
+        break;
+
+    case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] || rightUnionArray[i];
+        break;
+
+    case EOpLogicalXor:
+        for (int i = 0; i < newComps; i++) {
+            switch (getType().getBasicType()) {
+            case EbtBool: newConstArray[i].setBConst((leftUnionArray[i] == rightUnionArray[i]) ? false : true); break;
+            default: assert(false && "Default missing");
+            }
+        }
+        break;
+
+    case EOpLessThan:
+        newConstArray[0].setBConst(leftUnionArray[0] < rightUnionArray[0]);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpGreaterThan:
+        newConstArray[0].setBConst(leftUnionArray[0] > rightUnionArray[0]);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpLessThanEqual:
+        newConstArray[0].setBConst(! (leftUnionArray[0] > rightUnionArray[0]));
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpGreaterThanEqual:
+        newConstArray[0].setBConst(! (leftUnionArray[0] < rightUnionArray[0]));
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpEqual:
+        newConstArray[0].setBConst(rightNode->getConstArray() == leftUnionArray);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpNotEqual:
+        newConstArray[0].setBConst(rightNode->getConstArray() != leftUnionArray);
+        returnType.shallowCopy(constBool);
+        break;
+
+    default:
+        return 0;
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+    newNode->setLoc(getLoc());
+
+    return newNode;
+}
+
+//
+// Do single unary node folding
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) const
+{
+    // First, size the result, which is mostly the same as the argument's size,
+    // but not always, and classify what is componentwise.
+    // Also, eliminate cases that can't be compile-time constant.
+    int resultSize;
+    bool componentWise = true;
+
+    int objectSize = getType().computeNumComponents();
+    switch (op) {
+    case EOpDeterminant:
+    case EOpAny:
+    case EOpAll:
+    case EOpLength:
+        componentWise = false;
+        resultSize = 1;
+        break;
+
+    case EOpEmitStreamVertex:
+    case EOpEndStreamPrimitive:
+        // These don't actually fold
+        return 0;
+
+    case EOpPackSnorm2x16:
+    case EOpPackUnorm2x16:
+    case EOpPackHalf2x16:
+        componentWise = false;
+        resultSize = 1;
+        break;
+
+    case EOpUnpackSnorm2x16:
+    case EOpUnpackUnorm2x16:
+    case EOpUnpackHalf2x16:
+        componentWise = false;
+        resultSize = 2;
+        break;
+
+    case EOpNormalize:
+        componentWise = false;
+        resultSize = objectSize;
+        break;
+
+    default:
+        resultSize = objectSize;
+        break;
+    }
+
+    // Set up for processing
+    TConstUnionArray newConstArray(resultSize);
+    const TConstUnionArray& unionArray = getConstArray();
+
+    // Process non-component-wise operations
+    switch (op) {
+    case EOpLength:
+    case EOpNormalize:
+    {
+        double sum = 0;
+        for (int i = 0; i < objectSize; i++)
+            sum += unionArray[i].getDConst() * unionArray[i].getDConst();
+        double length = sqrt(sum);
+        if (op == EOpLength)
+            newConstArray[0].setDConst(length);
+        else {
+            for (int i = 0; i < objectSize; i++)
+                newConstArray[i].setDConst(unionArray[i].getDConst() / length);
+        }
+        break;
+    }
+
+    case EOpAny:
+    {
+        bool result = false;
+        for (int i = 0; i < objectSize; i++) {
+            if (unionArray[i].getBConst())
+                result = true;
+        }
+        newConstArray[0].setBConst(result);
+        break;
+    }
+    case EOpAll:
+    {
+        bool result = true;
+        for (int i = 0; i < objectSize; i++) {
+            if (! unionArray[i].getBConst())
+                result = false;
+        }
+        newConstArray[0].setBConst(result);
+        break;
+    }
+
+    // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+    case EOpPackSnorm2x16:
+    case EOpPackUnorm2x16:
+    case EOpPackHalf2x16:
+
+    case EOpUnpackSnorm2x16:
+    case EOpUnpackUnorm2x16:
+    case EOpUnpackHalf2x16:
+
+    case EOpDeterminant:
+    case EOpMatrixInverse:
+    case EOpTranspose:
+        return 0;
+
+    default:
+        assert(componentWise);
+        break;
+    }
+
+    // Turn off the componentwise loop
+    if (! componentWise)
+        objectSize = 0;
+
+    // Process component-wise operations
+    for (int i = 0; i < objectSize; i++) {
+        switch (op) {
+        case EOpNegative:
+            switch (getType().getBasicType()) {
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+            case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
+            case EbtInt:   newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+            case EbtUint:  newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst())));  break;
+            case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
+            case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getU64Const())));  break;
+            default:
+                return 0;
+            }
+            break;
+        case EOpLogicalNot:
+        case EOpVectorLogicalNot:
+            switch (getType().getBasicType()) {
+            case EbtBool:  newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+            default:
+                return 0;
+            }
+            break;
+        case EOpBitwiseNot:
+            newConstArray[i] = ~unionArray[i];
+            break;
+        case EOpRadians:
+            newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0);
+            break;
+        case EOpDegrees:
+            newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi);
+            break;
+        case EOpSin:
+            newConstArray[i].setDConst(sin(unionArray[i].getDConst()));
+            break;
+        case EOpCos:
+            newConstArray[i].setDConst(cos(unionArray[i].getDConst()));
+            break;
+        case EOpTan:
+            newConstArray[i].setDConst(tan(unionArray[i].getDConst()));
+            break;
+        case EOpAsin:
+            newConstArray[i].setDConst(asin(unionArray[i].getDConst()));
+            break;
+        case EOpAcos:
+            newConstArray[i].setDConst(acos(unionArray[i].getDConst()));
+            break;
+        case EOpAtan:
+            newConstArray[i].setDConst(atan(unionArray[i].getDConst()));
+            break;
+
+        case EOpDPdx:
+        case EOpDPdy:
+        case EOpFwidth:
+        case EOpDPdxFine:
+        case EOpDPdyFine:
+        case EOpFwidthFine:
+        case EOpDPdxCoarse:
+        case EOpDPdyCoarse:
+        case EOpFwidthCoarse:
+            // The derivatives are all mandated to create a constant 0.
+            newConstArray[i].setDConst(0.0);
+            break;
+
+        case EOpExp:
+            newConstArray[i].setDConst(exp(unionArray[i].getDConst()));
+            break;
+        case EOpLog:
+            newConstArray[i].setDConst(log(unionArray[i].getDConst()));
+            break;
+        case EOpExp2:
+            {
+                const double inv_log2_e = 0.69314718055994530941723212145818;
+                newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e));
+                break;
+            }
+        case EOpLog2:
+            {
+                const double log2_e = 1.4426950408889634073599246810019;
+                newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst()));
+                break;
+            }
+        case EOpSqrt:
+            newConstArray[i].setDConst(sqrt(unionArray[i].getDConst()));
+            break;
+        case EOpInverseSqrt:
+            newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst()));
+            break;
+
+        case EOpAbs:
+            if (unionArray[i].getType() == EbtDouble)
+                newConstArray[i].setDConst(fabs(unionArray[i].getDConst()));
+            else if (unionArray[i].getType() == EbtInt)
+                newConstArray[i].setIConst(abs(unionArray[i].getIConst()));
+            else
+                newConstArray[i] = unionArray[i];
+            break;
+        case EOpSign:
+            #define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1))
+            if (unionArray[i].getType() == EbtDouble)
+                newConstArray[i].setDConst(SIGN(unionArray[i].getDConst()));
+            else
+                newConstArray[i].setIConst(SIGN(unionArray[i].getIConst()));
+            break;
+        case EOpFloor:
+            newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+            break;
+        case EOpTrunc:
+            if (unionArray[i].getDConst() > 0)
+                newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+            else
+                newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+            break;
+        case EOpRound:
+            newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst()));
+            break;
+        case EOpRoundEven:
+        {
+            double flr = floor(unionArray[i].getDConst());
+            bool even = flr / 2.0 == floor(flr / 2.0);
+            double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5);
+            newConstArray[i].setDConst(rounded);
+            break;
+        }
+        case EOpCeil:
+            newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+            break;
+        case EOpFract:
+        {
+            double x = unionArray[i].getDConst();
+            newConstArray[i].setDConst(x - floor(x));
+            break;
+        }
+
+        case EOpIsNan:
+        {
+            newConstArray[i].setBConst(isNan(unionArray[i].getDConst()));
+            break;
+        }
+        case EOpIsInf:
+        {
+            newConstArray[i].setBConst(isInf(unionArray[i].getDConst()));
+            break;
+        }
+
+        // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+        case EOpSinh:
+        case EOpCosh:
+        case EOpTanh:
+        case EOpAsinh:
+        case EOpAcosh:
+        case EOpAtanh:
+
+        case EOpFloatBitsToInt:
+        case EOpFloatBitsToUint:
+        case EOpIntBitsToFloat:
+        case EOpUintBitsToFloat:
+        case EOpDoubleBitsToInt64:
+        case EOpDoubleBitsToUint64:
+
+        default:
+            return 0;
+        }
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+    newNode->getWritableType().getQualifier().storage = EvqConst;
+    newNode->setLoc(getLoc());
+
+    return newNode;
+}
+
+//
+// Do constant folding for an aggregate node that has all its children
+// as constants and an operator that requires constant folding.
+//
+TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
+{
+    if (aggrNode == nullptr)
+        return aggrNode;
+
+    if (! areAllChildConst(aggrNode))
+        return aggrNode;
+
+    if (aggrNode->isConstructor())
+        return foldConstructor(aggrNode);
+
+    TIntermSequence& children = aggrNode->getSequence();
+
+    // First, see if this is an operation to constant fold, kick out if not,
+    // see what size the result is if so.
+
+    bool componentwise = false;  // will also say componentwise if a scalar argument gets repeated to make per-component results
+    int objectSize;
+    switch (aggrNode->getOp()) {
+    case EOpAtan:
+    case EOpPow:
+    case EOpMin:
+    case EOpMax:
+    case EOpMix:
+    case EOpClamp:
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+    case EOpVectorEqual:
+    case EOpVectorNotEqual:
+        componentwise = true;
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        break;
+    case EOpCross:
+    case EOpReflect:
+    case EOpRefract:
+    case EOpFaceForward:
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        break;
+    case EOpDistance:
+    case EOpDot:
+        objectSize = 1;
+        break;
+    case EOpOuterProduct:
+        objectSize = children[0]->getAsTyped()->getType().getVectorSize() *
+                     children[1]->getAsTyped()->getType().getVectorSize();
+        break;
+    case EOpStep:
+        componentwise = true;
+        objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+                              children[1]->getAsTyped()->getType().getVectorSize());
+        break;
+    case EOpSmoothStep:
+        componentwise = true;
+        objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+                              children[2]->getAsTyped()->getType().getVectorSize());
+        break;
+    default:
+        return aggrNode;
+    }
+    TConstUnionArray newConstArray(objectSize);
+
+    TVector<TConstUnionArray> childConstUnions;
+    for (unsigned int arg = 0; arg < children.size(); ++arg)
+        childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray());
+
+    // Second, do the actual folding
+
+    bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat ||
+#ifdef AMD_EXTENSIONS
+                           children[0]->getAsTyped()->getBasicType() == EbtFloat16 ||
+#endif
+                           children[0]->getAsTyped()->getBasicType() == EbtDouble;
+    bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt ||
+                    children[0]->getAsTyped()->getBasicType() == EbtInt64;
+    bool isInt64 = children[0]->getAsTyped()->getBasicType() == EbtInt64 ||
+                   children[0]->getAsTyped()->getBasicType() == EbtUint64;
+    if (componentwise) {
+        for (int comp = 0; comp < objectSize; comp++) {
+
+            // some arguments are scalars instead of matching vectors; simulate a smear
+            int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1);
+            int arg1comp = 0;
+            if (children.size() > 1)
+                arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1);
+            int arg2comp = 0;
+            if (children.size() > 2)
+                arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1);
+
+            switch (aggrNode->getOp()) {
+            case EOpAtan:
+                newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                break;
+            case EOpPow:
+                newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                break;
+            case EOpMin:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+                }
+                break;
+            case EOpMax:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+                }
+                break;
+            case EOpClamp:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
+                                                                                                               childConstUnions[2][arg2comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()),
+                                                                                                                       childConstUnions[2][arg2comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()),
+                                                                                                                   childConstUnions[2][arg2comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()),
+                                                                                                                       childConstUnions[2][arg2comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()),
+                                                                                                                   childConstUnions[2][arg2comp].getUConst()));
+                }
+                break;
+            case EOpLessThan:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]);
+                break;
+            case EOpGreaterThan:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]);
+                break;
+            case EOpLessThanEqual:
+                newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]));
+                break;
+            case EOpGreaterThanEqual:
+                newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]));
+                break;
+            case EOpVectorEqual:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]);
+                break;
+            case EOpVectorNotEqual:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]);
+                break;
+            case EOpMix:
+                if (children[2]->getAsTyped()->getBasicType() == EbtBool)
+                    newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() :
+                                                                                              childConstUnions[0][arg0comp].getDConst());
+                else
+                    newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) +
+                                                  childConstUnions[1][arg1comp].getDConst() *        childConstUnions[2][arg2comp].getDConst());
+                break;
+            case EOpStep:
+                newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0);
+                break;
+            case EOpSmoothStep:
+            {
+                double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) /
+                           (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst());
+                if (t < 0.0)
+                    t = 0.0;
+                if (t > 1.0)
+                    t = 1.0;
+                newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t));
+                break;
+            }
+            default:
+                return aggrNode;
+            }
+        }
+    } else {
+        // Non-componentwise...
+
+        int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        double dot;
+
+        switch (aggrNode->getOp()) {
+        case EOpDistance:
+        {
+            double sum = 0.0;
+            for (int comp = 0; comp < numComps; ++comp) {
+                double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
+                sum += diff * diff;
+            }
+            newConstArray[0].setDConst(sqrt(sum));
+            break;
+        }
+        case EOpDot:
+            newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
+            break;
+        case EOpCross:
+            newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
+            newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
+            newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
+            break;
+        case EOpFaceForward:
+            // If dot(Nref, I) < 0 return N, otherwise return -N:  Arguments are (N, I, Nref).
+            dot = childConstUnions[1].dot(childConstUnions[2]);
+            for (int comp = 0; comp < numComps; ++comp) {
+                if (dot < 0.0)
+                    newConstArray[comp] = childConstUnions[0][comp];
+                else
+                    newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
+            }
+            break;
+        case EOpReflect:
+            // I - 2 * dot(N, I) * N:  Arguments are (I, N).
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            dot *= 2.0;
+            for (int comp = 0; comp < numComps; ++comp)
+                newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
+            break;
+        case EOpRefract:
+        {
+            // Arguments are (I, N, eta).
+            // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+            // if (k < 0.0)
+            //     return dvec(0.0)
+            // else
+            //     return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            double eta = childConstUnions[2][0].getDConst();
+            double k = 1.0 - eta * eta * (1.0 - dot * dot);
+            if (k < 0.0) {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(0.0);
+            } else {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
+            }
+            break;
+        }
+        case EOpOuterProduct:
+        {
+            int numRows = numComps;
+            int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
+            for (int row = 0; row < numRows; ++row)
+                for (int col = 0; col < numCols; ++col)
+                    newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
+            break;
+        }
+        default:
+            return aggrNode;
+        }
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
+    newNode->getWritableType().getQualifier().storage = EvqConst;
+    newNode->setLoc(aggrNode->getLoc());
+
+    return newNode;
+}
+
+bool TIntermediate::areAllChildConst(TIntermAggregate* aggrNode)
+{
+    bool allConstant = true;
+
+    // check if all the child nodes are constants so that they can be inserted into
+    // the parent node
+    if (aggrNode) {
+        TIntermSequence& childSequenceVector = aggrNode->getSequence();
+        for (TIntermSequence::iterator p  = childSequenceVector.begin();
+                                       p != childSequenceVector.end(); p++) {
+            if (!(*p)->getAsTyped()->getAsConstantUnion())
+                return false;
+        }
+    }
+
+    return allConstant;
+}
+
+TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
+{
+    bool error = false;
+
+    TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
+    if (aggrNode->getSequence().size() == 1)
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
+    else
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
+
+    if (error)
+        return aggrNode;
+
+    return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
+}
+
+//
+// Constant folding of a bracket (array-style) dereference or struct-like dot
+// dereference.  Can handle anything except a multi-character swizzle, though
+// all swizzles may go to foldSwizzle().
+//
+TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, const TSourceLoc& loc)
+{
+    TType dereferencedType(node->getType(), index);
+    dereferencedType.getQualifier().storage = EvqConst;
+    TIntermTyped* result = 0;
+    int size = dereferencedType.computeNumComponents();
+
+    // arrays, vectors, matrices, all use simple multiplicative math
+    // while structures need to add up heterogeneous members
+    int start;
+    if (node->isArray() || ! node->isStruct())
+        start = size * index;
+    else {
+        // it is a structure
+        assert(node->isStruct());
+        start = 0;
+        for (int i = 0; i < index; ++i)
+            start += (*node->getType().getStruct())[i].type->computeNumComponents();
+    }
+
+    result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc);
+
+    if (result == 0)
+        result = node;
+    else
+        result->setType(dereferencedType);
+
+    return result;
+}
+
+//
+// Make a constant vector node or constant scalar node, representing a given
+// constant vector and constant swizzle into it.
+//
+TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& selectors, const TSourceLoc& loc)
+{
+    const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray();
+    TConstUnionArray constArray(selectors.size());
+
+    for (int i = 0; i < selectors.size(); i++)
+        constArray[i] = unionArray[selectors[i]];
+
+    TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc);
+
+    if (result == 0)
+        result = node;
+    else
+        result->setType(TType(node->getBasicType(), EvqConst, selectors.size()));
+
+    return result;
+}
+
+} // end namespace glslang

+ 113 - 0
src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp

@@ -0,0 +1,113 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/InfoSink.h"
+
+#include <cstring>
+
+namespace glslang {
+
+void TInfoSinkBase::append(const char* s)
+{
+    if (outputStream & EString) {
+        if (s == nullptr)
+            sink.append("(null)");
+        else {
+            checkMem(strlen(s));
+            sink.append(s);
+        }
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(s);
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", s);
+}
+
+void TInfoSinkBase::append(int count, char c)
+{
+    if (outputStream & EString) {
+        checkMem(count);
+        sink.append(count, c);
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger) {
+//        char str[2];
+//        str[0] = c;
+//        str[1] = '\0';
+//        OutputDebugString(str);
+//    }
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%c", c);
+}
+
+void TInfoSinkBase::append(const TPersistString& t)
+{
+    if (outputStream & EString) {
+        checkMem(t.size());
+        sink.append(t);
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(t.c_str());
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", t.c_str());
+}
+
+void TInfoSinkBase::append(const TString& t)
+{
+    if (outputStream & EString) {
+        checkMem(t.size());
+        sink.append(t.c_str());
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(t.c_str());
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", t.c_str());
+}
+
+} // end namespace glslang

+ 5759 - 0
src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp

@@ -0,0 +1,5759 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Create strings that declare built-in definitions, add built-ins programmatically
+// that cannot be expressed in the strings, and establish mappings between
+// built-in functions and operators.
+//
+// Where to put a built-in:
+//   TBuiltIns::initialize(version,profile)       context-independent textual built-ins; add them to the right string
+//   TBuiltIns::initialize(resources,...)         context-dependent textual built-ins; add them to the right string
+//   TBuiltIns::identifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table,
+//                                                including identifying what extensions are needed if a version does not allow a symbol
+//   TBuiltIns::identifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table,
+//                                                including identifying what extensions are needed if a version does not allow a symbol
+//
+
+#include "../Include/intermediate.h"
+#include "Initialize.h"
+
+namespace glslang {
+
+// TODO: ARB_Compatability: do full extension support
+const bool ARBCompatibility = true;
+
+const bool ForwardCompatibility = false;
+
+// change this back to false if depending on textual spellings of texturing calls when consuming the AST
+// Using PureOperatorBuiltins=false is deprecated.
+bool PureOperatorBuiltins = true;
+
+inline bool IncludeLegacy(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    return profile != EEsProfile && (version <= 130 || (spvVersion.spv == 0 && ARBCompatibility) || profile == ECompatibilityProfile);
+}
+
+// Construct TBuiltInParseables base class.  This can be used for language-common constructs.
+TBuiltInParseables::TBuiltInParseables()
+{
+}
+
+// Destroy TBuiltInParseables.
+TBuiltInParseables::~TBuiltInParseables()
+{
+}
+
+TBuiltIns::TBuiltIns()
+{
+    // Set up textual representations for making all the permutations
+    // of texturing/imaging functions.
+    prefixes[EbtFloat] =  "";
+    prefixes[EbtInt]   = "i";
+    prefixes[EbtUint]  = "u";
+    postfixes[2] = "2";
+    postfixes[3] = "3";
+    postfixes[4] = "4";
+
+    // Map from symbolic class of texturing dimension to numeric dimensions.
+    dimMap[Esd1D] = 1;
+    dimMap[Esd2D] = 2;
+    dimMap[EsdRect] = 2;
+    dimMap[Esd3D] = 3;
+    dimMap[EsdCube] = 3;
+    dimMap[EsdBuffer] = 1;
+    dimMap[EsdSubpass] = 2;  // potientially unused for now
+}
+
+TBuiltIns::~TBuiltIns()
+{
+}
+
+//
+// Add all context-independent built-in functions and variables that are present
+// for the given version and profile.  Share common ones across stages, otherwise
+// make stage-specific entries.
+//
+// Most built-ins variables can be added as simple text strings.  Some need to
+// be added programmatically, which is done later in IdentifyBuiltIns() below.
+//
+void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by both vertex and fragment shaders.
+    //
+    //============================================================================
+
+    //
+    // Angle and Trigonometric Functions.
+    //
+    commonBuiltins.append(
+        "float radians(float degrees);"
+        "vec2  radians(vec2  degrees);"
+        "vec3  radians(vec3  degrees);"
+        "vec4  radians(vec4  degrees);"
+
+        "float degrees(float radians);"
+        "vec2  degrees(vec2  radians);"
+        "vec3  degrees(vec3  radians);"
+        "vec4  degrees(vec4  radians);"
+
+        "float sin(float angle);"
+        "vec2  sin(vec2  angle);"
+        "vec3  sin(vec3  angle);"
+        "vec4  sin(vec4  angle);"
+
+        "float cos(float angle);"
+        "vec2  cos(vec2  angle);"
+        "vec3  cos(vec3  angle);"
+        "vec4  cos(vec4  angle);"
+
+        "float tan(float angle);"
+        "vec2  tan(vec2  angle);"
+        "vec3  tan(vec3  angle);"
+        "vec4  tan(vec4  angle);"
+
+        "float asin(float x);"
+        "vec2  asin(vec2  x);"
+        "vec3  asin(vec3  x);"
+        "vec4  asin(vec4  x);"
+
+        "float acos(float x);"
+        "vec2  acos(vec2  x);"
+        "vec3  acos(vec3  x);"
+        "vec4  acos(vec4  x);"
+
+        "float atan(float y, float x);"
+        "vec2  atan(vec2  y, vec2  x);"
+        "vec3  atan(vec3  y, vec3  x);"
+        "vec4  atan(vec4  y, vec4  x);"
+
+        "float atan(float y_over_x);"
+        "vec2  atan(vec2  y_over_x);"
+        "vec3  atan(vec3  y_over_x);"
+        "vec4  atan(vec4  y_over_x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "float sinh(float angle);"
+            "vec2  sinh(vec2  angle);"
+            "vec3  sinh(vec3  angle);"
+            "vec4  sinh(vec4  angle);"
+
+            "float cosh(float angle);"
+            "vec2  cosh(vec2  angle);"
+            "vec3  cosh(vec3  angle);"
+            "vec4  cosh(vec4  angle);"
+
+            "float tanh(float angle);"
+            "vec2  tanh(vec2  angle);"
+            "vec3  tanh(vec3  angle);"
+            "vec4  tanh(vec4  angle);"
+
+            "float asinh(float x);"
+            "vec2  asinh(vec2  x);"
+            "vec3  asinh(vec3  x);"
+            "vec4  asinh(vec4  x);"
+
+            "float acosh(float x);"
+            "vec2  acosh(vec2  x);"
+            "vec3  acosh(vec3  x);"
+            "vec4  acosh(vec4  x);"
+
+            "float atanh(float y_over_x);"
+            "vec2  atanh(vec2  y_over_x);"
+            "vec3  atanh(vec3  y_over_x);"
+            "vec4  atanh(vec4  y_over_x);"
+
+            "\n");
+    }
+
+    //
+    // Exponential Functions.
+    //
+    commonBuiltins.append(
+        "float pow(float x, float y);"
+        "vec2  pow(vec2  x, vec2  y);"
+        "vec3  pow(vec3  x, vec3  y);"
+        "vec4  pow(vec4  x, vec4  y);"
+
+        "float exp(float x);"
+        "vec2  exp(vec2  x);"
+        "vec3  exp(vec3  x);"
+        "vec4  exp(vec4  x);"
+
+        "float log(float x);"
+        "vec2  log(vec2  x);"
+        "vec3  log(vec3  x);"
+        "vec4  log(vec4  x);"
+
+        "float exp2(float x);"
+        "vec2  exp2(vec2  x);"
+        "vec3  exp2(vec3  x);"
+        "vec4  exp2(vec4  x);"
+
+        "float log2(float x);"
+        "vec2  log2(vec2  x);"
+        "vec3  log2(vec3  x);"
+        "vec4  log2(vec4  x);"
+
+        "float sqrt(float x);"
+        "vec2  sqrt(vec2  x);"
+        "vec3  sqrt(vec3  x);"
+        "vec4  sqrt(vec4  x);"
+
+        "float inversesqrt(float x);"
+        "vec2  inversesqrt(vec2  x);"
+        "vec3  inversesqrt(vec3  x);"
+        "vec4  inversesqrt(vec4  x);"
+
+        "\n");
+
+    //
+    // Common Functions.
+    //
+    commonBuiltins.append(
+        "float abs(float x);"
+        "vec2  abs(vec2  x);"
+        "vec3  abs(vec3  x);"
+        "vec4  abs(vec4  x);"
+
+        "float sign(float x);"
+        "vec2  sign(vec2  x);"
+        "vec3  sign(vec3  x);"
+        "vec4  sign(vec4  x);"
+
+        "float floor(float x);"
+        "vec2  floor(vec2  x);"
+        "vec3  floor(vec3  x);"
+        "vec4  floor(vec4  x);"
+
+        "float ceil(float x);"
+        "vec2  ceil(vec2  x);"
+        "vec3  ceil(vec3  x);"
+        "vec4  ceil(vec4  x);"
+
+        "float fract(float x);"
+        "vec2  fract(vec2  x);"
+        "vec3  fract(vec3  x);"
+        "vec4  fract(vec4  x);"
+
+        "float mod(float x, float y);"
+        "vec2  mod(vec2  x, float y);"
+        "vec3  mod(vec3  x, float y);"
+        "vec4  mod(vec4  x, float y);"
+        "vec2  mod(vec2  x, vec2  y);"
+        "vec3  mod(vec3  x, vec3  y);"
+        "vec4  mod(vec4  x, vec4  y);"
+
+        "float min(float x, float y);"
+        "vec2  min(vec2  x, float y);"
+        "vec3  min(vec3  x, float y);"
+        "vec4  min(vec4  x, float y);"
+        "vec2  min(vec2  x, vec2  y);"
+        "vec3  min(vec3  x, vec3  y);"
+        "vec4  min(vec4  x, vec4  y);"
+
+        "float max(float x, float y);"
+        "vec2  max(vec2  x, float y);"
+        "vec3  max(vec3  x, float y);"
+        "vec4  max(vec4  x, float y);"
+        "vec2  max(vec2  x, vec2  y);"
+        "vec3  max(vec3  x, vec3  y);"
+        "vec4  max(vec4  x, vec4  y);"
+
+        "float clamp(float x, float minVal, float maxVal);"
+        "vec2  clamp(vec2  x, float minVal, float maxVal);"
+        "vec3  clamp(vec3  x, float minVal, float maxVal);"
+        "vec4  clamp(vec4  x, float minVal, float maxVal);"
+        "vec2  clamp(vec2  x, vec2  minVal, vec2  maxVal);"
+        "vec3  clamp(vec3  x, vec3  minVal, vec3  maxVal);"
+        "vec4  clamp(vec4  x, vec4  minVal, vec4  maxVal);"
+
+        "float mix(float x, float y, float a);"
+        "vec2  mix(vec2  x, vec2  y, float a);"
+        "vec3  mix(vec3  x, vec3  y, float a);"
+        "vec4  mix(vec4  x, vec4  y, float a);"
+        "vec2  mix(vec2  x, vec2  y, vec2  a);"
+        "vec3  mix(vec3  x, vec3  y, vec3  a);"
+        "vec4  mix(vec4  x, vec4  y, vec4  a);"
+
+        "float step(float edge, float x);"
+        "vec2  step(vec2  edge, vec2  x);"
+        "vec3  step(vec3  edge, vec3  x);"
+        "vec4  step(vec4  edge, vec4  x);"
+        "vec2  step(float edge, vec2  x);"
+        "vec3  step(float edge, vec3  x);"
+        "vec4  step(float edge, vec4  x);"
+
+        "float smoothstep(float edge0, float edge1, float x);"
+        "vec2  smoothstep(vec2  edge0, vec2  edge1, vec2  x);"
+        "vec3  smoothstep(vec3  edge0, vec3  edge1, vec3  x);"
+        "vec4  smoothstep(vec4  edge0, vec4  edge1, vec4  x);"
+        "vec2  smoothstep(float edge0, float edge1, vec2  x);"
+        "vec3  smoothstep(float edge0, float edge1, vec3  x);"
+        "vec4  smoothstep(float edge0, float edge1, vec4  x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "  int abs(  int x);"
+            "ivec2 abs(ivec2 x);"
+            "ivec3 abs(ivec3 x);"
+            "ivec4 abs(ivec4 x);"
+
+            "  int sign(  int x);"
+            "ivec2 sign(ivec2 x);"
+            "ivec3 sign(ivec3 x);"
+            "ivec4 sign(ivec4 x);"
+
+            "float trunc(float x);"
+            "vec2  trunc(vec2  x);"
+            "vec3  trunc(vec3  x);"
+            "vec4  trunc(vec4  x);"
+
+            "float round(float x);"
+            "vec2  round(vec2  x);"
+            "vec3  round(vec3  x);"
+            "vec4  round(vec4  x);"
+
+            "float roundEven(float x);"
+            "vec2  roundEven(vec2  x);"
+            "vec3  roundEven(vec3  x);"
+            "vec4  roundEven(vec4  x);"
+
+            "float modf(float, out float);"
+            "vec2  modf(vec2,  out vec2 );"
+            "vec3  modf(vec3,  out vec3 );"
+            "vec4  modf(vec4,  out vec4 );"
+
+            "  int min(int    x, int y);"
+            "ivec2 min(ivec2  x, int y);"
+            "ivec3 min(ivec3  x, int y);"
+            "ivec4 min(ivec4  x, int y);"
+            "ivec2 min(ivec2  x, ivec2  y);"
+            "ivec3 min(ivec3  x, ivec3  y);"
+            "ivec4 min(ivec4  x, ivec4  y);"
+
+            " uint min(uint   x, uint y);"
+            "uvec2 min(uvec2  x, uint y);"
+            "uvec3 min(uvec3  x, uint y);"
+            "uvec4 min(uvec4  x, uint y);"
+            "uvec2 min(uvec2  x, uvec2  y);"
+            "uvec3 min(uvec3  x, uvec3  y);"
+            "uvec4 min(uvec4  x, uvec4  y);"
+
+            "  int max(int    x, int y);"
+            "ivec2 max(ivec2  x, int y);"
+            "ivec3 max(ivec3  x, int y);"
+            "ivec4 max(ivec4  x, int y);"
+            "ivec2 max(ivec2  x, ivec2  y);"
+            "ivec3 max(ivec3  x, ivec3  y);"
+            "ivec4 max(ivec4  x, ivec4  y);"
+
+            " uint max(uint   x, uint y);"
+            "uvec2 max(uvec2  x, uint y);"
+            "uvec3 max(uvec3  x, uint y);"
+            "uvec4 max(uvec4  x, uint y);"
+            "uvec2 max(uvec2  x, uvec2  y);"
+            "uvec3 max(uvec3  x, uvec3  y);"
+            "uvec4 max(uvec4  x, uvec4  y);"
+
+            "int    clamp(int x, int minVal, int maxVal);"
+            "ivec2  clamp(ivec2  x, int minVal, int maxVal);"
+            "ivec3  clamp(ivec3  x, int minVal, int maxVal);"
+            "ivec4  clamp(ivec4  x, int minVal, int maxVal);"
+            "ivec2  clamp(ivec2  x, ivec2  minVal, ivec2  maxVal);"
+            "ivec3  clamp(ivec3  x, ivec3  minVal, ivec3  maxVal);"
+            "ivec4  clamp(ivec4  x, ivec4  minVal, ivec4  maxVal);"
+
+            "uint   clamp(uint x, uint minVal, uint maxVal);"
+            "uvec2  clamp(uvec2  x, uint minVal, uint maxVal);"
+            "uvec3  clamp(uvec3  x, uint minVal, uint maxVal);"
+            "uvec4  clamp(uvec4  x, uint minVal, uint maxVal);"
+            "uvec2  clamp(uvec2  x, uvec2  minVal, uvec2  maxVal);"
+            "uvec3  clamp(uvec3  x, uvec3  minVal, uvec3  maxVal);"
+            "uvec4  clamp(uvec4  x, uvec4  minVal, uvec4  maxVal);"
+
+            "float mix(float x, float y, bool  a);"
+            "vec2  mix(vec2  x, vec2  y, bvec2 a);"
+            "vec3  mix(vec3  x, vec3  y, bvec3 a);"
+            "vec4  mix(vec4  x, vec4  y, bvec4 a);"
+
+            "bool  isnan(float x);"
+            "bvec2 isnan(vec2  x);"
+            "bvec3 isnan(vec3  x);"
+            "bvec4 isnan(vec4  x);"
+
+            "bool  isinf(float x);"
+            "bvec2 isinf(vec2  x);"
+            "bvec3 isinf(vec3  x);"
+            "bvec4 isinf(vec4  x);"
+
+            "\n");
+    }
+
+    //
+    // double functions added to desktop 4.00, but not fma, frexp, ldexp, or pack/unpack
+    //
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+
+            "double sqrt(double);"
+            "dvec2  sqrt(dvec2);"
+            "dvec3  sqrt(dvec3);"
+            "dvec4  sqrt(dvec4);"
+
+            "double inversesqrt(double);"
+            "dvec2  inversesqrt(dvec2);"
+            "dvec3  inversesqrt(dvec3);"
+            "dvec4  inversesqrt(dvec4);"
+
+            "double abs(double);"
+            "dvec2  abs(dvec2);"
+            "dvec3  abs(dvec3);"
+            "dvec4  abs(dvec4);"
+
+            "double sign(double);"
+            "dvec2  sign(dvec2);"
+            "dvec3  sign(dvec3);"
+            "dvec4  sign(dvec4);"
+
+            "double floor(double);"
+            "dvec2  floor(dvec2);"
+            "dvec3  floor(dvec3);"
+            "dvec4  floor(dvec4);"
+
+            "double trunc(double);"
+            "dvec2  trunc(dvec2);"
+            "dvec3  trunc(dvec3);"
+            "dvec4  trunc(dvec4);"
+
+            "double round(double);"
+            "dvec2  round(dvec2);"
+            "dvec3  round(dvec3);"
+            "dvec4  round(dvec4);"
+
+            "double roundEven(double);"
+            "dvec2  roundEven(dvec2);"
+            "dvec3  roundEven(dvec3);"
+            "dvec4  roundEven(dvec4);"
+
+            "double ceil(double);"
+            "dvec2  ceil(dvec2);"
+            "dvec3  ceil(dvec3);"
+            "dvec4  ceil(dvec4);"
+
+            "double fract(double);"
+            "dvec2  fract(dvec2);"
+            "dvec3  fract(dvec3);"
+            "dvec4  fract(dvec4);"
+
+            "double mod(double, double);"
+            "dvec2  mod(dvec2 , double);"
+            "dvec3  mod(dvec3 , double);"
+            "dvec4  mod(dvec4 , double);"
+            "dvec2  mod(dvec2 , dvec2);"
+            "dvec3  mod(dvec3 , dvec3);"
+            "dvec4  mod(dvec4 , dvec4);"
+
+            "double modf(double, out double);"
+            "dvec2  modf(dvec2,  out dvec2);"
+            "dvec3  modf(dvec3,  out dvec3);"
+            "dvec4  modf(dvec4,  out dvec4);"
+
+            "double min(double, double);"
+            "dvec2  min(dvec2,  double);"
+            "dvec3  min(dvec3,  double);"
+            "dvec4  min(dvec4,  double);"
+            "dvec2  min(dvec2,  dvec2);"
+            "dvec3  min(dvec3,  dvec3);"
+            "dvec4  min(dvec4,  dvec4);"
+
+            "double max(double, double);"
+            "dvec2  max(dvec2 , double);"
+            "dvec3  max(dvec3 , double);"
+            "dvec4  max(dvec4 , double);"
+            "dvec2  max(dvec2 , dvec2);"
+            "dvec3  max(dvec3 , dvec3);"
+            "dvec4  max(dvec4 , dvec4);"
+
+            "double clamp(double, double, double);"
+            "dvec2  clamp(dvec2 , double, double);"
+            "dvec3  clamp(dvec3 , double, double);"
+            "dvec4  clamp(dvec4 , double, double);"
+            "dvec2  clamp(dvec2 , dvec2 , dvec2);"
+            "dvec3  clamp(dvec3 , dvec3 , dvec3);"
+            "dvec4  clamp(dvec4 , dvec4 , dvec4);"
+
+            "double mix(double, double, double);"
+            "dvec2  mix(dvec2,  dvec2,  double);"
+            "dvec3  mix(dvec3,  dvec3,  double);"
+            "dvec4  mix(dvec4,  dvec4,  double);"
+            "dvec2  mix(dvec2,  dvec2,  dvec2);"
+            "dvec3  mix(dvec3,  dvec3,  dvec3);"
+            "dvec4  mix(dvec4,  dvec4,  dvec4);"
+            "double mix(double, double, bool);"
+            "dvec2  mix(dvec2,  dvec2,  bvec2);"
+            "dvec3  mix(dvec3,  dvec3,  bvec3);"
+            "dvec4  mix(dvec4,  dvec4,  bvec4);"
+
+            "double step(double, double);"
+            "dvec2  step(dvec2 , dvec2);"
+            "dvec3  step(dvec3 , dvec3);"
+            "dvec4  step(dvec4 , dvec4);"
+            "dvec2  step(double, dvec2);"
+            "dvec3  step(double, dvec3);"
+            "dvec4  step(double, dvec4);"
+
+            "double smoothstep(double, double, double);"
+            "dvec2  smoothstep(dvec2 , dvec2 , dvec2);"
+            "dvec3  smoothstep(dvec3 , dvec3 , dvec3);"
+            "dvec4  smoothstep(dvec4 , dvec4 , dvec4);"
+            "dvec2  smoothstep(double, double, dvec2);"
+            "dvec3  smoothstep(double, double, dvec3);"
+            "dvec4  smoothstep(double, double, dvec4);"
+
+            "bool  isnan(double);"
+            "bvec2 isnan(dvec2);"
+            "bvec3 isnan(dvec3);"
+            "bvec4 isnan(dvec4);"
+
+            "bool  isinf(double);"
+            "bvec2 isinf(dvec2);"
+            "bvec3 isinf(dvec3);"
+            "bvec4 isinf(dvec4);"
+
+            "double length(double);"
+            "double length(dvec2);"
+            "double length(dvec3);"
+            "double length(dvec4);"
+
+            "double distance(double, double);"
+            "double distance(dvec2 , dvec2);"
+            "double distance(dvec3 , dvec3);"
+            "double distance(dvec4 , dvec4);"
+
+            "double dot(double, double);"
+            "double dot(dvec2 , dvec2);"
+            "double dot(dvec3 , dvec3);"
+            "double dot(dvec4 , dvec4);"
+
+            "dvec3 cross(dvec3, dvec3);"
+
+            "double normalize(double);"
+            "dvec2  normalize(dvec2);"
+            "dvec3  normalize(dvec3);"
+            "dvec4  normalize(dvec4);"
+
+            "double faceforward(double, double, double);"
+            "dvec2  faceforward(dvec2,  dvec2,  dvec2);"
+            "dvec3  faceforward(dvec3,  dvec3,  dvec3);"
+            "dvec4  faceforward(dvec4,  dvec4,  dvec4);"
+
+            "double reflect(double, double);"
+            "dvec2  reflect(dvec2 , dvec2 );"
+            "dvec3  reflect(dvec3 , dvec3 );"
+            "dvec4  reflect(dvec4 , dvec4 );"
+
+            "double refract(double, double, double);"
+            "dvec2  refract(dvec2 , dvec2 , double);"
+            "dvec3  refract(dvec3 , dvec3 , double);"
+            "dvec4  refract(dvec4 , dvec4 , double);"
+
+            "dmat2 matrixCompMult(dmat2, dmat2);"
+            "dmat3 matrixCompMult(dmat3, dmat3);"
+            "dmat4 matrixCompMult(dmat4, dmat4);"
+            "dmat2x3 matrixCompMult(dmat2x3, dmat2x3);"
+            "dmat2x4 matrixCompMult(dmat2x4, dmat2x4);"
+            "dmat3x2 matrixCompMult(dmat3x2, dmat3x2);"
+            "dmat3x4 matrixCompMult(dmat3x4, dmat3x4);"
+            "dmat4x2 matrixCompMult(dmat4x2, dmat4x2);"
+            "dmat4x3 matrixCompMult(dmat4x3, dmat4x3);"
+
+            "dmat2   outerProduct(dvec2, dvec2);"
+            "dmat3   outerProduct(dvec3, dvec3);"
+            "dmat4   outerProduct(dvec4, dvec4);"
+            "dmat2x3 outerProduct(dvec3, dvec2);"
+            "dmat3x2 outerProduct(dvec2, dvec3);"
+            "dmat2x4 outerProduct(dvec4, dvec2);"
+            "dmat4x2 outerProduct(dvec2, dvec4);"
+            "dmat3x4 outerProduct(dvec4, dvec3);"
+            "dmat4x3 outerProduct(dvec3, dvec4);"
+
+            "dmat2   transpose(dmat2);"
+            "dmat3   transpose(dmat3);"
+            "dmat4   transpose(dmat4);"
+            "dmat2x3 transpose(dmat3x2);"
+            "dmat3x2 transpose(dmat2x3);"
+            "dmat2x4 transpose(dmat4x2);"
+            "dmat4x2 transpose(dmat2x4);"
+            "dmat3x4 transpose(dmat4x3);"
+            "dmat4x3 transpose(dmat3x4);"
+
+            "double determinant(dmat2);"
+            "double determinant(dmat3);"
+            "double determinant(dmat4);"
+
+            "dmat2 inverse(dmat2);"
+            "dmat3 inverse(dmat3);"
+            "dmat4 inverse(dmat4);"
+
+            "bvec2 lessThan(dvec2, dvec2);"
+            "bvec3 lessThan(dvec3, dvec3);"
+            "bvec4 lessThan(dvec4, dvec4);"
+
+            "bvec2 lessThanEqual(dvec2, dvec2);"
+            "bvec3 lessThanEqual(dvec3, dvec3);"
+            "bvec4 lessThanEqual(dvec4, dvec4);"
+
+            "bvec2 greaterThan(dvec2, dvec2);"
+            "bvec3 greaterThan(dvec3, dvec3);"
+            "bvec4 greaterThan(dvec4, dvec4);"
+
+            "bvec2 greaterThanEqual(dvec2, dvec2);"
+            "bvec3 greaterThanEqual(dvec3, dvec3);"
+            "bvec4 greaterThanEqual(dvec4, dvec4);"
+
+            "bvec2 equal(dvec2, dvec2);"
+            "bvec3 equal(dvec3, dvec3);"
+            "bvec4 equal(dvec4, dvec4);"
+
+            "bvec2 notEqual(dvec2, dvec2);"
+            "bvec3 notEqual(dvec3, dvec3);"
+            "bvec4 notEqual(dvec4, dvec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+
+            "int64_t abs(int64_t);"
+            "i64vec2 abs(i64vec2);"
+            "i64vec3 abs(i64vec3);"
+            "i64vec4 abs(i64vec4);"
+
+            "int64_t sign(int64_t);"
+            "i64vec2 sign(i64vec2);"
+            "i64vec3 sign(i64vec3);"
+            "i64vec4 sign(i64vec4);"
+
+            "int64_t  min(int64_t,  int64_t);"
+            "i64vec2  min(i64vec2,  int64_t);"
+            "i64vec3  min(i64vec3,  int64_t);"
+            "i64vec4  min(i64vec4,  int64_t);"
+            "i64vec2  min(i64vec2,  i64vec2);"
+            "i64vec3  min(i64vec3,  i64vec3);"
+            "i64vec4  min(i64vec4,  i64vec4);"
+            "uint64_t min(uint64_t, uint64_t);"
+            "u64vec2  min(u64vec2,  uint64_t);"
+            "u64vec3  min(u64vec3,  uint64_t);"
+            "u64vec4  min(u64vec4,  uint64_t);"
+            "u64vec2  min(u64vec2,  u64vec2);"
+            "u64vec3  min(u64vec3,  u64vec3);"
+            "u64vec4  min(u64vec4,  u64vec4);"
+
+            "int64_t  max(int64_t,  int64_t);"
+            "i64vec2  max(i64vec2,  int64_t);"
+            "i64vec3  max(i64vec3,  int64_t);"
+            "i64vec4  max(i64vec4,  int64_t);"
+            "i64vec2  max(i64vec2,  i64vec2);"
+            "i64vec3  max(i64vec3,  i64vec3);"
+            "i64vec4  max(i64vec4,  i64vec4);"
+            "uint64_t max(uint64_t, uint64_t);"
+            "u64vec2  max(u64vec2,  uint64_t);"
+            "u64vec3  max(u64vec3,  uint64_t);"
+            "u64vec4  max(u64vec4,  uint64_t);"
+            "u64vec2  max(u64vec2,  u64vec2);"
+            "u64vec3  max(u64vec3,  u64vec3);"
+            "u64vec4  max(u64vec4,  u64vec4);"
+
+            "int64_t  clamp(int64_t,  int64_t,  int64_t);"
+            "i64vec2  clamp(i64vec2,  int64_t,  int64_t);"
+            "i64vec3  clamp(i64vec3,  int64_t,  int64_t);"
+            "i64vec4  clamp(i64vec4,  int64_t,  int64_t);"
+            "i64vec2  clamp(i64vec2,  i64vec2,  i64vec2);"
+            "i64vec3  clamp(i64vec3,  i64vec3,  i64vec3);"
+            "i64vec4  clamp(i64vec4,  i64vec4,  i64vec4);"
+            "uint64_t clamp(uint64_t, uint64_t, uint64_t);"
+            "u64vec2  clamp(u64vec2,  uint64_t, uint64_t);"
+            "u64vec3  clamp(u64vec3,  uint64_t, uint64_t);"
+            "u64vec4  clamp(u64vec4,  uint64_t, uint64_t);"
+            "u64vec2  clamp(u64vec2,  u64vec2,  u64vec2);"
+            "u64vec3  clamp(u64vec3,  u64vec3,  u64vec3);"
+            "u64vec4  clamp(u64vec4,  u64vec4,  u64vec4);"
+
+            "int64_t  mix(int64_t,  int64_t,  bool);"
+            "i64vec2  mix(i64vec2,  i64vec2,  bvec2);"
+            "i64vec3  mix(i64vec3,  i64vec3,  bvec3);"
+            "i64vec4  mix(i64vec4,  i64vec4,  bvec4);"
+            "uint64_t mix(uint64_t, uint64_t, bool);"
+            "u64vec2  mix(u64vec2,  u64vec2,  bvec2);"
+            "u64vec3  mix(u64vec3,  u64vec3,  bvec3);"
+            "u64vec4  mix(u64vec4,  u64vec4,  bvec4);"
+
+            "int64_t doubleBitsToInt64(double);"
+            "i64vec2 doubleBitsToInt64(dvec2);"
+            "i64vec3 doubleBitsToInt64(dvec3);"
+            "i64vec4 doubleBitsToInt64(dvec4);"
+
+            "uint64_t doubleBitsToUint64(double);"
+            "u64vec2  doubleBitsToUint64(dvec2);"
+            "u64vec3  doubleBitsToUint64(dvec3);"
+            "u64vec4  doubleBitsToUint64(dvec4);"
+
+            "double int64BitsToDouble(int64_t);"
+            "dvec2  int64BitsToDouble(i64vec2);"
+            "dvec3  int64BitsToDouble(i64vec3);"
+            "dvec4  int64BitsToDouble(i64vec4);"
+
+            "double uint64BitsToDouble(uint64_t);"
+            "dvec2  uint64BitsToDouble(u64vec2);"
+            "dvec3  uint64BitsToDouble(u64vec3);"
+            "dvec4  uint64BitsToDouble(u64vec4);"
+
+            "int64_t  packInt2x32(ivec2);"
+            "uint64_t packUint2x32(uvec2);"
+            "ivec2    unpackInt2x32(int64_t);"
+            "uvec2    unpackUint2x32(uint64_t);"
+
+            "bvec2 lessThan(i64vec2, i64vec2);"
+            "bvec3 lessThan(i64vec3, i64vec3);"
+            "bvec4 lessThan(i64vec4, i64vec4);"
+            "bvec2 lessThan(u64vec2, u64vec2);"
+            "bvec3 lessThan(u64vec3, u64vec3);"
+            "bvec4 lessThan(u64vec4, u64vec4);"
+
+            "bvec2 lessThanEqual(i64vec2, i64vec2);"
+            "bvec3 lessThanEqual(i64vec3, i64vec3);"
+            "bvec4 lessThanEqual(i64vec4, i64vec4);"
+            "bvec2 lessThanEqual(u64vec2, u64vec2);"
+            "bvec3 lessThanEqual(u64vec3, u64vec3);"
+            "bvec4 lessThanEqual(u64vec4, u64vec4);"
+
+            "bvec2 greaterThan(i64vec2, i64vec2);"
+            "bvec3 greaterThan(i64vec3, i64vec3);"
+            "bvec4 greaterThan(i64vec4, i64vec4);"
+            "bvec2 greaterThan(u64vec2, u64vec2);"
+            "bvec3 greaterThan(u64vec3, u64vec3);"
+            "bvec4 greaterThan(u64vec4, u64vec4);"
+
+            "bvec2 greaterThanEqual(i64vec2, i64vec2);"
+            "bvec3 greaterThanEqual(i64vec3, i64vec3);"
+            "bvec4 greaterThanEqual(i64vec4, i64vec4);"
+            "bvec2 greaterThanEqual(u64vec2, u64vec2);"
+            "bvec3 greaterThanEqual(u64vec3, u64vec3);"
+            "bvec4 greaterThanEqual(u64vec4, u64vec4);"
+
+            "bvec2 equal(i64vec2, i64vec2);"
+            "bvec3 equal(i64vec3, i64vec3);"
+            "bvec4 equal(i64vec4, i64vec4);"
+            "bvec2 equal(u64vec2, u64vec2);"
+            "bvec3 equal(u64vec3, u64vec3);"
+            "bvec4 equal(u64vec4, u64vec4);"
+
+            "bvec2 notEqual(i64vec2, i64vec2);"
+            "bvec3 notEqual(i64vec3, i64vec3);"
+            "bvec4 notEqual(i64vec4, i64vec4);"
+            "bvec2 notEqual(u64vec2, u64vec2);"
+            "bvec3 notEqual(u64vec3, u64vec3);"
+            "bvec4 notEqual(u64vec4, u64vec4);"
+
+#ifdef AMD_EXTENSIONS
+            "int   findLSB(int64_t);"
+            "ivec2 findLSB(i64vec2);"
+            "ivec3 findLSB(i64vec3);"
+            "ivec4 findLSB(i64vec4);"
+
+            "int   findLSB(uint64_t);"
+            "ivec2 findLSB(u64vec2);"
+            "ivec3 findLSB(u64vec3);"
+            "ivec4 findLSB(u64vec4);"
+
+            "int   findMSB(int64_t);"
+            "ivec2 findMSB(i64vec2);"
+            "ivec3 findMSB(i64vec3);"
+            "ivec4 findMSB(i64vec4);"
+
+            "int   findMSB(uint64_t);"
+            "ivec2 findMSB(u64vec2);"
+            "ivec3 findMSB(u64vec3);"
+            "ivec4 findMSB(u64vec4);"
+#endif
+            "\n"
+        );
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_trinary_minmax
+    if (profile != EEsProfile && version >= 430) {
+        commonBuiltins.append(
+            "float min3(float, float, float);"
+            "vec2  min3(vec2,  vec2,  vec2);"
+            "vec3  min3(vec3,  vec3,  vec3);"
+            "vec4  min3(vec4,  vec4,  vec4);"
+
+            "int   min3(int,   int,   int);"
+            "ivec2 min3(ivec2, ivec2, ivec2);"
+            "ivec3 min3(ivec3, ivec3, ivec3);"
+            "ivec4 min3(ivec4, ivec4, ivec4);"
+
+            "uint  min3(uint,  uint,  uint);"
+            "uvec2 min3(uvec2, uvec2, uvec2);"
+            "uvec3 min3(uvec3, uvec3, uvec3);"
+            "uvec4 min3(uvec4, uvec4, uvec4);"
+
+            "float max3(float, float, float);"
+            "vec2  max3(vec2,  vec2,  vec2);"
+            "vec3  max3(vec3,  vec3,  vec3);"
+            "vec4  max3(vec4,  vec4,  vec4);"
+
+            "int   max3(int,   int,   int);"
+            "ivec2 max3(ivec2, ivec2, ivec2);"
+            "ivec3 max3(ivec3, ivec3, ivec3);"
+            "ivec4 max3(ivec4, ivec4, ivec4);"
+
+            "uint  max3(uint,  uint,  uint);"
+            "uvec2 max3(uvec2, uvec2, uvec2);"
+            "uvec3 max3(uvec3, uvec3, uvec3);"
+            "uvec4 max3(uvec4, uvec4, uvec4);"
+
+            "float mid3(float, float, float);"
+            "vec2  mid3(vec2,  vec2,  vec2);"
+            "vec3  mid3(vec3,  vec3,  vec3);"
+            "vec4  mid3(vec4,  vec4,  vec4);"
+
+            "int   mid3(int,   int,   int);"
+            "ivec2 mid3(ivec2, ivec2, ivec2);"
+            "ivec3 mid3(ivec3, ivec3, ivec3);"
+            "ivec4 mid3(ivec4, ivec4, ivec4);"
+
+            "uint  mid3(uint,  uint,  uint);"
+            "uvec2 mid3(uvec2, uvec2, uvec2);"
+            "uvec3 mid3(uvec3, uvec3, uvec3);"
+            "uvec4 mid3(uvec4, uvec4, uvec4);"
+
+            "float16_t min3(float16_t, float16_t, float16_t);"
+            "f16vec2   min3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   min3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   min3(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t max3(float16_t, float16_t, float16_t);"
+            "f16vec2   max3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   max3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   max3(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t mid3(float16_t, float16_t, float16_t);"
+            "f16vec2   mid3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   mid3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   mid3(f16vec4,   f16vec4,   f16vec4);"
+
+            "\n"
+        );
+    }
+#endif
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 430)) {
+        commonBuiltins.append(
+            "uint atomicAdd(coherent volatile inout uint, uint);"
+            " int atomicAdd(coherent volatile inout  int,  int);"
+
+            "uint atomicMin(coherent volatile inout uint, uint);"
+            " int atomicMin(coherent volatile inout  int,  int);"
+
+            "uint atomicMax(coherent volatile inout uint, uint);"
+            " int atomicMax(coherent volatile inout  int,  int);"
+
+            "uint atomicAnd(coherent volatile inout uint, uint);"
+            " int atomicAnd(coherent volatile inout  int,  int);"
+
+            "uint atomicOr (coherent volatile inout uint, uint);"
+            " int atomicOr (coherent volatile inout  int,  int);"
+
+            "uint atomicXor(coherent volatile inout uint, uint);"
+            " int atomicXor(coherent volatile inout  int,  int);"
+
+            "uint atomicExchange(coherent volatile inout uint, uint);"
+            " int atomicExchange(coherent volatile inout  int,  int);"
+
+            "uint atomicCompSwap(coherent volatile inout uint, uint, uint);"
+            " int atomicCompSwap(coherent volatile inout  int,  int,  int);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 450)) {
+        commonBuiltins.append(
+            "int    mix(int    x, int    y, bool  a);"
+            "ivec2  mix(ivec2  x, ivec2  y, bvec2 a);"
+            "ivec3  mix(ivec3  x, ivec3  y, bvec3 a);"
+            "ivec4  mix(ivec4  x, ivec4  y, bvec4 a);"
+
+            "uint   mix(uint   x, uint   y, bool  a);"
+            "uvec2  mix(uvec2  x, uvec2  y, bvec2 a);"
+            "uvec3  mix(uvec3  x, uvec3  y, bvec3 a);"
+            "uvec4  mix(uvec4  x, uvec4  y, bvec4 a);"
+
+            "bool   mix(bool   x, bool   y, bool  a);"
+            "bvec2  mix(bvec2  x, bvec2  y, bvec2 a);"
+            "bvec3  mix(bvec3  x, bvec3  y, bvec3 a);"
+            "bvec4  mix(bvec4  x, bvec4  y, bvec4 a);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 330)) {
+        commonBuiltins.append(
+            "int   floatBitsToInt(highp float value);"
+            "ivec2 floatBitsToInt(highp vec2  value);"
+            "ivec3 floatBitsToInt(highp vec3  value);"
+            "ivec4 floatBitsToInt(highp vec4  value);"
+
+            "uint  floatBitsToUint(highp float value);"
+            "uvec2 floatBitsToUint(highp vec2  value);"
+            "uvec3 floatBitsToUint(highp vec3  value);"
+            "uvec4 floatBitsToUint(highp vec4  value);"
+
+            "float intBitsToFloat(highp int   value);"
+            "vec2  intBitsToFloat(highp ivec2 value);"
+            "vec3  intBitsToFloat(highp ivec3 value);"
+            "vec4  intBitsToFloat(highp ivec4 value);"
+
+            "float uintBitsToFloat(highp uint  value);"
+            "vec2  uintBitsToFloat(highp uvec2 value);"
+            "vec3  uintBitsToFloat(highp uvec3 value);"
+            "vec4  uintBitsToFloat(highp uvec4 value);"
+
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 400) ||
+        (profile == EEsProfile && version >= 310)) {    // GL_OES_gpu_shader5
+
+        commonBuiltins.append(
+            "float  fma(float,  float,  float );"
+            "vec2   fma(vec2,   vec2,   vec2  );"
+            "vec3   fma(vec3,   vec3,   vec3  );"
+            "vec4   fma(vec4,   vec4,   vec4  );"
+            "\n");
+
+        if (profile != EEsProfile) {
+            commonBuiltins.append(
+                "double fma(double, double, double);"
+                "dvec2  fma(dvec2,  dvec2,  dvec2 );"
+                "dvec3  fma(dvec3,  dvec3,  dvec3 );"
+                "dvec4  fma(dvec4,  dvec4,  dvec4 );"
+                "\n");
+        }
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "float frexp(highp float, out highp int);"
+            "vec2  frexp(highp vec2,  out highp ivec2);"
+            "vec3  frexp(highp vec3,  out highp ivec3);"
+            "vec4  frexp(highp vec4,  out highp ivec4);"
+
+            "float ldexp(highp float, highp int);"
+            "vec2  ldexp(highp vec2,  highp ivec2);"
+            "vec3  ldexp(highp vec3,  highp ivec3);"
+            "vec4  ldexp(highp vec4,  highp ivec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "double frexp(double, out int);"
+            "dvec2  frexp( dvec2, out ivec2);"
+            "dvec3  frexp( dvec3, out ivec3);"
+            "dvec4  frexp( dvec4, out ivec4);"
+
+            "double ldexp(double, int);"
+            "dvec2  ldexp( dvec2, ivec2);"
+            "dvec3  ldexp( dvec3, ivec3);"
+            "dvec4  ldexp( dvec4, ivec4);"
+
+            "double packDouble2x32(uvec2);"
+            "uvec2 unpackDouble2x32(double);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "highp uint packUnorm2x16(vec2);"
+                  "vec2 unpackUnorm2x16(highp uint);"
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 420)) {
+        commonBuiltins.append(
+            "highp uint packSnorm2x16(vec2);"
+            "      vec2 unpackSnorm2x16(highp uint);"
+            "highp uint packHalf2x16(vec2);"
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 300) {
+        commonBuiltins.append(
+            "mediump vec2 unpackHalf2x16(highp uint);"
+            "\n");
+    } else if (profile != EEsProfile && version >= 420) {
+        commonBuiltins.append(
+            "        vec2 unpackHalf2x16(highp uint);"
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "highp uint packSnorm4x8(vec4);"
+            "highp uint packUnorm4x8(vec4);"
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "mediump vec4 unpackSnorm4x8(highp uint);"
+            "mediump vec4 unpackUnorm4x8(highp uint);"
+            "\n");
+    } else if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+                    "vec4 unpackSnorm4x8(highp uint);"
+                    "vec4 unpackUnorm4x8(highp uint);"
+            "\n");
+    }
+
+    //
+    // Geometric Functions.
+    //
+    commonBuiltins.append(
+        "float length(float x);"
+        "float length(vec2  x);"
+        "float length(vec3  x);"
+        "float length(vec4  x);"
+
+        "float distance(float p0, float p1);"
+        "float distance(vec2  p0, vec2  p1);"
+        "float distance(vec3  p0, vec3  p1);"
+        "float distance(vec4  p0, vec4  p1);"
+
+        "float dot(float x, float y);"
+        "float dot(vec2  x, vec2  y);"
+        "float dot(vec3  x, vec3  y);"
+        "float dot(vec4  x, vec4  y);"
+
+        "vec3 cross(vec3 x, vec3 y);"
+        "float normalize(float x);"
+        "vec2  normalize(vec2  x);"
+        "vec3  normalize(vec3  x);"
+        "vec4  normalize(vec4  x);"
+
+        "float faceforward(float N, float I, float Nref);"
+        "vec2  faceforward(vec2  N, vec2  I, vec2  Nref);"
+        "vec3  faceforward(vec3  N, vec3  I, vec3  Nref);"
+        "vec4  faceforward(vec4  N, vec4  I, vec4  Nref);"
+
+        "float reflect(float I, float N);"
+        "vec2  reflect(vec2  I, vec2  N);"
+        "vec3  reflect(vec3  I, vec3  N);"
+        "vec4  reflect(vec4  I, vec4  N);"
+
+        "float refract(float I, float N, float eta);"
+        "vec2  refract(vec2  I, vec2  N, float eta);"
+        "vec3  refract(vec3  I, vec3  N, float eta);"
+        "vec4  refract(vec4  I, vec4  N, float eta);"
+
+        "\n");
+
+    //
+    // Matrix Functions.
+    //
+    commonBuiltins.append(
+        "mat2 matrixCompMult(mat2 x, mat2 y);"
+        "mat3 matrixCompMult(mat3 x, mat3 y);"
+        "mat4 matrixCompMult(mat4 x, mat4 y);"
+
+        "\n");
+
+    // 120 is correct for both ES and desktop
+    if (version >= 120) {
+        commonBuiltins.append(
+            "mat2   outerProduct(vec2 c, vec2 r);"
+            "mat3   outerProduct(vec3 c, vec3 r);"
+            "mat4   outerProduct(vec4 c, vec4 r);"
+            "mat2x3 outerProduct(vec3 c, vec2 r);"
+            "mat3x2 outerProduct(vec2 c, vec3 r);"
+            "mat2x4 outerProduct(vec4 c, vec2 r);"
+            "mat4x2 outerProduct(vec2 c, vec4 r);"
+            "mat3x4 outerProduct(vec4 c, vec3 r);"
+            "mat4x3 outerProduct(vec3 c, vec4 r);"
+
+            "mat2   transpose(mat2   m);"
+            "mat3   transpose(mat3   m);"
+            "mat4   transpose(mat4   m);"
+            "mat2x3 transpose(mat3x2 m);"
+            "mat3x2 transpose(mat2x3 m);"
+            "mat2x4 transpose(mat4x2 m);"
+            "mat4x2 transpose(mat2x4 m);"
+            "mat3x4 transpose(mat4x3 m);"
+            "mat4x3 transpose(mat3x4 m);"
+
+            "mat2x3 matrixCompMult(mat2x3, mat2x3);"
+            "mat2x4 matrixCompMult(mat2x4, mat2x4);"
+            "mat3x2 matrixCompMult(mat3x2, mat3x2);"
+            "mat3x4 matrixCompMult(mat3x4, mat3x4);"
+            "mat4x2 matrixCompMult(mat4x2, mat4x2);"
+            "mat4x3 matrixCompMult(mat4x3, mat4x3);"
+
+            "\n");
+
+        // 150 is correct for both ES and desktop
+        if (version >= 150) {
+            commonBuiltins.append(
+                "float determinant(mat2 m);"
+                "float determinant(mat3 m);"
+                "float determinant(mat4 m);"
+
+                "mat2 inverse(mat2 m);"
+                "mat3 inverse(mat3 m);"
+                "mat4 inverse(mat4 m);"
+
+                "\n");
+        }
+    }
+
+    //
+    // Vector relational functions.
+    //
+    commonBuiltins.append(
+        "bvec2 lessThan(vec2 x, vec2 y);"
+        "bvec3 lessThan(vec3 x, vec3 y);"
+        "bvec4 lessThan(vec4 x, vec4 y);"
+
+        "bvec2 lessThan(ivec2 x, ivec2 y);"
+        "bvec3 lessThan(ivec3 x, ivec3 y);"
+        "bvec4 lessThan(ivec4 x, ivec4 y);"
+
+        "bvec2 lessThanEqual(vec2 x, vec2 y);"
+        "bvec3 lessThanEqual(vec3 x, vec3 y);"
+        "bvec4 lessThanEqual(vec4 x, vec4 y);"
+
+        "bvec2 lessThanEqual(ivec2 x, ivec2 y);"
+        "bvec3 lessThanEqual(ivec3 x, ivec3 y);"
+        "bvec4 lessThanEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 greaterThan(vec2 x, vec2 y);"
+        "bvec3 greaterThan(vec3 x, vec3 y);"
+        "bvec4 greaterThan(vec4 x, vec4 y);"
+
+        "bvec2 greaterThan(ivec2 x, ivec2 y);"
+        "bvec3 greaterThan(ivec3 x, ivec3 y);"
+        "bvec4 greaterThan(ivec4 x, ivec4 y);"
+
+        "bvec2 greaterThanEqual(vec2 x, vec2 y);"
+        "bvec3 greaterThanEqual(vec3 x, vec3 y);"
+        "bvec4 greaterThanEqual(vec4 x, vec4 y);"
+
+        "bvec2 greaterThanEqual(ivec2 x, ivec2 y);"
+        "bvec3 greaterThanEqual(ivec3 x, ivec3 y);"
+        "bvec4 greaterThanEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 equal(vec2 x, vec2 y);"
+        "bvec3 equal(vec3 x, vec3 y);"
+        "bvec4 equal(vec4 x, vec4 y);"
+
+        "bvec2 equal(ivec2 x, ivec2 y);"
+        "bvec3 equal(ivec3 x, ivec3 y);"
+        "bvec4 equal(ivec4 x, ivec4 y);"
+
+        "bvec2 equal(bvec2 x, bvec2 y);"
+        "bvec3 equal(bvec3 x, bvec3 y);"
+        "bvec4 equal(bvec4 x, bvec4 y);"
+
+        "bvec2 notEqual(vec2 x, vec2 y);"
+        "bvec3 notEqual(vec3 x, vec3 y);"
+        "bvec4 notEqual(vec4 x, vec4 y);"
+
+        "bvec2 notEqual(ivec2 x, ivec2 y);"
+        "bvec3 notEqual(ivec3 x, ivec3 y);"
+        "bvec4 notEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 notEqual(bvec2 x, bvec2 y);"
+        "bvec3 notEqual(bvec3 x, bvec3 y);"
+        "bvec4 notEqual(bvec4 x, bvec4 y);"
+
+        "bool any(bvec2 x);"
+        "bool any(bvec3 x);"
+        "bool any(bvec4 x);"
+
+        "bool all(bvec2 x);"
+        "bool all(bvec3 x);"
+        "bool all(bvec4 x);"
+
+        "bvec2 not(bvec2 x);"
+        "bvec3 not(bvec3 x);"
+        "bvec4 not(bvec4 x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "bvec2 lessThan(uvec2 x, uvec2 y);"
+            "bvec3 lessThan(uvec3 x, uvec3 y);"
+            "bvec4 lessThan(uvec4 x, uvec4 y);"
+
+            "bvec2 lessThanEqual(uvec2 x, uvec2 y);"
+            "bvec3 lessThanEqual(uvec3 x, uvec3 y);"
+            "bvec4 lessThanEqual(uvec4 x, uvec4 y);"
+
+            "bvec2 greaterThan(uvec2 x, uvec2 y);"
+            "bvec3 greaterThan(uvec3 x, uvec3 y);"
+            "bvec4 greaterThan(uvec4 x, uvec4 y);"
+
+            "bvec2 greaterThanEqual(uvec2 x, uvec2 y);"
+            "bvec3 greaterThanEqual(uvec3 x, uvec3 y);"
+            "bvec4 greaterThanEqual(uvec4 x, uvec4 y);"
+
+            "bvec2 equal(uvec2 x, uvec2 y);"
+            "bvec3 equal(uvec3 x, uvec3 y);"
+            "bvec4 equal(uvec4 x, uvec4 y);"
+
+            "bvec2 notEqual(uvec2 x, uvec2 y);"
+            "bvec3 notEqual(uvec3 x, uvec3 y);"
+            "bvec4 notEqual(uvec4 x, uvec4 y);"
+
+            "\n");
+    }
+
+    //
+    // Original-style texture functions existing in all stages.
+    // (Per-stage functions below.)
+    //
+    if ((profile == EEsProfile && version == 100) ||
+         profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture2D(sampler2D, vec2);"
+
+                "vec4 texture2DProj(sampler2D, vec3);"
+                "vec4 texture2DProj(sampler2D, vec4);"
+
+                "vec4 texture3D(sampler3D, vec3);"     // OES_texture_3D, but caught by keyword check
+                "vec4 texture3DProj(sampler3D, vec4);" // OES_texture_3D, but caught by keyword check
+
+                "vec4 textureCube(samplerCube, vec3);"
+
+                "\n");
+        }
+    }
+
+    if ( profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture1D(sampler1D, float);"
+
+                "vec4 texture1DProj(sampler1D, vec2);"
+                "vec4 texture1DProj(sampler1D, vec4);"
+
+                "vec4 shadow1D(sampler1DShadow, vec3);"
+                "vec4 shadow2D(sampler2DShadow, vec3);"
+                "vec4 shadow1DProj(sampler1DShadow, vec4);"
+                "vec4 shadow2DProj(sampler2DShadow, vec4);"
+
+                "vec4 texture2DRect(sampler2DRect, vec2);"          // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 texture2DRectProj(sampler2DRect, vec3);"      // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 texture2DRectProj(sampler2DRect, vec4);"      // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 shadow2DRect(sampler2DRectShadow, vec3);"     // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 shadow2DRectProj(sampler2DRectShadow, vec4);" // GL_ARB_texture_rectangle, caught by keyword check
+
+                "\n");
+        }
+    }
+
+    if (profile == EEsProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture2D(samplerExternalOES, vec2 coord);"  // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DProj(samplerExternalOES, vec3);"    // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DProj(samplerExternalOES, vec4);"    // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);"      // GL_EXT_shader_texture_lod
+                "vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);"  // GL_EXT_shader_texture_lod
+                "vec4 texture2DProjGradEXT(sampler2D, vec4, vec2, vec2);"  // GL_EXT_shader_texture_lod
+                "vec4 textureCubeGradEXT(samplerCube, vec3, vec3, vec3);"  // GL_EXT_shader_texture_lod
+
+                "\n");
+        }
+    }
+
+    //
+    // Noise functions.
+    //
+    if (profile != EEsProfile) {
+        commonBuiltins.append(
+            "float noise1(float x);"
+            "float noise1(vec2  x);"
+            "float noise1(vec3  x);"
+            "float noise1(vec4  x);"
+
+            "vec2 noise2(float x);"
+            "vec2 noise2(vec2  x);"
+            "vec2 noise2(vec3  x);"
+            "vec2 noise2(vec4  x);"
+
+            "vec3 noise3(float x);"
+            "vec3 noise3(vec2  x);"
+            "vec3 noise3(vec3  x);"
+            "vec3 noise3(vec4  x);"
+
+            "vec4 noise4(float x);"
+            "vec4 noise4(vec2  x);"
+            "vec4 noise4(vec3  x);"
+            "vec4 noise4(vec4  x);"
+
+            "\n");
+    }
+
+    if (spvVersion.vulkan == 0) {
+        //
+        // Atomic counter functions.
+        //
+        if ((profile != EEsProfile && version >= 300) ||
+            (profile == EEsProfile && version >= 310)) {
+            commonBuiltins.append(
+                "uint atomicCounterIncrement(atomic_uint x);"
+                "uint atomicCounterDecrement(atomic_uint x);"
+                "uint atomicCounter(atomic_uint x);"
+
+                "\n");
+        }
+    }
+
+    // Bitfield
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "  int bitfieldExtract(  int, int, int);"
+            "ivec2 bitfieldExtract(ivec2, int, int);"
+            "ivec3 bitfieldExtract(ivec3, int, int);"
+            "ivec4 bitfieldExtract(ivec4, int, int);"
+
+            " uint bitfieldExtract( uint, int, int);"
+            "uvec2 bitfieldExtract(uvec2, int, int);"
+            "uvec3 bitfieldExtract(uvec3, int, int);"
+            "uvec4 bitfieldExtract(uvec4, int, int);"
+
+            "  int bitfieldInsert(  int base,   int, int, int);"
+            "ivec2 bitfieldInsert(ivec2 base, ivec2, int, int);"
+            "ivec3 bitfieldInsert(ivec3 base, ivec3, int, int);"
+            "ivec4 bitfieldInsert(ivec4 base, ivec4, int, int);"
+
+            " uint bitfieldInsert( uint base,  uint, int, int);"
+            "uvec2 bitfieldInsert(uvec2 base, uvec2, int, int);"
+            "uvec3 bitfieldInsert(uvec3 base, uvec3, int, int);"
+            "uvec4 bitfieldInsert(uvec4 base, uvec4, int, int);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "  int findLSB(  int);"
+            "ivec2 findLSB(ivec2);"
+            "ivec3 findLSB(ivec3);"
+            "ivec4 findLSB(ivec4);"
+
+            "  int findLSB( uint);"
+            "ivec2 findLSB(uvec2);"
+            "ivec3 findLSB(uvec3);"
+            "ivec4 findLSB(uvec4);"
+
+            "\n");
+    } else if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "lowp   int findLSB(  int);"
+            "lowp ivec2 findLSB(ivec2);"
+            "lowp ivec3 findLSB(ivec3);"
+            "lowp ivec4 findLSB(ivec4);"
+
+            "lowp   int findLSB( uint);"
+            "lowp ivec2 findLSB(uvec2);"
+            "lowp ivec3 findLSB(uvec3);"
+            "lowp ivec4 findLSB(uvec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "  int bitCount(  int);"
+            "ivec2 bitCount(ivec2);"
+            "ivec3 bitCount(ivec3);"
+            "ivec4 bitCount(ivec4);"
+
+            "  int bitCount( uint);"
+            "ivec2 bitCount(uvec2);"
+            "ivec3 bitCount(uvec3);"
+            "ivec4 bitCount(uvec4);"
+
+            "  int findMSB(highp   int);"
+            "ivec2 findMSB(highp ivec2);"
+            "ivec3 findMSB(highp ivec3);"
+            "ivec4 findMSB(highp ivec4);"
+
+            "  int findMSB(highp  uint);"
+            "ivec2 findMSB(highp uvec2);"
+            "ivec3 findMSB(highp uvec3);"
+            "ivec4 findMSB(highp uvec4);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            " uint uaddCarry(highp  uint, highp  uint, out lowp  uint carry);"
+            "uvec2 uaddCarry(highp uvec2, highp uvec2, out lowp uvec2 carry);"
+            "uvec3 uaddCarry(highp uvec3, highp uvec3, out lowp uvec3 carry);"
+            "uvec4 uaddCarry(highp uvec4, highp uvec4, out lowp uvec4 carry);"
+
+            " uint usubBorrow(highp  uint, highp  uint, out lowp  uint borrow);"
+            "uvec2 usubBorrow(highp uvec2, highp uvec2, out lowp uvec2 borrow);"
+            "uvec3 usubBorrow(highp uvec3, highp uvec3, out lowp uvec3 borrow);"
+            "uvec4 usubBorrow(highp uvec4, highp uvec4, out lowp uvec4 borrow);"
+
+            "void umulExtended(highp  uint, highp  uint, out highp  uint, out highp  uint lsb);"
+            "void umulExtended(highp uvec2, highp uvec2, out highp uvec2, out highp uvec2 lsb);"
+            "void umulExtended(highp uvec3, highp uvec3, out highp uvec3, out highp uvec3 lsb);"
+            "void umulExtended(highp uvec4, highp uvec4, out highp uvec4, out highp uvec4 lsb);"
+
+            "void imulExtended(highp   int, highp   int, out highp   int, out highp   int lsb);"
+            "void imulExtended(highp ivec2, highp ivec2, out highp ivec2, out highp ivec2 lsb);"
+            "void imulExtended(highp ivec3, highp ivec3, out highp ivec3, out highp ivec3 lsb);"
+            "void imulExtended(highp ivec4, highp ivec4, out highp ivec4, out highp ivec4 lsb);"
+
+            "  int bitfieldReverse(highp   int);"
+            "ivec2 bitfieldReverse(highp ivec2);"
+            "ivec3 bitfieldReverse(highp ivec3);"
+            "ivec4 bitfieldReverse(highp ivec4);"
+
+            " uint bitfieldReverse(highp  uint);"
+            "uvec2 bitfieldReverse(highp uvec2);"
+            "uvec3 bitfieldReverse(highp uvec3);"
+            "uvec4 bitfieldReverse(highp uvec4);"
+
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "lowp   int bitCount(  int);"
+            "lowp ivec2 bitCount(ivec2);"
+            "lowp ivec3 bitCount(ivec3);"
+            "lowp ivec4 bitCount(ivec4);"
+
+            "lowp   int bitCount( uint);"
+            "lowp ivec2 bitCount(uvec2);"
+            "lowp ivec3 bitCount(uvec3);"
+            "lowp ivec4 bitCount(uvec4);"
+
+            "lowp   int findMSB(highp   int);"
+            "lowp ivec2 findMSB(highp ivec2);"
+            "lowp ivec3 findMSB(highp ivec3);"
+            "lowp ivec4 findMSB(highp ivec4);"
+
+            "lowp   int findMSB(highp  uint);"
+            "lowp ivec2 findMSB(highp uvec2);"
+            "lowp ivec3 findMSB(highp uvec3);"
+            "lowp ivec4 findMSB(highp uvec4);"
+
+            "\n");
+    }
+
+    // GL_ARB_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "uint64_t ballotARB(bool);"
+
+            "float readInvocationARB(float, uint);"
+            "vec2  readInvocationARB(vec2,  uint);"
+            "vec3  readInvocationARB(vec3,  uint);"
+            "vec4  readInvocationARB(vec4,  uint);"
+
+            "int   readInvocationARB(int,   uint);"
+            "ivec2 readInvocationARB(ivec2, uint);"
+            "ivec3 readInvocationARB(ivec3, uint);"
+            "ivec4 readInvocationARB(ivec4, uint);"
+
+            "uint  readInvocationARB(uint,  uint);"
+            "uvec2 readInvocationARB(uvec2, uint);"
+            "uvec3 readInvocationARB(uvec3, uint);"
+            "uvec4 readInvocationARB(uvec4, uint);"
+
+            "float readFirstInvocationARB(float);"
+            "vec2  readFirstInvocationARB(vec2);"
+            "vec3  readFirstInvocationARB(vec3);"
+            "vec4  readFirstInvocationARB(vec4);"
+
+            "int   readFirstInvocationARB(int);"
+            "ivec2 readFirstInvocationARB(ivec2);"
+            "ivec3 readFirstInvocationARB(ivec3);"
+            "ivec4 readFirstInvocationARB(ivec4);"
+
+            "uint  readFirstInvocationARB(uint);"
+            "uvec2 readFirstInvocationARB(uvec2);"
+            "uvec3 readFirstInvocationARB(uvec3);"
+            "uvec4 readFirstInvocationARB(uvec4);"
+
+            "\n");
+    }
+
+        // GL_ARB_shader_group_vote
+    if (profile != EEsProfile && version >= 430) {
+        commonBuiltins.append(
+            "bool anyInvocationARB(bool);"
+            "bool allInvocationsARB(bool);"
+            "bool allInvocationsEqualARB(bool);"
+
+            "\n");
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float minInvocationsAMD(float);"
+            "vec2  minInvocationsAMD(vec2);"
+            "vec3  minInvocationsAMD(vec3);"
+            "vec4  minInvocationsAMD(vec4);"
+
+            "int   minInvocationsAMD(int);"
+            "ivec2 minInvocationsAMD(ivec2);"
+            "ivec3 minInvocationsAMD(ivec3);"
+            "ivec4 minInvocationsAMD(ivec4);"
+
+            "uint  minInvocationsAMD(uint);"
+            "uvec2 minInvocationsAMD(uvec2);"
+            "uvec3 minInvocationsAMD(uvec3);"
+            "uvec4 minInvocationsAMD(uvec4);"
+
+            "double minInvocationsAMD(double);"
+            "dvec2  minInvocationsAMD(dvec2);"
+            "dvec3  minInvocationsAMD(dvec3);"
+            "dvec4  minInvocationsAMD(dvec4);"
+
+            "int64_t minInvocationsAMD(int64_t);"
+            "i64vec2 minInvocationsAMD(i64vec2);"
+            "i64vec3 minInvocationsAMD(i64vec3);"
+            "i64vec4 minInvocationsAMD(i64vec4);"
+
+            "uint64_t minInvocationsAMD(uint64_t);"
+            "u64vec2  minInvocationsAMD(u64vec2);"
+            "u64vec3  minInvocationsAMD(u64vec3);"
+            "u64vec4  minInvocationsAMD(u64vec4);"
+
+            "float16_t minInvocationsAMD(float16_t);"
+            "f16vec2   minInvocationsAMD(f16vec2);"
+            "f16vec3   minInvocationsAMD(f16vec3);"
+            "f16vec4   minInvocationsAMD(f16vec4);"
+
+            "float minInvocationsInclusiveScanAMD(float);"
+            "vec2  minInvocationsInclusiveScanAMD(vec2);"
+            "vec3  minInvocationsInclusiveScanAMD(vec3);"
+            "vec4  minInvocationsInclusiveScanAMD(vec4);"
+
+            "int   minInvocationsInclusiveScanAMD(int);"
+            "ivec2 minInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 minInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 minInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  minInvocationsInclusiveScanAMD(uint);"
+            "uvec2 minInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 minInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 minInvocationsInclusiveScanAMD(uvec4);"
+
+            "double minInvocationsInclusiveScanAMD(double);"
+            "dvec2  minInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3  minInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4  minInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t minInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 minInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 minInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 minInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t minInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  minInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  minInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  minInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t minInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   minInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   minInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   minInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float minInvocationsExclusiveScanAMD(float);"
+            "vec2  minInvocationsExclusiveScanAMD(vec2);"
+            "vec3  minInvocationsExclusiveScanAMD(vec3);"
+            "vec4  minInvocationsExclusiveScanAMD(vec4);"
+
+            "int   minInvocationsExclusiveScanAMD(int);"
+            "ivec2 minInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 minInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 minInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  minInvocationsExclusiveScanAMD(uint);"
+            "uvec2 minInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 minInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 minInvocationsExclusiveScanAMD(uvec4);"
+
+            "double minInvocationsExclusiveScanAMD(double);"
+            "dvec2  minInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3  minInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4  minInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t minInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 minInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 minInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 minInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t minInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  minInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  minInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  minInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t minInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   minInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   minInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   minInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float maxInvocationsAMD(float);"
+            "vec2  maxInvocationsAMD(vec2);"
+            "vec3  maxInvocationsAMD(vec3);"
+            "vec4  maxInvocationsAMD(vec4);"
+
+            "int   maxInvocationsAMD(int);"
+            "ivec2 maxInvocationsAMD(ivec2);"
+            "ivec3 maxInvocationsAMD(ivec3);"
+            "ivec4 maxInvocationsAMD(ivec4);"
+
+            "uint  maxInvocationsAMD(uint);"
+            "uvec2 maxInvocationsAMD(uvec2);"
+            "uvec3 maxInvocationsAMD(uvec3);"
+            "uvec4 maxInvocationsAMD(uvec4);"
+
+            "double maxInvocationsAMD(double);"
+            "dvec2  maxInvocationsAMD(dvec2);"
+            "dvec3  maxInvocationsAMD(dvec3);"
+            "dvec4  maxInvocationsAMD(dvec4);"
+
+            "int64_t maxInvocationsAMD(int64_t);"
+            "i64vec2 maxInvocationsAMD(i64vec2);"
+            "i64vec3 maxInvocationsAMD(i64vec3);"
+            "i64vec4 maxInvocationsAMD(i64vec4);"
+
+            "uint64_t maxInvocationsAMD(uint64_t);"
+            "u64vec2  maxInvocationsAMD(u64vec2);"
+            "u64vec3  maxInvocationsAMD(u64vec3);"
+            "u64vec4  maxInvocationsAMD(u64vec4);"
+
+            "float16_t maxInvocationsAMD(float16_t);"
+            "f16vec2   maxInvocationsAMD(f16vec2);"
+            "f16vec3   maxInvocationsAMD(f16vec3);"
+            "f16vec4   maxInvocationsAMD(f16vec4);"
+
+            "float maxInvocationsInclusiveScanAMD(float);"
+            "vec2  maxInvocationsInclusiveScanAMD(vec2);"
+            "vec3  maxInvocationsInclusiveScanAMD(vec3);"
+            "vec4  maxInvocationsInclusiveScanAMD(vec4);"
+
+            "int   maxInvocationsInclusiveScanAMD(int);"
+            "ivec2 maxInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 maxInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 maxInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  maxInvocationsInclusiveScanAMD(uint);"
+            "uvec2 maxInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 maxInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 maxInvocationsInclusiveScanAMD(uvec4);"
+
+            "double maxInvocationsInclusiveScanAMD(double);"
+            "dvec2  maxInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3  maxInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4  maxInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t maxInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 maxInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 maxInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 maxInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t maxInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  maxInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  maxInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  maxInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t maxInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   maxInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   maxInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   maxInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float maxInvocationsExclusiveScanAMD(float);"
+            "vec2  maxInvocationsExclusiveScanAMD(vec2);"
+            "vec3  maxInvocationsExclusiveScanAMD(vec3);"
+            "vec4  maxInvocationsExclusiveScanAMD(vec4);"
+
+            "int   maxInvocationsExclusiveScanAMD(int);"
+            "ivec2 maxInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 maxInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 maxInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  maxInvocationsExclusiveScanAMD(uint);"
+            "uvec2 maxInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 maxInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 maxInvocationsExclusiveScanAMD(uvec4);"
+
+            "double maxInvocationsExclusiveScanAMD(double);"
+            "dvec2  maxInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3  maxInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4  maxInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t maxInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 maxInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 maxInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 maxInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t maxInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  maxInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  maxInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  maxInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t maxInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   maxInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   maxInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   maxInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float addInvocationsAMD(float);"
+            "vec2  addInvocationsAMD(vec2);"
+            "vec3  addInvocationsAMD(vec3);"
+            "vec4  addInvocationsAMD(vec4);"
+
+            "int   addInvocationsAMD(int);"
+            "ivec2 addInvocationsAMD(ivec2);"
+            "ivec3 addInvocationsAMD(ivec3);"
+            "ivec4 addInvocationsAMD(ivec4);"
+
+            "uint  addInvocationsAMD(uint);"
+            "uvec2 addInvocationsAMD(uvec2);"
+            "uvec3 addInvocationsAMD(uvec3);"
+            "uvec4 addInvocationsAMD(uvec4);"
+
+            "double  addInvocationsAMD(double);"
+            "dvec2   addInvocationsAMD(dvec2);"
+            "dvec3   addInvocationsAMD(dvec3);"
+            "dvec4   addInvocationsAMD(dvec4);"
+
+            "int64_t addInvocationsAMD(int64_t);"
+            "i64vec2 addInvocationsAMD(i64vec2);"
+            "i64vec3 addInvocationsAMD(i64vec3);"
+            "i64vec4 addInvocationsAMD(i64vec4);"
+
+            "uint64_t addInvocationsAMD(uint64_t);"
+            "u64vec2  addInvocationsAMD(u64vec2);"
+            "u64vec3  addInvocationsAMD(u64vec3);"
+            "u64vec4  addInvocationsAMD(u64vec4);"
+
+            "float16_t addInvocationsAMD(float16_t);"
+            "f16vec2   addInvocationsAMD(f16vec2);"
+            "f16vec3   addInvocationsAMD(f16vec3);"
+            "f16vec4   addInvocationsAMD(f16vec4);"
+
+            "float addInvocationsInclusiveScanAMD(float);"
+            "vec2  addInvocationsInclusiveScanAMD(vec2);"
+            "vec3  addInvocationsInclusiveScanAMD(vec3);"
+            "vec4  addInvocationsInclusiveScanAMD(vec4);"
+
+            "int   addInvocationsInclusiveScanAMD(int);"
+            "ivec2 addInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 addInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 addInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  addInvocationsInclusiveScanAMD(uint);"
+            "uvec2 addInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 addInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 addInvocationsInclusiveScanAMD(uvec4);"
+
+            "double  addInvocationsInclusiveScanAMD(double);"
+            "dvec2   addInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3   addInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4   addInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t addInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 addInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 addInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 addInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t addInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  addInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  addInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  addInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t addInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   addInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   addInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   addInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float addInvocationsExclusiveScanAMD(float);"
+            "vec2  addInvocationsExclusiveScanAMD(vec2);"
+            "vec3  addInvocationsExclusiveScanAMD(vec3);"
+            "vec4  addInvocationsExclusiveScanAMD(vec4);"
+
+            "int   addInvocationsExclusiveScanAMD(int);"
+            "ivec2 addInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 addInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 addInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  addInvocationsExclusiveScanAMD(uint);"
+            "uvec2 addInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 addInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 addInvocationsExclusiveScanAMD(uvec4);"
+
+            "double  addInvocationsExclusiveScanAMD(double);"
+            "dvec2   addInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3   addInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4   addInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t addInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 addInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 addInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 addInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t addInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  addInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  addInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  addInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t addInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   addInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   addInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   addInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float minInvocationsNonUniformAMD(float);"
+            "vec2  minInvocationsNonUniformAMD(vec2);"
+            "vec3  minInvocationsNonUniformAMD(vec3);"
+            "vec4  minInvocationsNonUniformAMD(vec4);"
+
+            "int   minInvocationsNonUniformAMD(int);"
+            "ivec2 minInvocationsNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsNonUniformAMD(uint);"
+            "uvec2 minInvocationsNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsNonUniformAMD(uvec4);"
+
+            "double minInvocationsNonUniformAMD(double);"
+            "dvec2  minInvocationsNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsNonUniformAMD(f16vec4);"
+
+            "float minInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  minInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  minInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  minInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   minInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 minInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 minInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double minInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  minInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float minInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  minInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  minInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  minInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   minInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 minInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 minInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double minInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  minInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsNonUniformAMD(float);"
+            "vec2  maxInvocationsNonUniformAMD(vec2);"
+            "vec3  maxInvocationsNonUniformAMD(vec3);"
+            "vec4  maxInvocationsNonUniformAMD(vec4);"
+
+            "int   maxInvocationsNonUniformAMD(int);"
+            "ivec2 maxInvocationsNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsNonUniformAMD(uint);"
+            "uvec2 maxInvocationsNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsNonUniformAMD(uvec4);"
+
+            "double maxInvocationsNonUniformAMD(double);"
+            "dvec2  maxInvocationsNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  maxInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  maxInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  maxInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   maxInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 maxInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 maxInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double maxInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  maxInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  maxInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  maxInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  maxInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   maxInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 maxInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 maxInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double maxInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  maxInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float addInvocationsNonUniformAMD(float);"
+            "vec2  addInvocationsNonUniformAMD(vec2);"
+            "vec3  addInvocationsNonUniformAMD(vec3);"
+            "vec4  addInvocationsNonUniformAMD(vec4);"
+
+            "int   addInvocationsNonUniformAMD(int);"
+            "ivec2 addInvocationsNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsNonUniformAMD(uint);"
+            "uvec2 addInvocationsNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsNonUniformAMD(uvec4);"
+
+            "double addInvocationsNonUniformAMD(double);"
+            "dvec2  addInvocationsNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsNonUniformAMD(f16vec4);"
+
+            "float addInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  addInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  addInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  addInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   addInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 addInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 addInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double addInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  addInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float addInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  addInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  addInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  addInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   addInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 addInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 addInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double addInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  addInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float swizzleInvocationsAMD(float, uvec4);"
+            "vec2  swizzleInvocationsAMD(vec2,  uvec4);"
+            "vec3  swizzleInvocationsAMD(vec3,  uvec4);"
+            "vec4  swizzleInvocationsAMD(vec4,  uvec4);"
+
+            "int   swizzleInvocationsAMD(int,   uvec4);"
+            "ivec2 swizzleInvocationsAMD(ivec2, uvec4);"
+            "ivec3 swizzleInvocationsAMD(ivec3, uvec4);"
+            "ivec4 swizzleInvocationsAMD(ivec4, uvec4);"
+
+            "uint  swizzleInvocationsAMD(uint,  uvec4);"
+            "uvec2 swizzleInvocationsAMD(uvec2, uvec4);"
+            "uvec3 swizzleInvocationsAMD(uvec3, uvec4);"
+            "uvec4 swizzleInvocationsAMD(uvec4, uvec4);"
+
+            "float swizzleInvocationsMaskedAMD(float, uvec3);"
+            "vec2  swizzleInvocationsMaskedAMD(vec2,  uvec3);"
+            "vec3  swizzleInvocationsMaskedAMD(vec3,  uvec3);"
+            "vec4  swizzleInvocationsMaskedAMD(vec4,  uvec3);"
+
+            "int   swizzleInvocationsMaskedAMD(int,   uvec3);"
+            "ivec2 swizzleInvocationsMaskedAMD(ivec2, uvec3);"
+            "ivec3 swizzleInvocationsMaskedAMD(ivec3, uvec3);"
+            "ivec4 swizzleInvocationsMaskedAMD(ivec4, uvec3);"
+
+            "uint  swizzleInvocationsMaskedAMD(uint,  uvec3);"
+            "uvec2 swizzleInvocationsMaskedAMD(uvec2, uvec3);"
+            "uvec3 swizzleInvocationsMaskedAMD(uvec3, uvec3);"
+            "uvec4 swizzleInvocationsMaskedAMD(uvec4, uvec3);"
+
+            "float writeInvocationAMD(float, float, uint);"
+            "vec2  writeInvocationAMD(vec2,  vec2,  uint);"
+            "vec3  writeInvocationAMD(vec3,  vec3,  uint);"
+            "vec4  writeInvocationAMD(vec4,  vec4,  uint);"
+
+            "int   writeInvocationAMD(int,   int,   uint);"
+            "ivec2 writeInvocationAMD(ivec2, ivec2, uint);"
+            "ivec3 writeInvocationAMD(ivec3, ivec3, uint);"
+            "ivec4 writeInvocationAMD(ivec4, ivec4, uint);"
+
+            "uint  writeInvocationAMD(uint,  uint,  uint);"
+            "uvec2 writeInvocationAMD(uvec2, uvec2, uint);"
+            "uvec3 writeInvocationAMD(uvec3, uvec3, uint);"
+            "uvec4 writeInvocationAMD(uvec4, uvec4, uint);"
+
+            "uint mbcntAMD(uint64_t);"
+
+            "\n");
+    }
+
+    // GL_AMD_gcn_shader
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float cubeFaceIndexAMD(vec3);"
+            "vec2 cubeFaceCoordAMD(vec3);"
+            "uint64_t timeAMD();"
+
+            "\n");
+    }
+
+    // GL_AMD_gpu_shader_half_float
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float16_t radians(float16_t);"
+            "f16vec2   radians(f16vec2);"
+            "f16vec3   radians(f16vec3);"
+            "f16vec4   radians(f16vec4);"
+
+            "float16_t degrees(float16_t);"
+            "f16vec2   degrees(f16vec2);"
+            "f16vec3   degrees(f16vec3);"
+            "f16vec4   degrees(f16vec4);"
+
+            "float16_t sin(float16_t);"
+            "f16vec2   sin(f16vec2);"
+            "f16vec3   sin(f16vec3);"
+            "f16vec4   sin(f16vec4);"
+
+            "float16_t cos(float16_t);"
+            "f16vec2   cos(f16vec2);"
+            "f16vec3   cos(f16vec3);"
+            "f16vec4   cos(f16vec4);"
+
+            "float16_t tan(float16_t);"
+            "f16vec2   tan(f16vec2);"
+            "f16vec3   tan(f16vec3);"
+            "f16vec4   tan(f16vec4);"
+
+            "float16_t asin(float16_t);"
+            "f16vec2   asin(f16vec2);"
+            "f16vec3   asin(f16vec3);"
+            "f16vec4   asin(f16vec4);"
+
+            "float16_t acos(float16_t);"
+            "f16vec2   acos(f16vec2);"
+            "f16vec3   acos(f16vec3);"
+            "f16vec4   acos(f16vec4);"
+
+            "float16_t atan(float16_t, float16_t);"
+            "f16vec2   atan(f16vec2,   f16vec2);"
+            "f16vec3   atan(f16vec3,   f16vec3);"
+            "f16vec4   atan(f16vec4,   f16vec4);"
+
+            "float16_t atan(float16_t);"
+            "f16vec2   atan(f16vec2);"
+            "f16vec3   atan(f16vec3);"
+            "f16vec4   atan(f16vec4);"
+
+            "float16_t sinh(float16_t);"
+            "f16vec2   sinh(f16vec2);"
+            "f16vec3   sinh(f16vec3);"
+            "f16vec4   sinh(f16vec4);"
+
+            "float16_t cosh(float16_t);"
+            "f16vec2   cosh(f16vec2);"
+            "f16vec3   cosh(f16vec3);"
+            "f16vec4   cosh(f16vec4);"
+
+            "float16_t tanh(float16_t);"
+            "f16vec2   tanh(f16vec2);"
+            "f16vec3   tanh(f16vec3);"
+            "f16vec4   tanh(f16vec4);"
+
+            "float16_t asinh(float16_t);"
+            "f16vec2   asinh(f16vec2);"
+            "f16vec3   asinh(f16vec3);"
+            "f16vec4   asinh(f16vec4);"
+
+            "float16_t acosh(float16_t);"
+            "f16vec2   acosh(f16vec2);"
+            "f16vec3   acosh(f16vec3);"
+            "f16vec4   acosh(f16vec4);"
+
+            "float16_t atanh(float16_t);"
+            "f16vec2   atanh(f16vec2);"
+            "f16vec3   atanh(f16vec3);"
+            "f16vec4   atanh(f16vec4);"
+
+            "float16_t pow(float16_t, float16_t);"
+            "f16vec2   pow(f16vec2,   f16vec2);"
+            "f16vec3   pow(f16vec3,   f16vec3);"
+            "f16vec4   pow(f16vec4,   f16vec4);"
+
+            "float16_t exp(float16_t);"
+            "f16vec2   exp(f16vec2);"
+            "f16vec3   exp(f16vec3);"
+            "f16vec4   exp(f16vec4);"
+
+            "float16_t log(float16_t);"
+            "f16vec2   log(f16vec2);"
+            "f16vec3   log(f16vec3);"
+            "f16vec4   log(f16vec4);"
+
+            "float16_t exp2(float16_t);"
+            "f16vec2   exp2(f16vec2);"
+            "f16vec3   exp2(f16vec3);"
+            "f16vec4   exp2(f16vec4);"
+
+            "float16_t log2(float16_t);"
+            "f16vec2   log2(f16vec2);"
+            "f16vec3   log2(f16vec3);"
+            "f16vec4   log2(f16vec4);"
+
+            "float16_t sqrt(float16_t);"
+            "f16vec2   sqrt(f16vec2);"
+            "f16vec3   sqrt(f16vec3);"
+            "f16vec4   sqrt(f16vec4);"
+
+            "float16_t inversesqrt(float16_t);"
+            "f16vec2   inversesqrt(f16vec2);"
+            "f16vec3   inversesqrt(f16vec3);"
+            "f16vec4   inversesqrt(f16vec4);"
+
+            "float16_t abs(float16_t);"
+            "f16vec2   abs(f16vec2);"
+            "f16vec3   abs(f16vec3);"
+            "f16vec4   abs(f16vec4);"
+
+            "float16_t sign(float16_t);"
+            "f16vec2   sign(f16vec2);"
+            "f16vec3   sign(f16vec3);"
+            "f16vec4   sign(f16vec4);"
+
+            "float16_t floor(float16_t);"
+            "f16vec2   floor(f16vec2);"
+            "f16vec3   floor(f16vec3);"
+            "f16vec4   floor(f16vec4);"
+
+            "float16_t trunc(float16_t);"
+            "f16vec2   trunc(f16vec2);"
+            "f16vec3   trunc(f16vec3);"
+            "f16vec4   trunc(f16vec4);"
+
+            "float16_t round(float16_t);"
+            "f16vec2   round(f16vec2);"
+            "f16vec3   round(f16vec3);"
+            "f16vec4   round(f16vec4);"
+
+            "float16_t roundEven(float16_t);"
+            "f16vec2   roundEven(f16vec2);"
+            "f16vec3   roundEven(f16vec3);"
+            "f16vec4   roundEven(f16vec4);"
+
+            "float16_t ceil(float16_t);"
+            "f16vec2   ceil(f16vec2);"
+            "f16vec3   ceil(f16vec3);"
+            "f16vec4   ceil(f16vec4);"
+
+            "float16_t fract(float16_t);"
+            "f16vec2   fract(f16vec2);"
+            "f16vec3   fract(f16vec3);"
+            "f16vec4   fract(f16vec4);"
+
+            "float16_t mod(float16_t, float16_t);"
+            "f16vec2   mod(f16vec2,   float16_t);"
+            "f16vec3   mod(f16vec3,   float16_t);"
+            "f16vec4   mod(f16vec4,   float16_t);"
+            "f16vec2   mod(f16vec2,   f16vec2);"
+            "f16vec3   mod(f16vec3,   f16vec3);"
+            "f16vec4   mod(f16vec4,   f16vec4);"
+
+            "float16_t modf(float16_t, out float16_t);"
+            "f16vec2   modf(f16vec2,   out f16vec2);"
+            "f16vec3   modf(f16vec3,   out f16vec3);"
+            "f16vec4   modf(f16vec4,   out f16vec4);"
+
+            "float16_t min(float16_t, float16_t);"
+            "f16vec2   min(f16vec2,   float16_t);"
+            "f16vec3   min(f16vec3,   float16_t);"
+            "f16vec4   min(f16vec4,   float16_t);"
+            "f16vec2   min(f16vec2,   f16vec2);"
+            "f16vec3   min(f16vec3,   f16vec3);"
+            "f16vec4   min(f16vec4,   f16vec4);"
+
+            "float16_t max(float16_t, float16_t);"
+            "f16vec2   max(f16vec2,   float16_t);"
+            "f16vec3   max(f16vec3,   float16_t);"
+            "f16vec4   max(f16vec4,   float16_t);"
+            "f16vec2   max(f16vec2,   f16vec2);"
+            "f16vec3   max(f16vec3,   f16vec3);"
+            "f16vec4   max(f16vec4,   f16vec4);"
+
+            "float16_t clamp(float16_t, float16_t, float16_t);"
+            "f16vec2   clamp(f16vec2,   float16_t, float16_t);"
+            "f16vec3   clamp(f16vec3,   float16_t, float16_t);"
+            "f16vec4   clamp(f16vec4,   float16_t, float16_t);"
+            "f16vec2   clamp(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   clamp(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   clamp(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t mix(float16_t, float16_t, float16_t);"
+            "f16vec2   mix(f16vec2,   f16vec2,   float16_t);"
+            "f16vec3   mix(f16vec3,   f16vec3,   float16_t);"
+            "f16vec4   mix(f16vec4,   f16vec4,   float16_t);"
+            "f16vec2   mix(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   mix(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   mix(f16vec4,   f16vec4,   f16vec4);"
+            "float16_t mix(float16_t, float16_t, bool);"
+            "f16vec2   mix(f16vec2,   f16vec2,   bvec2);"
+            "f16vec3   mix(f16vec3,   f16vec3,   bvec3);"
+            "f16vec4   mix(f16vec4,   f16vec4,   bvec4);"
+
+            "float16_t step(float16_t, float16_t);"
+            "f16vec2   step(f16vec2,   f16vec2);"
+            "f16vec3   step(f16vec3,   f16vec3);"
+            "f16vec4   step(f16vec4,   f16vec4);"
+            "f16vec2   step(float16_t, f16vec2);"
+            "f16vec3   step(float16_t, f16vec3);"
+            "f16vec4   step(float16_t, f16vec4);"
+
+            "float16_t smoothstep(float16_t, float16_t, float16_t);"
+            "f16vec2   smoothstep(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   smoothstep(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   smoothstep(f16vec4,   f16vec4,   f16vec4);"
+            "f16vec2   smoothstep(float16_t, float16_t, f16vec2);"
+            "f16vec3   smoothstep(float16_t, float16_t, f16vec3);"
+            "f16vec4   smoothstep(float16_t, float16_t, f16vec4);"
+
+            "bool  isnan(float16_t);"
+            "bvec2 isnan(f16vec2);"
+            "bvec3 isnan(f16vec3);"
+            "bvec4 isnan(f16vec4);"
+
+            "bool  isinf(float16_t);"
+            "bvec2 isinf(f16vec2);"
+            "bvec3 isinf(f16vec3);"
+            "bvec4 isinf(f16vec4);"
+
+            "float16_t fma(float16_t, float16_t, float16_t);"
+            "f16vec2   fma(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   fma(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   fma(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t frexp(float16_t, out int);"
+            "f16vec2   frexp(f16vec2,   out ivec2);"
+            "f16vec3   frexp(f16vec3,   out ivec3);"
+            "f16vec4   frexp(f16vec4,   out ivec4);"
+
+            "float16_t ldexp(float16_t, in int);"
+            "f16vec2   ldexp(f16vec2,   in ivec2);"
+            "f16vec3   ldexp(f16vec3,   in ivec3);"
+            "f16vec4   ldexp(f16vec4,   in ivec4);"
+
+            "uint    packFloat2x16(f16vec2);"
+            "f16vec2 unpackFloat2x16(uint);"
+
+            "float16_t length(float16_t);"
+            "float16_t length(f16vec2);"
+            "float16_t length(f16vec3);"
+            "float16_t length(f16vec4);"
+
+            "float16_t distance(float16_t, float16_t);"
+            "float16_t distance(f16vec2,   f16vec2);"
+            "float16_t distance(f16vec3,   f16vec3);"
+            "float16_t distance(f16vec4,   f16vec4);"
+
+            "float16_t dot(float16_t, float16_t);"
+            "float16_t dot(f16vec2,   f16vec2);"
+            "float16_t dot(f16vec3,   f16vec3);"
+            "float16_t dot(f16vec4,   f16vec4);"
+
+            "f16vec3 cross(f16vec3, f16vec3);"
+
+            "float16_t normalize(float16_t);"
+            "f16vec2   normalize(f16vec2);"
+            "f16vec3   normalize(f16vec3);"
+            "f16vec4   normalize(f16vec4);"
+
+            "float16_t faceforward(float16_t, float16_t, float16_t);"
+            "f16vec2   faceforward(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   faceforward(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   faceforward(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t reflect(float16_t, float16_t);"
+            "f16vec2   reflect(f16vec2,   f16vec2);"
+            "f16vec3   reflect(f16vec3,   f16vec3);"
+            "f16vec4   reflect(f16vec4,   f16vec4);"
+
+            "float16_t refract(float16_t, float16_t, float16_t);"
+            "f16vec2   refract(f16vec2,   f16vec2,   float16_t);"
+            "f16vec3   refract(f16vec3,   f16vec3,   float16_t);"
+            "f16vec4   refract(f16vec4,   f16vec4,   float16_t);"
+
+            "f16mat2   matrixCompMult(f16mat2,   f16mat2);"
+            "f16mat3   matrixCompMult(f16mat3,   f16mat3);"
+            "f16mat4   matrixCompMult(f16mat4,   f16mat4);"
+            "f16mat2x3 matrixCompMult(f16mat2x3, f16mat2x3);"
+            "f16mat2x4 matrixCompMult(f16mat2x4, f16mat2x4);"
+            "f16mat3x2 matrixCompMult(f16mat3x2, f16mat3x2);"
+            "f16mat3x4 matrixCompMult(f16mat3x4, f16mat3x4);"
+            "f16mat4x2 matrixCompMult(f16mat4x2, f16mat4x2);"
+            "f16mat4x3 matrixCompMult(f16mat4x3, f16mat4x3);"
+
+            "f16mat2   outerProduct(f16vec2, f16vec2);"
+            "f16mat3   outerProduct(f16vec3, f16vec3);"
+            "f16mat4   outerProduct(f16vec4, f16vec4);"
+            "f16mat2x3 outerProduct(f16vec3, f16vec2);"
+            "f16mat3x2 outerProduct(f16vec2, f16vec3);"
+            "f16mat2x4 outerProduct(f16vec4, f16vec2);"
+            "f16mat4x2 outerProduct(f16vec2, f16vec4);"
+            "f16mat3x4 outerProduct(f16vec4, f16vec3);"
+            "f16mat4x3 outerProduct(f16vec3, f16vec4);"
+
+            "f16mat2   transpose(f16mat2);"
+            "f16mat3   transpose(f16mat3);"
+            "f16mat4   transpose(f16mat4);"
+            "f16mat2x3 transpose(f16mat3x2);"
+            "f16mat3x2 transpose(f16mat2x3);"
+            "f16mat2x4 transpose(f16mat4x2);"
+            "f16mat4x2 transpose(f16mat2x4);"
+            "f16mat3x4 transpose(f16mat4x3);"
+            "f16mat4x3 transpose(f16mat3x4);"
+
+            "float16_t determinant(f16mat2);"
+            "float16_t determinant(f16mat3);"
+            "float16_t determinant(f16mat4);"
+
+            "f16mat2 inverse(f16mat2);"
+            "f16mat3 inverse(f16mat3);"
+            "f16mat4 inverse(f16mat4);"
+
+            "bvec2 lessThan(f16vec2, f16vec2);"
+            "bvec3 lessThan(f16vec3, f16vec3);"
+            "bvec4 lessThan(f16vec4, f16vec4);"
+
+            "bvec2 lessThanEqual(f16vec2, f16vec2);"
+            "bvec3 lessThanEqual(f16vec3, f16vec3);"
+            "bvec4 lessThanEqual(f16vec4, f16vec4);"
+
+            "bvec2 greaterThan(f16vec2, f16vec2);"
+            "bvec3 greaterThan(f16vec3, f16vec3);"
+            "bvec4 greaterThan(f16vec4, f16vec4);"
+
+            "bvec2 greaterThanEqual(f16vec2, f16vec2);"
+            "bvec3 greaterThanEqual(f16vec3, f16vec3);"
+            "bvec4 greaterThanEqual(f16vec4, f16vec4);"
+
+            "bvec2 equal(f16vec2, f16vec2);"
+            "bvec3 equal(f16vec3, f16vec3);"
+            "bvec4 equal(f16vec4, f16vec4);"
+
+            "bvec2 notEqual(f16vec2, f16vec2);"
+            "bvec3 notEqual(f16vec3, f16vec3);"
+            "bvec4 notEqual(f16vec4, f16vec4);"
+
+            "\n");
+    }
+#endif
+
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by vertex shaders only.
+    // (Except legacy lod functions, where it depends which release they are
+    // vertex only.)
+    //
+    //============================================================================
+
+    //
+    // Geometric Functions.
+    //
+    if (IncludeLegacy(version, profile, spvVersion))
+        stageBuiltins[EShLangVertex].append("vec4 ftransform();");
+
+    //
+    // Original-style texture Functions with lod.
+    //
+    TString* s;
+    if (version == 100)
+        s = &stageBuiltins[EShLangVertex];
+    else
+        s = &commonBuiltins;
+    if ((profile == EEsProfile && version == 100) ||
+         profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            s->append(
+                "vec4 texture2DLod(sampler2D, vec2, float);"         // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjLod(sampler2D, vec3, float);"     // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjLod(sampler2D, vec4, float);"     // GL_ARB_shader_texture_lod
+                "vec4 texture3DLod(sampler3D, vec3, float);"         // GL_ARB_shader_texture_lod  // OES_texture_3D, but caught by keyword check
+                "vec4 texture3DProjLod(sampler3D, vec4, float);"     // GL_ARB_shader_texture_lod  // OES_texture_3D, but caught by keyword check
+                "vec4 textureCubeLod(samplerCube, vec3, float);"     // GL_ARB_shader_texture_lod
+
+                "\n");
+        }
+    }
+    if ( profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            s->append(
+                "vec4 texture1DLod(sampler1D, float, float);"                          // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjLod(sampler1D, vec2, float);"                       // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjLod(sampler1D, vec4, float);"                       // GL_ARB_shader_texture_lod
+                "vec4 shadow1DLod(sampler1DShadow, vec3, float);"                      // GL_ARB_shader_texture_lod
+                "vec4 shadow2DLod(sampler2DShadow, vec3, float);"                      // GL_ARB_shader_texture_lod
+                "vec4 shadow1DProjLod(sampler1DShadow, vec4, float);"                  // GL_ARB_shader_texture_lod
+                "vec4 shadow2DProjLod(sampler2DShadow, vec4, float);"                  // GL_ARB_shader_texture_lod
+
+                "vec4 texture1DGradARB(sampler1D, float, float, float);"               // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjGradARB(sampler1D, vec2, float, float);"            // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjGradARB(sampler1D, vec4, float, float);"            // GL_ARB_shader_texture_lod
+                "vec4 texture2DGradARB(sampler2D, vec2, vec2, vec2);"                  // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjGradARB(sampler2D, vec3, vec2, vec2);"              // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjGradARB(sampler2D, vec4, vec2, vec2);"              // GL_ARB_shader_texture_lod
+                "vec4 texture3DGradARB(sampler3D, vec3, vec3, vec3);"                  // GL_ARB_shader_texture_lod
+                "vec4 texture3DProjGradARB(sampler3D, vec4, vec3, vec3);"              // GL_ARB_shader_texture_lod
+                "vec4 textureCubeGradARB(samplerCube, vec3, vec3, vec3);"              // GL_ARB_shader_texture_lod
+                "vec4 shadow1DGradARB(sampler1DShadow, vec3, float, float);"           // GL_ARB_shader_texture_lod
+                "vec4 shadow1DProjGradARB( sampler1DShadow, vec4, float, float);"      // GL_ARB_shader_texture_lod
+                "vec4 shadow2DGradARB(sampler2DShadow, vec3, vec2, vec2);"             // GL_ARB_shader_texture_lod
+                "vec4 shadow2DProjGradARB( sampler2DShadow, vec4, vec2, vec2);"        // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectGradARB(sampler2DRect, vec2, vec2, vec2);"          // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectProjGradARB( sampler2DRect, vec3, vec2, vec2);"     // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectProjGradARB( sampler2DRect, vec4, vec2, vec2);"     // GL_ARB_shader_texture_lod
+                "vec4 shadow2DRectGradARB( sampler2DRectShadow, vec3, vec2, vec2);"    // GL_ARB_shader_texture_lod
+                "vec4 shadow2DRectProjGradARB(sampler2DRectShadow, vec4, vec2, vec2);" // GL_ARB_shader_texture_lod
+
+                "\n");
+        }
+    }
+
+    if ((profile != EEsProfile && version >= 150) ||
+        (profile == EEsProfile && version >= 310)) {
+        //============================================================================
+        //
+        // Prototypes for built-in functions seen by geometry shaders only.
+        //
+        //============================================================================
+
+        if (profile != EEsProfile && version >= 400) {
+            stageBuiltins[EShLangGeometry].append(
+                "void EmitStreamVertex(int);"
+                "void EndStreamPrimitive(int);"
+                );
+        }
+        stageBuiltins[EShLangGeometry].append(
+            "void EmitVertex();"
+            "void EndPrimitive();"
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Prototypes for all control functions.
+    //
+    //============================================================================
+    bool esBarrier = (profile == EEsProfile && version >= 310);
+    if ((profile != EEsProfile && version >= 150) || esBarrier)
+        stageBuiltins[EShLangTessControl].append(
+            "void barrier();"
+            );
+    if ((profile != EEsProfile && version >= 420) || esBarrier)
+        stageBuiltins[EShLangCompute].append(
+            "void barrier();"
+            );
+    if ((profile != EEsProfile && version >= 130) || esBarrier)
+        commonBuiltins.append(
+            "void memoryBarrier();"
+            );
+    if ((profile != EEsProfile && version >= 420) || esBarrier) {
+        commonBuiltins.append(
+            "void memoryBarrierAtomicCounter();"
+            "void memoryBarrierBuffer();"
+            "void memoryBarrierImage();"
+            );
+        stageBuiltins[EShLangCompute].append(
+            "void memoryBarrierShared();"
+            "void groupMemoryBarrier();"
+            );
+    }
+
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by fragment shaders only.
+    //
+    //============================================================================
+
+    //
+    // Original-style texture Functions with bias.
+    //
+    if (spvVersion.spv == 0 && (profile != EEsProfile || version == 100)) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture2D(sampler2D, vec2, float);"
+            "vec4 texture2DProj(sampler2D, vec3, float);"
+            "vec4 texture2DProj(sampler2D, vec4, float);"
+            "vec4 texture3D(sampler3D, vec3, float);"        // OES_texture_3D
+            "vec4 texture3DProj(sampler3D, vec4, float);"    // OES_texture_3D
+            "vec4 textureCube(samplerCube, vec3, float);"
+
+            "\n");
+    }
+    if (spvVersion.spv == 0 && (profile != EEsProfile && version > 100)) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture1D(sampler1D, float, float);"
+            "vec4 texture1DProj(sampler1D, vec2, float);"
+            "vec4 texture1DProj(sampler1D, vec4, float);"
+            "vec4 shadow1D(sampler1DShadow, vec3, float);"
+            "vec4 shadow2D(sampler2DShadow, vec3, float);"
+            "vec4 shadow1DProj(sampler1DShadow, vec4, float);"
+            "vec4 shadow2DProj(sampler2DShadow, vec4, float);"
+
+            "\n");
+    }
+    if (spvVersion.spv == 0 && profile == EEsProfile) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture2DLodEXT(sampler2D, vec2, float);"      // GL_EXT_shader_texture_lod
+            "vec4 texture2DProjLodEXT(sampler2D, vec3, float);"  // GL_EXT_shader_texture_lod
+            "vec4 texture2DProjLodEXT(sampler2D, vec4, float);"  // GL_EXT_shader_texture_lod
+            "vec4 textureCubeLodEXT(samplerCube, vec3, float);"  // GL_EXT_shader_texture_lod
+
+            "\n");
+    }
+
+    stageBuiltins[EShLangFragment].append(
+        "float dFdx(float p);"
+        "vec2  dFdx(vec2  p);"
+        "vec3  dFdx(vec3  p);"
+        "vec4  dFdx(vec4  p);"
+
+        "float dFdy(float p);"
+        "vec2  dFdy(vec2  p);"
+        "vec3  dFdy(vec3  p);"
+        "vec4  dFdy(vec4  p);"
+
+        "float fwidth(float p);"
+        "vec2  fwidth(vec2  p);"
+        "vec3  fwidth(vec3  p);"
+        "vec4  fwidth(vec4  p);"
+
+        "\n");
+
+    // GL_ARB_derivative_control
+    if (profile != EEsProfile && version >= 400) {
+        stageBuiltins[EShLangFragment].append(
+            "float dFdxFine(float p);"
+            "vec2  dFdxFine(vec2  p);"
+            "vec3  dFdxFine(vec3  p);"
+            "vec4  dFdxFine(vec4  p);"
+
+            "float dFdyFine(float p);"
+            "vec2  dFdyFine(vec2  p);"
+            "vec3  dFdyFine(vec3  p);"
+            "vec4  dFdyFine(vec4  p);"
+
+            "float fwidthFine(float p);"
+            "vec2  fwidthFine(vec2  p);"
+            "vec3  fwidthFine(vec3  p);"
+            "vec4  fwidthFine(vec4  p);"
+
+            "\n");
+
+        stageBuiltins[EShLangFragment].append(
+            "float dFdxCoarse(float p);"
+            "vec2  dFdxCoarse(vec2  p);"
+            "vec3  dFdxCoarse(vec3  p);"
+            "vec4  dFdxCoarse(vec4  p);"
+
+            "float dFdyCoarse(float p);"
+            "vec2  dFdyCoarse(vec2  p);"
+            "vec3  dFdyCoarse(vec3  p);"
+            "vec4  dFdyCoarse(vec4  p);"
+
+            "float fwidthCoarse(float p);"
+            "vec2  fwidthCoarse(vec2  p);"
+            "vec3  fwidthCoarse(vec3  p);"
+            "vec4  fwidthCoarse(vec4  p);"
+
+            "\n");
+    }
+
+    // GL_OES_shader_multisample_interpolation
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        stageBuiltins[EShLangFragment].append(
+            "float interpolateAtCentroid(float);"
+            "vec2  interpolateAtCentroid(vec2);"
+            "vec3  interpolateAtCentroid(vec3);"
+            "vec4  interpolateAtCentroid(vec4);"
+
+            "float interpolateAtSample(float, int);"
+            "vec2  interpolateAtSample(vec2,  int);"
+            "vec3  interpolateAtSample(vec3,  int);"
+            "vec4  interpolateAtSample(vec4,  int);"
+
+            "float interpolateAtOffset(float, vec2);"
+            "vec2  interpolateAtOffset(vec2,  vec2);"
+            "vec3  interpolateAtOffset(vec3,  vec2);"
+            "vec4  interpolateAtOffset(vec4,  vec2);"
+
+            "\n");
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_explicit_vertex_parameter
+    if (profile != EEsProfile && version >= 450) {
+        stageBuiltins[EShLangFragment].append(
+            "float interpolateAtVertexAMD(float, uint);"
+            "vec2  interpolateAtVertexAMD(vec2,  uint);"
+            "vec3  interpolateAtVertexAMD(vec3,  uint);"
+            "vec4  interpolateAtVertexAMD(vec4,  uint);"
+
+            "int   interpolateAtVertexAMD(int,   uint);"
+            "ivec2 interpolateAtVertexAMD(ivec2, uint);"
+            "ivec3 interpolateAtVertexAMD(ivec3, uint);"
+            "ivec4 interpolateAtVertexAMD(ivec4, uint);"
+
+            "uint  interpolateAtVertexAMD(uint,  uint);"
+            "uvec2 interpolateAtVertexAMD(uvec2, uint);"
+            "uvec3 interpolateAtVertexAMD(uvec3, uint);"
+            "uvec4 interpolateAtVertexAMD(uvec4, uint);"
+
+            "float16_t interpolateAtVertexAMD(float16_t, uint);"
+            "f16vec2   interpolateAtVertexAMD(f16vec2,   uint);"
+            "f16vec3   interpolateAtVertexAMD(f16vec3,   uint);"
+            "f16vec4   interpolateAtVertexAMD(f16vec4,   uint);"
+
+            "\n");
+    }
+
+    // GL_AMD_gpu_shader_half_float
+    if (profile != EEsProfile && version >= 450) {
+        stageBuiltins[EShLangFragment].append(
+            "float16_t dFdx(float16_t);"
+            "f16vec2   dFdx(f16vec2);"
+            "f16vec3   dFdx(f16vec3);"
+            "f16vec4   dFdx(f16vec4);"
+
+            "float16_t dFdy(float16_t);"
+            "f16vec2   dFdy(f16vec2);"
+            "f16vec3   dFdy(f16vec3);"
+            "f16vec4   dFdy(f16vec4);"
+
+            "float16_t dFdxFine(float16_t);"
+            "f16vec2   dFdxFine(f16vec2);"
+            "f16vec3   dFdxFine(f16vec3);"
+            "f16vec4   dFdxFine(f16vec4);"
+
+            "float16_t dFdyFine(float16_t);"
+            "f16vec2   dFdyFine(f16vec2);"
+            "f16vec3   dFdyFine(f16vec3);"
+            "f16vec4   dFdyFine(f16vec4);"
+
+            "float16_t dFdxCoarse(float16_t);"
+            "f16vec2   dFdxCoarse(f16vec2);"
+            "f16vec3   dFdxCoarse(f16vec3);"
+            "f16vec4   dFdxCoarse(f16vec4);"
+
+            "float16_t dFdyCoarse(float16_t);"
+            "f16vec2   dFdyCoarse(f16vec2);"
+            "f16vec3   dFdyCoarse(f16vec3);"
+            "f16vec4   dFdyCoarse(f16vec4);"
+
+            "float16_t fwidth(float16_t);"
+            "f16vec2   fwidth(f16vec2);"
+            "f16vec3   fwidth(f16vec3);"
+            "f16vec4   fwidth(f16vec4);"
+
+            "float16_t fwidthFine(float16_t);"
+            "f16vec2   fwidthFine(f16vec2);"
+            "f16vec3   fwidthFine(f16vec3);"
+            "f16vec4   fwidthFine(f16vec4);"
+
+            "float16_t fwidthCoarse(float16_t);"
+            "f16vec2   fwidthCoarse(f16vec2);"
+            "f16vec3   fwidthCoarse(f16vec3);"
+            "f16vec4   fwidthCoarse(f16vec4);"
+
+            "float16_t interpolateAtCentroid(float16_t);"
+            "f16vec2   interpolateAtCentroid(f16vec2);"
+            "f16vec3   interpolateAtCentroid(f16vec3);"
+            "f16vec4   interpolateAtCentroid(f16vec4);"
+
+            "float16_t interpolateAtSample(float16_t, int);"
+            "f16vec2   interpolateAtSample(f16vec2,   int);"
+            "f16vec3   interpolateAtSample(f16vec3,   int);"
+            "f16vec4   interpolateAtSample(f16vec4,   int);"
+
+            "float16_t interpolateAtOffset(float16_t, f16vec2);"
+            "f16vec2   interpolateAtOffset(f16vec2,   f16vec2);"
+            "f16vec3   interpolateAtOffset(f16vec3,   f16vec2);"
+            "f16vec4   interpolateAtOffset(f16vec4,   f16vec2);"
+
+            "\n");
+    }
+#endif
+
+    //============================================================================
+    //
+    // Standard Uniforms
+    //
+    //============================================================================
+
+    //
+    // Depth range in window coordinates, p. 33
+    //
+    if (spvVersion.spv == 0) {
+        commonBuiltins.append(
+            "struct gl_DepthRangeParameters {"
+            );
+        if (profile == EEsProfile) {
+            commonBuiltins.append(
+                "highp float near;"   // n
+                "highp float far;"    // f
+                "highp float diff;"   // f - n
+                );
+        } else {
+            commonBuiltins.append(
+                "float near;"  // n
+                "float far;"   // f
+                "float diff;"  // f - n
+                );
+        }
+
+        commonBuiltins.append(
+            "};"
+            "uniform gl_DepthRangeParameters gl_DepthRange;"
+            "\n");
+    }
+
+    if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) {
+        //
+        // Matrix state. p. 31, 32, 37, 39, 40.
+        //
+        commonBuiltins.append(
+            "uniform mat4  gl_ModelViewMatrix;"
+            "uniform mat4  gl_ProjectionMatrix;"
+            "uniform mat4  gl_ModelViewProjectionMatrix;"
+
+            //
+            // Derived matrix state that provides inverse and transposed versions
+            // of the matrices above.
+            //
+            "uniform mat3  gl_NormalMatrix;"
+
+            "uniform mat4  gl_ModelViewMatrixInverse;"
+            "uniform mat4  gl_ProjectionMatrixInverse;"
+            "uniform mat4  gl_ModelViewProjectionMatrixInverse;"
+
+            "uniform mat4  gl_ModelViewMatrixTranspose;"
+            "uniform mat4  gl_ProjectionMatrixTranspose;"
+            "uniform mat4  gl_ModelViewProjectionMatrixTranspose;"
+
+            "uniform mat4  gl_ModelViewMatrixInverseTranspose;"
+            "uniform mat4  gl_ProjectionMatrixInverseTranspose;"
+            "uniform mat4  gl_ModelViewProjectionMatrixInverseTranspose;"
+
+            //
+            // Normal scaling p. 39.
+            //
+            "uniform float gl_NormalScale;"
+
+            //
+            // Point Size, p. 66, 67.
+            //
+            "struct gl_PointParameters {"
+                "float size;"
+                "float sizeMin;"
+                "float sizeMax;"
+                "float fadeThresholdSize;"
+                "float distanceConstantAttenuation;"
+                "float distanceLinearAttenuation;"
+                "float distanceQuadraticAttenuation;"
+            "};"
+
+            "uniform gl_PointParameters gl_Point;"
+
+            //
+            // Material State p. 50, 55.
+            //
+            "struct gl_MaterialParameters {"
+                "vec4  emission;"    // Ecm
+                "vec4  ambient;"     // Acm
+                "vec4  diffuse;"     // Dcm
+                "vec4  specular;"    // Scm
+                "float shininess;"   // Srm
+            "};"
+            "uniform gl_MaterialParameters  gl_FrontMaterial;"
+            "uniform gl_MaterialParameters  gl_BackMaterial;"
+
+            //
+            // Light State p 50, 53, 55.
+            //
+            "struct gl_LightSourceParameters {"
+                "vec4  ambient;"             // Acli
+                "vec4  diffuse;"             // Dcli
+                "vec4  specular;"            // Scli
+                "vec4  position;"            // Ppli
+                "vec4  halfVector;"          // Derived: Hi
+                "vec3  spotDirection;"       // Sdli
+                "float spotExponent;"        // Srli
+                "float spotCutoff;"          // Crli
+                                                        // (range: [0.0,90.0], 180.0)
+                "float spotCosCutoff;"       // Derived: cos(Crli)
+                                                        // (range: [1.0,0.0],-1.0)
+                "float constantAttenuation;" // K0
+                "float linearAttenuation;"   // K1
+                "float quadraticAttenuation;"// K2
+            "};"
+
+            "struct gl_LightModelParameters {"
+                "vec4  ambient;"       // Acs
+            "};"
+
+            "uniform gl_LightModelParameters  gl_LightModel;"
+
+            //
+            // Derived state from products of light and material.
+            //
+            "struct gl_LightModelProducts {"
+                "vec4  sceneColor;"     // Derived. Ecm + Acm * Acs
+            "};"
+
+            "uniform gl_LightModelProducts gl_FrontLightModelProduct;"
+            "uniform gl_LightModelProducts gl_BackLightModelProduct;"
+
+            "struct gl_LightProducts {"
+                "vec4  ambient;"        // Acm * Acli
+                "vec4  diffuse;"        // Dcm * Dcli
+                "vec4  specular;"       // Scm * Scli
+            "};"
+
+            //
+            // Fog p. 161
+            //
+            "struct gl_FogParameters {"
+                "vec4  color;"
+                "float density;"
+                "float start;"
+                "float end;"
+                "float scale;"   //  1 / (gl_FogEnd - gl_FogStart)
+            "};"
+
+            "uniform gl_FogParameters gl_Fog;"
+
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the compute shader.
+    //
+    //============================================================================
+
+    if ((profile != EEsProfile && version >= 420) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangCompute].append(
+            "in    highp uvec3 gl_NumWorkGroups;"
+            "const highp uvec3 gl_WorkGroupSize = uvec3(1,1,1);"
+
+            "in highp uvec3 gl_WorkGroupID;"
+            "in highp uvec3 gl_LocalInvocationID;"
+
+            "in highp uvec3 gl_GlobalInvocationID;"
+            "in highp uint gl_LocalInvocationIndex;"
+
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the vertex shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile) {
+        if (version < 130) {
+            stageBuiltins[EShLangVertex].append(
+                "attribute vec4  gl_Color;"
+                "attribute vec4  gl_SecondaryColor;"
+                "attribute vec3  gl_Normal;"
+                "attribute vec4  gl_Vertex;"
+                "attribute vec4  gl_MultiTexCoord0;"
+                "attribute vec4  gl_MultiTexCoord1;"
+                "attribute vec4  gl_MultiTexCoord2;"
+                "attribute vec4  gl_MultiTexCoord3;"
+                "attribute vec4  gl_MultiTexCoord4;"
+                "attribute vec4  gl_MultiTexCoord5;"
+                "attribute vec4  gl_MultiTexCoord6;"
+                "attribute vec4  gl_MultiTexCoord7;"
+                "attribute float gl_FogCoord;"
+                "\n");
+        } else if (IncludeLegacy(version, profile, spvVersion)) {
+            stageBuiltins[EShLangVertex].append(
+                "in vec4  gl_Color;"
+                "in vec4  gl_SecondaryColor;"
+                "in vec3  gl_Normal;"
+                "in vec4  gl_Vertex;"
+                "in vec4  gl_MultiTexCoord0;"
+                "in vec4  gl_MultiTexCoord1;"
+                "in vec4  gl_MultiTexCoord2;"
+                "in vec4  gl_MultiTexCoord3;"
+                "in vec4  gl_MultiTexCoord4;"
+                "in vec4  gl_MultiTexCoord5;"
+                "in vec4  gl_MultiTexCoord6;"
+                "in vec4  gl_MultiTexCoord7;"
+                "in float gl_FogCoord;"
+                "\n");
+        }
+
+        if (version < 150) {
+            if (version < 130) {
+                stageBuiltins[EShLangVertex].append(
+                    "        vec4  gl_ClipVertex;"       // needs qualifier fixed later
+                    "varying vec4  gl_FrontColor;"
+                    "varying vec4  gl_BackColor;"
+                    "varying vec4  gl_FrontSecondaryColor;"
+                    "varying vec4  gl_BackSecondaryColor;"
+                    "varying vec4  gl_TexCoord[];"
+                    "varying float gl_FogFragCoord;"
+                    "\n");
+            } else if (IncludeLegacy(version, profile, spvVersion)) {
+                stageBuiltins[EShLangVertex].append(
+                    "    vec4  gl_ClipVertex;"       // needs qualifier fixed later
+                    "out vec4  gl_FrontColor;"
+                    "out vec4  gl_BackColor;"
+                    "out vec4  gl_FrontSecondaryColor;"
+                    "out vec4  gl_BackSecondaryColor;"
+                    "out vec4  gl_TexCoord[];"
+                    "out float gl_FogFragCoord;"
+                    "\n");
+            }
+            stageBuiltins[EShLangVertex].append(
+                "vec4 gl_Position;"   // needs qualifier fixed later
+                "float gl_PointSize;" // needs qualifier fixed later
+                );
+
+            if (version == 130 || version == 140)
+                stageBuiltins[EShLangVertex].append(
+                    "out float gl_ClipDistance[];"
+                    );
+        } else {
+            // version >= 150
+            stageBuiltins[EShLangVertex].append(
+                "out gl_PerVertex {"
+                    "vec4 gl_Position;"     // needs qualifier fixed later
+                    "float gl_PointSize;"   // needs qualifier fixed later
+                    "float gl_ClipDistance[];"
+                    );
+            if (IncludeLegacy(version, profile, spvVersion))
+                stageBuiltins[EShLangVertex].append(
+                    "vec4 gl_ClipVertex;"   // needs qualifier fixed later
+                    "vec4 gl_FrontColor;"
+                    "vec4 gl_BackColor;"
+                    "vec4 gl_FrontSecondaryColor;"
+                    "vec4 gl_BackSecondaryColor;"
+                    "vec4 gl_TexCoord[];"
+                    "float gl_FogFragCoord;"
+                    );
+            if (version >= 450)
+                stageBuiltins[EShLangVertex].append(
+                    "float gl_CullDistance[];"
+                    );
+            stageBuiltins[EShLangVertex].append(
+                "};"
+                "\n");
+        }
+        if (version >= 130 && spvVersion.vulkan == 0)
+            stageBuiltins[EShLangVertex].append(
+                "int gl_VertexID;"            // needs qualifier fixed later
+                );
+        if (version >= 140 && spvVersion.vulkan == 0)
+            stageBuiltins[EShLangVertex].append(
+                "int gl_InstanceID;"          // needs qualifier fixed later
+                );
+        if (spvVersion.vulkan >= 100 && version >= 140)
+            stageBuiltins[EShLangVertex].append(
+                "in int gl_VertexIndex;"
+                "in int gl_InstanceIndex;"
+                );
+        if (version >= 440) {
+            stageBuiltins[EShLangVertex].append(
+                "in int gl_BaseVertexARB;"
+                "in int gl_BaseInstanceARB;"
+                "in int gl_DrawIDARB;"
+                );
+        }
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangVertex].append(
+                "out int gl_ViewportIndex;"
+                "out int gl_Layer;"
+                "out int gl_ViewportMask[];"
+                "out int gl_SecondaryViewportMaskNV[];"
+                "out vec4 gl_SecondaryPositionNV;"
+                );
+#endif
+
+    } else {
+        // ES profile
+        if (version == 100) {
+            stageBuiltins[EShLangVertex].append(
+                "highp   vec4  gl_Position;"  // needs qualifier fixed later
+                "mediump float gl_PointSize;" // needs qualifier fixed later
+                );
+        } else {
+            if (spvVersion.vulkan == 0)
+                stageBuiltins[EShLangVertex].append(
+                    "in highp int gl_VertexID;"      // needs qualifier fixed later
+                    "in highp int gl_InstanceID;"    // needs qualifier fixed later
+                    );
+            if (spvVersion.vulkan >= 100)
+                stageBuiltins[EShLangVertex].append(
+                    "in highp int gl_VertexIndex;"
+                    "in highp int gl_InstanceIndex;"
+                    );
+            if (version < 310)
+                stageBuiltins[EShLangVertex].append(
+                    "highp vec4  gl_Position;"    // needs qualifier fixed later
+                    "highp float gl_PointSize;"   // needs qualifier fixed later
+                    );
+            else
+                stageBuiltins[EShLangVertex].append(
+                    "out gl_PerVertex {"
+                        "highp vec4  gl_Position;"    // needs qualifier fixed later
+                        "highp float gl_PointSize;"   // needs qualifier fixed later
+                    "};"
+                    );
+        }
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the geometry shader.
+    //
+    //============================================================================
+
+    if (profile == ECoreProfile || profile == ECompatibilityProfile) {
+        stageBuiltins[EShLangGeometry].append(
+            "in gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                );
+        if (profile == ECompatibilityProfile)
+            stageBuiltins[EShLangGeometry].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+                "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                "vec4 gl_SecondaryPositionNV;"
+#endif
+                );
+        stageBuiltins[EShLangGeometry].append(
+            "} gl_in[];"
+
+            "in int gl_PrimitiveIDIn;"
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                "\n");
+        if (profile == ECompatibilityProfile && version >= 400)
+            stageBuiltins[EShLangGeometry].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+                "float gl_CullDistance[];"
+                );
+        stageBuiltins[EShLangGeometry].append(
+            "};"
+
+            "out int gl_PrimitiveID;"
+            "out int gl_Layer;");
+
+        if (profile == ECompatibilityProfile && version < 400)
+            stageBuiltins[EShLangGeometry].append(
+            "out vec4 gl_ClipVertex;"
+            );
+
+        if (version >= 400)
+            stageBuiltins[EShLangGeometry].append(
+            "in int gl_InvocationID;"
+            );
+        // GL_ARB_viewport_array
+        if (version >= 150)
+            stageBuiltins[EShLangGeometry].append(
+            "out int gl_ViewportIndex;"
+            );
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+            "out int gl_ViewportMask[];"
+            "out int gl_SecondaryViewportMaskNV[];"
+            "out vec4 gl_SecondaryPositionNV;"
+            );
+#endif
+
+        stageBuiltins[EShLangGeometry].append("\n");
+    } else if (profile == EEsProfile && version >= 310) {
+        stageBuiltins[EShLangGeometry].append(
+            "in gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            "} gl_in[];"
+            "\n"
+            "in highp int gl_PrimitiveIDIn;"
+            "in highp int gl_InvocationID;"
+            "\n"
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            "};"
+            "\n"
+            "out highp int gl_PrimitiveID;"
+            "out highp int gl_Layer;"
+            "\n"
+            );
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the tessellation control shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile && version >= 150) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessControl].append(
+            "in int gl_PatchVerticesIn;"
+            "in int gl_PrimitiveID;"
+            "in int gl_InvocationID;"
+
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                );
+        if (profile == ECompatibilityProfile)
+            stageBuiltins[EShLangTessControl].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangTessControl].append(
+                "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                "int gl_ViewportIndex;"
+                "int gl_Layer;"
+                "int gl_ViewportMask[];"
+                "vec4 gl_SecondaryPositionNV;"
+                "int gl_SecondaryViewportMaskNV[];"
+#endif
+                );
+        stageBuiltins[EShLangTessControl].append(
+            "} gl_out[];"
+
+            "patch out float gl_TessLevelOuter[4];"
+            "patch out float gl_TessLevelInner[2];"
+            "\n");
+    } else {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessControl].append(
+            "in highp int gl_PatchVerticesIn;"
+            "in highp int gl_PrimitiveID;"
+            "in highp int gl_InvocationID;"
+
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+                );
+        stageBuiltins[EShLangTessControl].append(
+            "} gl_out[];"
+
+            "patch out highp float gl_TessLevelOuter[4];"
+            "patch out highp float gl_TessLevelInner[2];"
+            "patch out highp vec4 gl_BoundingBoxOES[2];"
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the tessellation evaluation shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile && version >= 150) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessEvaluation].append(
+            "in int gl_PatchVerticesIn;"
+            "in int gl_PrimitiveID;"
+            "in vec3 gl_TessCoord;"
+
+            "patch in float gl_TessLevelOuter[4];"
+            "patch in float gl_TessLevelInner[2];"
+
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+            );
+        if (version >= 400 && profile == ECompatibilityProfile)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "float gl_CullDistance[];"
+                );
+        stageBuiltins[EShLangTessEvaluation].append(
+            "};"
+            "\n");
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "out int gl_ViewportIndex;"
+                "out int gl_Layer;"
+                "out int gl_ViewportMask[];"
+                "out vec4 gl_SecondaryPositionNV;"
+                "out int gl_SecondaryViewportMaskNV[];"
+                );
+#endif
+
+    } else if (profile == EEsProfile && version >= 310) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessEvaluation].append(
+            "in highp int gl_PatchVerticesIn;"
+            "in highp int gl_PrimitiveID;"
+            "in highp vec3 gl_TessCoord;"
+
+            "patch in highp float gl_TessLevelOuter[4];"
+            "patch in highp float gl_TessLevelInner[2];"
+
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            );
+        stageBuiltins[EShLangTessEvaluation].append(
+            "};"
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the fragment shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile) {
+
+        stageBuiltins[EShLangFragment].append(
+            "vec4  gl_FragCoord;"   // needs qualifier fixed later
+            "bool  gl_FrontFacing;" // needs qualifier fixed later
+            "float gl_FragDepth;"   // needs qualifier fixed later
+            );
+        if (version >= 120)
+            stageBuiltins[EShLangFragment].append(
+                "vec2 gl_PointCoord;"  // needs qualifier fixed later
+                );
+        if (IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && version < 420))
+            stageBuiltins[EShLangFragment].append(
+                "vec4 gl_FragColor;"   // needs qualifier fixed later
+                );
+
+        if (version < 130) {
+            stageBuiltins[EShLangFragment].append(
+                "varying vec4  gl_Color;"
+                "varying vec4  gl_SecondaryColor;"
+                "varying vec4  gl_TexCoord[];"
+                "varying float gl_FogFragCoord;"
+                );
+        } else {
+            stageBuiltins[EShLangFragment].append(
+                "in float gl_ClipDistance[];"
+                );
+
+            if (IncludeLegacy(version, profile, spvVersion)) {
+                if (version < 150)
+                    stageBuiltins[EShLangFragment].append(
+                        "in float gl_FogFragCoord;"
+                        "in vec4  gl_TexCoord[];"
+                        "in vec4  gl_Color;"
+                        "in vec4  gl_SecondaryColor;"
+                        );
+                else
+                    stageBuiltins[EShLangFragment].append(
+                        "in gl_PerFragment {"
+                            "in float gl_FogFragCoord;"
+                            "in vec4  gl_TexCoord[];"
+                            "in vec4  gl_Color;"
+                            "in vec4  gl_SecondaryColor;"
+                        "};"
+                        );
+            }
+        }
+
+        if (version >= 150)
+            stageBuiltins[EShLangFragment].append(
+                "flat in int gl_PrimitiveID;"
+                );
+
+        if (version >= 400) {
+            stageBuiltins[EShLangFragment].append(
+                "flat in  int  gl_SampleID;"
+                "     in  vec2 gl_SamplePosition;"
+                "flat in  int  gl_SampleMaskIn[];"
+                "     out int  gl_SampleMask[];"
+                );
+            if (spvVersion.spv == 0)
+                stageBuiltins[EShLangFragment].append(
+                    "uniform int gl_NumSamples;"
+                    );
+        }
+
+        if (version >= 430)
+            stageBuiltins[EShLangFragment].append(
+                "flat in int gl_Layer;"
+                "flat in int gl_ViewportIndex;"
+                );
+
+        if (version >= 450)
+            stageBuiltins[EShLangFragment].append(
+                "in float gl_CullDistance[];"
+                "bool gl_HelperInvocation;"     // needs qualifier fixed later
+                );
+
+#ifdef AMD_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangFragment].append(
+                "in vec2 gl_BaryCoordNoPerspAMD;"
+                "in vec2 gl_BaryCoordNoPerspCentroidAMD;"
+                "in vec2 gl_BaryCoordNoPerspSampleAMD;"
+                "in vec2 gl_BaryCoordSmoothAMD;"
+                "in vec2 gl_BaryCoordSmoothCentroidAMD;"
+                "in vec2 gl_BaryCoordSmoothSampleAMD;"
+                "in vec3 gl_BaryCoordPullModelAMD;"
+                );
+#endif
+    } else {
+        // ES profile
+
+        if (version == 100) {
+            stageBuiltins[EShLangFragment].append(
+                "mediump vec4 gl_FragCoord;"    // needs qualifier fixed later
+                "        bool gl_FrontFacing;"  // needs qualifier fixed later
+                "mediump vec4 gl_FragColor;"    // needs qualifier fixed later
+                "mediump vec2 gl_PointCoord;"   // needs qualifier fixed later
+                );
+        }
+        if (version >= 300) {
+            stageBuiltins[EShLangFragment].append(
+                "highp   vec4  gl_FragCoord;"    // needs qualifier fixed later
+                "        bool  gl_FrontFacing;"  // needs qualifier fixed later
+                "mediump vec2  gl_PointCoord;"   // needs qualifier fixed later
+                "highp   float gl_FragDepth;"    // needs qualifier fixed later
+                );
+        }
+        if (version >= 310) {
+            stageBuiltins[EShLangFragment].append(
+                "bool gl_HelperInvocation;"          // needs qualifier fixed later
+                "flat in highp int gl_PrimitiveID;"  // needs qualifier fixed later
+                "flat in highp int gl_Layer;"        // needs qualifier fixed later
+                );
+
+            stageBuiltins[EShLangFragment].append(  // GL_OES_sample_variables
+                "flat  in lowp     int gl_SampleID;"
+                "      in mediump vec2 gl_SamplePosition;"
+                "flat  in highp    int gl_SampleMaskIn[];"
+                "     out highp    int gl_SampleMask[];"
+                );
+            if (spvVersion.spv == 0)
+                stageBuiltins[EShLangFragment].append(  // GL_OES_sample_variables
+                    "uniform lowp int gl_NumSamples;"
+                    );
+        }
+        stageBuiltins[EShLangFragment].append(
+            "highp float gl_FragDepthEXT;"       // GL_EXT_frag_depth
+            );
+    }
+    stageBuiltins[EShLangFragment].append("\n");
+
+    if (version >= 130)
+        add2ndGenerationSamplingImaging(version, profile, spvVersion);
+
+    // GL_ARB_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "uniform uint gl_SubGroupSizeARB;"
+
+            "in uint     gl_SubGroupInvocationARB;"
+            "in uint64_t gl_SubGroupEqMaskARB;"
+            "in uint64_t gl_SubGroupGeMaskARB;"
+            "in uint64_t gl_SubGroupGtMaskARB;"
+            "in uint64_t gl_SubGroupLeMaskARB;"
+            "in uint64_t gl_SubGroupLtMaskARB;"
+
+            "\n");
+    }
+
+    // printf("%s\n", commonBuiltins.c_str());
+    // printf("%s\n", stageBuiltins[EShLangFragment].c_str());
+}
+
+//
+// Helper function for initialize(), to add the second set of names for texturing,
+// when adding context-independent built-in functions.
+//
+void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    //
+    // In this function proper, enumerate the types, then calls the next set of functions
+    // to enumerate all the uses for that type.
+    //
+
+    TBasicType bTypes[3] = { EbtFloat, EbtInt, EbtUint };
+    bool skipBuffer = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 140);
+    bool skipCubeArrayed = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 130);
+
+    // enumerate all the types
+    for (int image = 0; image <= 1; ++image) { // loop over "bool" image vs sampler
+
+        for (int shadow = 0; shadow <= 1; ++shadow) { // loop over "bool" shadow or not
+            for (int ms = 0; ms <=1; ++ms) {
+                if ((ms || image) && shadow)
+                    continue;
+                if (ms && profile != EEsProfile && version < 150)
+                    continue;
+                if (ms && image && profile == EEsProfile)
+                    continue;
+                if (ms && profile == EEsProfile && version < 310)
+                    continue;
+
+                for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not
+                    for (int dim = Esd1D; dim < EsdNumDims; ++dim) { // 1D, 2D, ..., buffer
+                        if (dim == EsdSubpass && spvVersion.vulkan == 0)
+                            continue;
+                        if (dim == EsdSubpass && (image || shadow || arrayed))
+                            continue;
+                        if ((dim == Esd1D || dim == EsdRect) && profile == EEsProfile)
+                            continue;
+                        if (dim != Esd2D && dim != EsdSubpass && ms)
+                            continue;
+                        if ((dim == Esd3D || dim == EsdRect) && arrayed)
+                            continue;
+                        if (dim == Esd3D && shadow)
+                            continue;
+                        if (dim == EsdCube && arrayed && skipCubeArrayed)
+                            continue;
+                        if (dim == EsdBuffer && skipBuffer)
+                            continue;
+                        if (dim == EsdBuffer && (shadow || arrayed || ms))
+                            continue;
+                        if (ms && arrayed && profile == EEsProfile && version < 310)
+                            continue;
+
+                        for (int bType = 0; bType < 3; ++bType) { // float, int, uint results
+
+                            if (shadow && bType > 0)
+                                continue;
+
+                            if (dim == EsdRect && version < 140 && bType > 0)
+                                continue;
+
+                            //
+                            // Now, make all the function prototypes for the type we just built...
+                            //
+
+                            TSampler sampler;
+                            if (dim == EsdSubpass) {
+                                sampler.setSubpass(bTypes[bType], ms ? true : false);
+                            } else if (image) {
+                                sampler.setImage(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false,
+                                                                                  shadow  ? true : false,
+                                                                                  ms      ? true : false);
+                            } else {
+                                sampler.set(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false,
+                                                                             shadow  ? true : false,
+                                                                             ms      ? true : false);
+                            }
+
+                            TString typeName = sampler.getString();
+
+                            if (dim == EsdSubpass) {
+                                addSubpassSampling(sampler, typeName, version, profile);
+                                continue;
+                            }
+
+                            addQueryFunctions(sampler, typeName, version, profile);
+
+                            if (image)
+                                addImageFunctions(sampler, typeName, version, profile);
+                            else {
+                                addSamplingFunctions(sampler, typeName, version, profile);
+                                addGatherFunctions(sampler, typeName, version, profile);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    //
+    // sparseTexelsResidentARB()
+    //
+
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append("bool sparseTexelsResidentARB(int code);\n");
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the query functions for the given type.
+//
+void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
+{
+    if (sampler.image && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 430)))
+        return;
+
+    //
+    // textureSize() and imageSize()
+    //
+
+    int sizeDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0) - (sampler.dim == EsdCube ? 1 : 0);
+    if (profile == EEsProfile)
+        commonBuiltins.append("highp ");
+    if (sizeDims == 1)
+        commonBuiltins.append("int");
+    else {
+        commonBuiltins.append("ivec");
+        commonBuiltins.append(postfixes[sizeDims]);
+    }
+    if (sampler.image)
+        commonBuiltins.append(" imageSize(readonly writeonly volatile coherent ");
+    else
+        commonBuiltins.append(" textureSize(");
+    commonBuiltins.append(typeName);
+    if (! sampler.image && sampler.dim != EsdRect && sampler.dim != EsdBuffer && ! sampler.ms)
+        commonBuiltins.append(",int);\n");
+    else
+        commonBuiltins.append(");\n");
+
+    //
+    // textureSamples() and imageSamples()
+    //
+
+    // GL_ARB_shader_texture_image_samples
+    // TODO: spec issue? there are no memory qualifiers; how to query a writeonly/readonly image, etc?
+    if (profile != EEsProfile && version >= 430 && sampler.ms) {
+        commonBuiltins.append("int ");
+        if (sampler.image)
+            commonBuiltins.append("imageSamples(readonly writeonly volatile coherent ");
+        else
+            commonBuiltins.append("textureSamples(");
+        commonBuiltins.append(typeName);
+        commonBuiltins.append(");\n");
+    }
+
+    //
+    // textureQueryLod(), fragment stage only
+    //
+
+    if (profile != EEsProfile && version >= 400 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
+        stageBuiltins[EShLangFragment].append("vec2 textureQueryLod(");
+        stageBuiltins[EShLangFragment].append(typeName);
+        if (dimMap[sampler.dim] == 1)
+            stageBuiltins[EShLangFragment].append(", float");
+        else {
+            stageBuiltins[EShLangFragment].append(", vec");
+            stageBuiltins[EShLangFragment].append(postfixes[dimMap[sampler.dim]]);
+        }
+        stageBuiltins[EShLangFragment].append(");\n");
+    }
+
+    //
+    // textureQueryLevels()
+    //
+
+    if (profile != EEsProfile && version >= 430 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
+        commonBuiltins.append("int textureQueryLevels(");
+        commonBuiltins.append(typeName);
+        commonBuiltins.append(");\n");
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the image access functions for the given type.
+//
+void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
+{
+    int dims = dimMap[sampler.dim];
+    // most things with an array add a dimension, except for cubemaps
+    if (sampler.arrayed && sampler.dim != EsdCube)
+        ++dims;
+
+    TString imageParams = typeName;
+    if (dims == 1)
+        imageParams.append(", int");
+    else {
+        imageParams.append(", ivec");
+        imageParams.append(postfixes[dims]);
+    }
+    if (sampler.ms)
+        imageParams.append(", int");
+
+    if (profile == EEsProfile)
+        commonBuiltins.append("highp ");
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4 imageLoad(readonly volatile coherent ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(");\n");
+
+    commonBuiltins.append("void imageStore(writeonly volatile coherent ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(", ");
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4);\n");
+
+    if (sampler.dim != Esd1D && sampler.dim != EsdBuffer && profile != EEsProfile && version >= 450) {
+        commonBuiltins.append("int sparseImageLoadARB(readonly volatile coherent ");
+        commonBuiltins.append(imageParams);
+        commonBuiltins.append(", out ");
+        commonBuiltins.append(prefixes[sampler.type]);
+        commonBuiltins.append("vec4");
+        commonBuiltins.append(");\n");
+    }
+
+    if ( profile != EEsProfile ||
+        (profile == EEsProfile && version >= 310)) {
+        if (sampler.type == EbtInt || sampler.type == EbtUint) {
+            const char* dataType = sampler.type == EbtInt ? "highp int" : "highp uint";
+
+            const int numBuiltins = 7;
+
+            static const char* atomicFunc[numBuiltins] = {
+                " imageAtomicAdd(volatile coherent ",
+                " imageAtomicMin(volatile coherent ",
+                " imageAtomicMax(volatile coherent ",
+                " imageAtomicAnd(volatile coherent ",
+                " imageAtomicOr(volatile coherent ",
+                " imageAtomicXor(volatile coherent ",
+                " imageAtomicExchange(volatile coherent "
+            };
+
+            for (size_t i = 0; i < numBuiltins; ++i) {
+                commonBuiltins.append(dataType);
+                commonBuiltins.append(atomicFunc[i]);
+                commonBuiltins.append(imageParams);
+                commonBuiltins.append(", ");
+                commonBuiltins.append(dataType);
+                commonBuiltins.append(");\n");
+            }
+
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(" imageAtomicCompSwap(volatile coherent ");
+            commonBuiltins.append(imageParams);
+            commonBuiltins.append(", ");
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(", ");
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(");\n");
+        } else {
+            // not int or uint
+            // GL_ARB_ES3_1_compatibility
+            // TODO: spec issue: are there restrictions on the kind of layout() that can be used?  what about dropping memory qualifiers?
+            if ((profile != EEsProfile && version >= 450) ||
+                (profile == EEsProfile && version >= 310)) {
+                commonBuiltins.append("float imageAtomicExchange(volatile coherent ");
+                commonBuiltins.append(imageParams);
+                commonBuiltins.append(", float);\n");
+            }
+        }
+    }
+}
+
+//
+// Helper function for initialize(),
+// when adding context-independent built-in functions.
+//
+// Add all the subpass access functions for the given type.
+//
+void TBuiltIns::addSubpassSampling(TSampler sampler, TString& typeName, int /*version*/, EProfile /*profile*/)
+{
+    stageBuiltins[EShLangFragment].append(prefixes[sampler.type]);
+    stageBuiltins[EShLangFragment].append("vec4 subpassLoad");
+    stageBuiltins[EShLangFragment].append("(");
+    stageBuiltins[EShLangFragment].append(typeName.c_str());
+    if (sampler.ms)
+        stageBuiltins[EShLangFragment].append(", int");
+    stageBuiltins[EShLangFragment].append(");\n");
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the texture lookup functions for the given type.
+//
+void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
+{
+    //
+    // texturing
+    //
+    for (int proj = 0; proj <= 1; ++proj) { // loop over "bool" projective or not
+
+        if (proj && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.arrayed || sampler.ms))
+            continue;
+
+        for (int lod = 0; lod <= 1; ++lod) {
+
+            if (lod && (sampler.dim == EsdBuffer || sampler.dim == EsdRect || sampler.ms))
+                continue;
+            if (lod && sampler.dim == Esd2D && sampler.arrayed && sampler.shadow)
+                continue;
+            if (lod && sampler.dim == EsdCube && sampler.shadow)
+                continue;
+
+            for (int bias = 0; bias <= 1; ++bias) {
+
+                if (bias && (lod || sampler.ms))
+                    continue;
+                if (bias && sampler.dim == Esd2D && sampler.shadow && sampler.arrayed)
+                    continue;
+                if (bias && (sampler.dim == EsdRect || sampler.dim == EsdBuffer))
+                    continue;
+
+                for (int offset = 0; offset <= 1; ++offset) { // loop over "bool" offset or not
+
+                    if (proj + offset + bias + lod > 3)
+                        continue;
+                    if (offset && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.ms))
+                        continue;
+
+                    for (int fetch = 0; fetch <= 1; ++fetch) { // loop over "bool" fetch or not
+
+                        if (proj + offset + fetch + bias + lod > 3)
+                            continue;
+                        if (fetch && (lod || bias))
+                            continue;
+                        if (fetch && (sampler.shadow || sampler.dim == EsdCube))
+                            continue;
+                        if (fetch == 0 && (sampler.ms || sampler.dim == EsdBuffer))
+                            continue;
+
+                        for (int grad = 0; grad <= 1; ++grad) { // loop over "bool" grad or not
+
+                            if (grad && (lod || bias || sampler.ms))
+                                continue;
+                            if (grad && sampler.dim == EsdBuffer)
+                                continue;
+                            if (proj + offset + fetch + grad + bias + lod > 3)
+                                continue;
+
+                            for (int extraProj = 0; extraProj <= 1; ++extraProj) {
+                                bool compare = false;
+                                int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                                // skip dummy unused second component for 1D non-array shadows
+                                if (sampler.shadow && totalDims < 2)
+                                    totalDims = 2;
+                                totalDims += (sampler.shadow ? 1 : 0) + proj;
+                                if (totalDims > 4 && sampler.shadow) {
+                                    compare = true;
+                                    totalDims = 4;
+                                }
+                                assert(totalDims <= 4);
+
+                                if (extraProj && ! proj)
+                                    continue;
+                                if (extraProj && (sampler.dim == Esd3D || sampler.shadow))
+                                    continue;
+
+                                for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) { // loop over "bool" lod clamp
+
+                                    if (lodClamp && (profile == EEsProfile || version < 450))
+                                        continue;
+                                    if (lodClamp && (proj || lod || fetch))
+                                        continue;
+
+                                    for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+
+                                        if (sparse && (profile == EEsProfile || version < 450))
+                                            continue;
+                                        // Sparse sampling is not for 1D/1D array texture, buffer texture, and projective texture
+                                        if (sparse && (sampler.dim == Esd1D || sampler.dim == EsdBuffer || proj))
+                                            continue;
+
+                                        TString s;
+
+                                        // return type
+                                        if (sparse)
+                                            s.append("int ");
+                                        else {
+                                            if (sampler.shadow)
+                                                s.append("float ");
+                                            else {
+                                                s.append(prefixes[sampler.type]);
+                                                s.append("vec4 ");
+                                            }
+                                        }
+
+                                        // name
+                                        if (sparse) {
+                                            if (fetch)
+                                                s.append("sparseTexel");
+                                            else
+                                                s.append("sparseTexture");
+                                        } else {
+                                            if (fetch)
+                                                s.append("texel");
+                                            else
+                                                s.append("texture");
+                                        }
+                                        if (proj)
+                                            s.append("Proj");
+                                        if (lod)
+                                            s.append("Lod");
+                                        if (grad)
+                                            s.append("Grad");
+                                        if (fetch)
+                                            s.append("Fetch");
+                                        if (offset)
+                                            s.append("Offset");
+                                        if (lodClamp)
+                                            s.append("Clamp");
+                                        if (lodClamp || sparse)
+                                            s.append("ARB");
+                                        s.append("(");
+
+                                        // sampler type
+                                        s.append(typeName);
+
+                                        // P coordinate
+                                        if (extraProj)
+                                            s.append(",vec4");
+                                        else {
+                                            s.append(",");
+                                            TBasicType t = fetch ? EbtInt : EbtFloat;
+                                            if (totalDims == 1)
+                                                s.append(TType::getBasicString(t));
+                                            else {
+                                                s.append(prefixes[t]);
+                                                s.append("vec");
+                                                s.append(postfixes[totalDims]);
+                                            }
+                                        }
+
+                                        if (bias && compare)
+                                            continue;
+
+                                        // non-optional lod argument (lod that's not driven by lod loop) or sample
+                                        if ((fetch && sampler.dim != EsdBuffer && sampler.dim != EsdRect && !sampler.ms) ||
+                                            (sampler.ms && fetch))
+                                            s.append(",int");
+
+                                        // non-optional lod
+                                        if (lod)
+                                            s.append(",float");
+
+                                        // gradient arguments
+                                        if (grad) {
+                                            if (dimMap[sampler.dim] == 1)
+                                                s.append(",float,float");
+                                            else {
+                                                s.append(",vec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                                s.append(",vec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                            }
+                                        }
+
+                                        // offset
+                                        if (offset) {
+                                            if (dimMap[sampler.dim] == 1)
+                                                s.append(",int");
+                                            else {
+                                                s.append(",ivec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                            }
+                                        }
+
+                                        // non-optional compare
+                                        if (compare)
+                                            s.append(",float");
+
+                                        // lod clamp
+                                        if (lodClamp)
+                                            s.append(",float");
+
+                                        // texel out (for sparse texture)
+                                        if (sparse) {
+                                            s.append(",out ");
+                                            if (sampler.shadow)
+                                                s.append("float ");
+                                            else {
+                                                s.append(prefixes[sampler.type]);
+                                                s.append("vec4 ");
+                                            }
+                                        }
+
+                                        // optional bias
+                                        if (bias)
+                                            s.append(",float");
+
+                                        s.append(");\n");
+
+                                        // Add to the per-language set of built-ins
+
+                                        if (bias)
+                                            stageBuiltins[EShLangFragment].append(s);
+                                        else
+                                            commonBuiltins.append(s);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the texture gather functions for the given type.
+//
+void TBuiltIns::addGatherFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
+{
+    switch (sampler.dim) {
+    case Esd2D:
+    case EsdRect:
+    case EsdCube:
+        break;
+    default:
+        return;
+    }
+
+    if (sampler.ms)
+        return;
+
+    if (version < 140 && sampler.dim == EsdRect && sampler.type != EbtFloat)
+        return;
+
+    for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name:  none, Offset, and Offsets
+
+        for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument
+
+            if (comp > 0 && sampler.shadow)
+                continue;
+
+            if (offset > 0 && sampler.dim == EsdCube)
+                continue;
+
+            for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+                if (sparse && (profile == EEsProfile || version < 450))
+                    continue;
+
+                TString s;
+
+                // return type
+                if (sparse)
+                    s.append("int ");
+                else {
+                    s.append(prefixes[sampler.type]);
+                    s.append("vec4 ");
+                }
+
+                // name
+                if (sparse)
+                    s.append("sparseTextureGather");
+                else
+                    s.append("textureGather");
+                switch (offset) {
+                case 1:
+                    s.append("Offset");
+                    break;
+                case 2:
+                    s.append("Offsets");
+                default:
+                    break;
+                }
+                if (sparse)
+                    s.append("ARB");
+                s.append("(");
+
+                // sampler type argument
+                s.append(typeName);
+
+                // P coordinate argument
+                s.append(",vec");
+                int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                s.append(postfixes[totalDims]);
+
+                // refZ argument
+                if (sampler.shadow)
+                    s.append(",float");
+
+                // offset argument
+                if (offset > 0) {
+                    s.append(",ivec2");
+                    if (offset == 2)
+                        s.append("[4]");
+                }
+
+                // texel out (for sparse texture)
+                if (sparse) {
+                    s.append(",out ");
+                    s.append(prefixes[sampler.type]);
+                    s.append("vec4 ");
+                }
+
+                // comp argument
+                if (comp)
+                    s.append(",int");
+
+                s.append(");\n");
+                commonBuiltins.append(s);
+            }
+        }
+    }
+}
+
+//
+// Add context-dependent built-in functions and variables that are present
+// for the given version and profile.  All the results are put into just the
+// commonBuiltins, because it is called for just a specific stage.  So,
+// add stage-specific entries to the commonBuiltins, and only if that stage
+// was requested.
+//
+void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language)
+{
+    //
+    // Initialize the context-dependent (resource-dependent) built-in strings for parsing.
+    //
+
+    //============================================================================
+    //
+    // Standard Uniforms
+    //
+    //============================================================================
+
+    TString& s = commonBuiltins;
+    const int maxSize = 80;
+    char builtInConstant[maxSize];
+
+    //
+    // Build string of implementation dependent constants.
+    //
+
+    if (profile == EEsProfile) {
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexUniformVectors = %d;", resources.maxVertexUniformVectors);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxFragmentUniformVectors = %d;", resources.maxFragmentUniformVectors);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
+        s.append(builtInConstant);
+
+        if (version == 100) {
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVaryingVectors = %d;", resources.maxVaryingVectors);
+            s.append(builtInConstant);
+        } else {
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexOutputVectors = %d;", resources.maxVertexOutputVectors);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxFragmentInputVectors = %d;", resources.maxFragmentInputVectors);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxProgramTexelOffset = %d;", resources.maxProgramTexelOffset);
+            s.append(builtInConstant);
+        }
+
+        if (version >= 310) {
+            // geometry
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryInputComponents = %d;", resources.maxGeometryInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputComponents = %d;", resources.maxGeometryOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.maxGeometryTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputVertices = %d;", resources.maxGeometryOutputVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTotalOutputComponents = %d;", resources.maxGeometryTotalOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryUniformComponents = %d;", resources.maxGeometryUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounters = %d;", resources.maxGeometryAtomicCounters);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounterBuffers = %d;", resources.maxGeometryAtomicCounterBuffers);
+            s.append(builtInConstant);
+
+            // tessellation
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlInputComponents = %d;", resources.maxTessControlInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlOutputComponents = %d;", resources.maxTessControlOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTextureImageUnits = %d;", resources.maxTessControlTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlUniformComponents = %d;", resources.maxTessControlUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationTextureImageUnits = %d;", resources.maxTessEvaluationTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxPatchVertices = %d;", resources.maxPatchVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessGenLevel = %d;", resources.maxTessGenLevel);
+            s.append(builtInConstant);
+
+            // this is here instead of with the others in initialize(version, profile) due to the dependence on gl_MaxPatchVertices
+            if (language == EShLangTessControl || language == EShLangTessEvaluation) {
+                s.append(
+                    "in gl_PerVertex {"
+                        "highp vec4 gl_Position;"
+                        "highp float gl_PointSize;"
+#ifdef NV_EXTENSIONS
+                        "highp vec4 gl_SecondaryPositionNV;"
+#endif
+                    "} gl_in[gl_MaxPatchVertices];"
+                    "\n");
+            }
+        }
+
+    } else {
+        // non-ES profile
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxLights = %d;", resources.maxLights);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxClipPlanes = %d;", resources.maxClipPlanes);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureUnits = %d;", resources.maxTextureUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureCoords = %d;", resources.maxTextureCoords);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents);
+        s.append(builtInConstant);
+
+        if (version < 150 || ARBCompatibility) {
+            snprintf(builtInConstant, maxSize, "const int  gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats);
+            s.append(builtInConstant);
+        }
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents);
+        s.append(builtInConstant);
+
+        if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) {
+            //
+            // OpenGL'uniform' state.  Page numbers are in reference to version
+            // 1.4 of the OpenGL specification.
+            //
+
+            //
+            // Matrix state. p. 31, 32, 37, 39, 40.
+            //
+            s.append("uniform mat4  gl_TextureMatrix[gl_MaxTextureCoords];"
+
+            //
+            // Derived matrix state that provides inverse and transposed versions
+            // of the matrices above.
+            //
+                        "uniform mat4  gl_TextureMatrixInverse[gl_MaxTextureCoords];"
+
+                        "uniform mat4  gl_TextureMatrixTranspose[gl_MaxTextureCoords];"
+
+                        "uniform mat4  gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];"
+
+            //
+            // Clip planes p. 42.
+            //
+                        "uniform vec4  gl_ClipPlane[gl_MaxClipPlanes];"
+
+            //
+            // Light State p 50, 53, 55.
+            //
+                        "uniform gl_LightSourceParameters  gl_LightSource[gl_MaxLights];"
+
+            //
+            // Derived state from products of light.
+            //
+                        "uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];"
+                        "uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];"
+
+            //
+            // Texture Environment and Generation, p. 152, p. 40-42.
+            //
+                        "uniform vec4  gl_TextureEnvColor[gl_MaxTextureImageUnits];"
+                        "uniform vec4  gl_EyePlaneS[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneT[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneR[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneQ[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneS[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneT[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneR[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneQ[gl_MaxTextureCoords];");
+        }
+
+        if (version >= 130) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxClipDistances = %d;", resources.maxClipDistances);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingComponents = %d;", resources.maxVaryingComponents);
+            s.append(builtInConstant);
+
+            // GL_ARB_shading_language_420pack
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxProgramTexelOffset = %d;", resources.maxProgramTexelOffset);
+            s.append(builtInConstant);
+        }
+
+        // geometry
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryInputComponents = %d;", resources.maxGeometryInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputComponents = %d;", resources.maxGeometryOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.maxGeometryTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputVertices = %d;", resources.maxGeometryOutputVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTotalOutputComponents = %d;", resources.maxGeometryTotalOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryUniformComponents = %d;", resources.maxGeometryUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryVaryingComponents = %d;", resources.maxGeometryVaryingComponents);
+            s.append(builtInConstant);
+
+        }
+
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxVertexOutputComponents = %d;", resources.maxVertexOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentInputComponents = %d;", resources.maxFragmentInputComponents);
+            s.append(builtInConstant);
+        }
+
+        // tessellation
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlInputComponents = %d;", resources.maxTessControlInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlOutputComponents = %d;", resources.maxTessControlOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTextureImageUnits = %d;", resources.maxTessControlTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlUniformComponents = %d;", resources.maxTessControlUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationTextureImageUnits = %d;", resources.maxTessEvaluationTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessGenLevel = %d;", resources.maxTessGenLevel);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxPatchVertices = %d;", resources.maxPatchVertices);
+            s.append(builtInConstant);
+
+            // this is here instead of with the others in initialize(version, profile) due to the dependence on gl_MaxPatchVertices
+            if (language == EShLangTessControl || language == EShLangTessEvaluation) {
+                s.append(
+                    "in gl_PerVertex {"
+                        "vec4 gl_Position;"
+                        "float gl_PointSize;"
+                        "float gl_ClipDistance[];"
+                    );
+                if (profile == ECompatibilityProfile)
+                    s.append(
+                        "vec4 gl_ClipVertex;"
+                        "vec4 gl_FrontColor;"
+                        "vec4 gl_BackColor;"
+                        "vec4 gl_FrontSecondaryColor;"
+                        "vec4 gl_BackSecondaryColor;"
+                        "vec4 gl_TexCoord[];"
+                        "float gl_FogFragCoord;"
+                        );
+                if (profile != EEsProfile && version >= 450)
+                    s.append(
+                        "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                        "vec4 gl_SecondaryPositionNV;"
+#endif
+                       );
+                s.append(
+                    "} gl_in[gl_MaxPatchVertices];"
+                    "\n");
+            }
+        }
+
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxViewports = %d;", resources.maxViewports);
+            s.append(builtInConstant);
+        }
+
+        // images
+        if (version >= 130) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.maxCombinedImageUnitsAndFragmentOutputs);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.maxImageSamples);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.maxTessControlImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.maxTessEvaluationImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
+            s.append(builtInConstant);
+        }
+
+        // enhanced layouts
+        if (version >= 430) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTransformFeedbackBuffers = %d;", resources.maxTransformFeedbackBuffers);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTransformFeedbackInterleavedComponents = %d;", resources.maxTransformFeedbackInterleavedComponents);
+            s.append(builtInConstant);
+        }
+    }
+
+    // images (some in compute below)
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 130)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.maxImageUnits);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedShaderOutputResources = %d;", resources.maxCombinedShaderOutputResources);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.maxVertexImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.maxFragmentImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.maxCombinedImageUniforms);
+        s.append(builtInConstant);
+    }
+
+    // atomic counters (some in compute below)
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 420)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAtomicCounters = %d;", resources.               maxVertexAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentAtomicCounters = %d;", resources.             maxFragmentAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedAtomicCounters = %d;", resources.             maxCombinedAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxAtomicCounterBindings = %d;", resources.              maxAtomicCounterBindings);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAtomicCounterBuffers = %d;", resources.         maxVertexAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentAtomicCounterBuffers = %d;", resources.       maxFragmentAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedAtomicCounterBuffers = %d;", resources.       maxCombinedAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxAtomicCounterBufferSize = %d;", resources.            maxAtomicCounterBufferSize);
+        s.append(builtInConstant);
+    }
+    if (profile != EEsProfile && version >= 420) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounters = %d;", resources.          maxTessControlAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounters = %d;", resources.       maxTessEvaluationAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounters = %d;", resources.             maxGeometryAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounterBuffers = %d;", resources.    maxTessControlAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounterBuffers = %d;", resources. maxTessEvaluationAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounterBuffers = %d;", resources.       maxGeometryAtomicCounterBuffers);
+        s.append(builtInConstant);
+
+        s.append("\n");
+    }
+
+    // compute
+    if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) {
+        snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupCount = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupCountX,
+                                                                                                         resources.maxComputeWorkGroupCountY,
+                                                                                                         resources.maxComputeWorkGroupCountZ);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupSize = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupSizeX,
+                                                                                                        resources.maxComputeWorkGroupSizeY,
+                                                                                                        resources.maxComputeWorkGroupSizeZ);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeUniformComponents = %d;", resources.maxComputeUniformComponents);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeTextureImageUnits = %d;", resources.maxComputeTextureImageUnits);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeImageUniforms = %d;", resources.maxComputeImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeAtomicCounters = %d;", resources.maxComputeAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeAtomicCounterBuffers = %d;", resources.maxComputeAtomicCounterBuffers);
+        s.append(builtInConstant);
+
+        s.append("\n");
+    }
+
+    // GL_ARB_cull_distance
+    if (profile != EEsProfile && version >= 450) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCullDistances = %d;",                resources.maxCullDistances);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedClipAndCullDistances = %d;", resources.maxCombinedClipAndCullDistances);
+        s.append(builtInConstant);
+    }
+
+    // GL_ARB_ES3_1_compatibility
+    if ((profile != EEsProfile && version >= 450) ||
+        (profile == EEsProfile && version >= 310)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxSamples = %d;", resources.maxSamples);
+        s.append(builtInConstant);
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_gcn_shader
+    if (profile != EEsProfile && version >= 450) {
+        snprintf(builtInConstant, maxSize, "const int gl_SIMDGroupSizeAMD = 64;");
+        s.append(builtInConstant);
+    }
+#endif
+
+    s.append("\n");
+}
+
+//
+// To support special built-ins that have a special qualifier that cannot be declared textually
+// in a shader, like gl_Position.
+//
+// This lets the type of the built-in be declared textually, and then have just its qualifier be
+// updated afterward.
+//
+// Safe to call even if name is not present.
+//
+// Only use this for built-in variables that have a special qualifier in TStorageQualifier.
+// New built-in variables should use a generic (textually declarable) qualifier in
+// TStoraregQualifier and only call BuiltInVariable().
+//
+static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (symbol) {
+        TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+        symQualifier.storage = qualifier;
+        symQualifier.builtIn = builtIn;
+    }
+}
+
+//
+// To tag built-in variables with their TBuiltInVariable enum.  Use this when the
+// normal declaration text already gets the qualifier right, and all that's needed
+// is setting the builtIn field.  This should be the normal way for all new
+// built-in variables.
+//
+// If SpecialQualifier() was called, this does not need to be called.
+//
+// Safe to call even if name is not present.
+//
+static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (! symbol)
+        return;
+
+    TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+    symQualifier.builtIn = builtIn;
+}
+
+//
+// For built-in variables inside a named block.
+// SpecialQualifier() won't ever go inside a block; their member's qualifier come
+// from the qualification of the block.
+//
+// See comments above for other detail.
+//
+static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(blockName);
+    if (! symbol)
+        return;
+
+    TTypeList& structure = *symbol->getWritableType().getWritableStruct();
+    for (int i = 0; i < (int)structure.size(); ++i) {
+        if (structure[i].type->getFieldName().compare(name) == 0) {
+            structure[i].type->getQualifier().builtIn = builtIn;
+            return;
+        }
+    }
+}
+
+//
+// Finish adding/processing context-independent built-in symbols.
+// 1) Programmatically add symbols that could not be added by simple text strings above.
+// 2) Map built-in functions to operators, for those that will turn into an operation node
+//    instead of remaining a function call.
+// 3) Tag extension-related symbols added to their base version with their extensions, so
+//    that if an early version has the extension turned off, there is an error reported on use.
+//
+void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable)
+{
+    //
+    // Tag built-in variables and functions with additional qualifier and extension information
+    // that cannot be declared with the text strings.
+    //
+
+    // N.B.: a symbol should only be tagged once, and this function is called multiple times, once
+    // per stage that's used for this profile.  So
+    //  - generally, stick common ones in the fragment stage to ensure they are tagged exactly once
+    //  - for ES, which has different precisions for different stages, the coarsest-grained tagging
+    //    for a built-in used in many stages needs to be once for the fragment stage and once for
+    //    the vertex stage
+
+    switch(language) {
+    case EShLangVertex:
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_BaseVertexARB",   1, &E_GL_ARB_shader_draw_parameters);
+            symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters);
+            symbolTable.setVariableExtensions("gl_DrawIDARB",       1, &E_GL_ARB_shader_draw_parameters);
+
+            BuiltInVariable("gl_BaseVertexARB",   EbvBaseVertex,   symbolTable);
+            BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable);
+            BuiltInVariable("gl_DrawIDARB",       EbvDrawId,       symbolTable);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_SubGroupSizeARB",       1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupGeMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupGtMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupLeMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupLtMaskARB",     1, &E_GL_ARB_shader_ballot);
+
+            symbolTable.setFunctionExtensions("ballotARB",              1, &E_GL_ARB_shader_ballot);
+            symbolTable.setFunctionExtensions("readInvocationARB",      1, &E_GL_ARB_shader_ballot);
+            symbolTable.setFunctionExtensions("readFirstInvocationARB", 1, &E_GL_ARB_shader_ballot);
+
+            BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable);
+            BuiltInVariable("gl_SubGroupEqMaskARB",     EbvSubGroupEqMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupGeMaskARB",     EbvSubGroupGeMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupGtMaskARB",     EbvSubGroupGtMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupLeMaskARB",     EbvSubGroupLeMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupLtMaskARB",     EbvSubGroupLtMask,     symbolTable);
+
+            if (spvVersion.vulkan >= 100)
+                // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan
+                SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable);
+
+            symbolTable.setFunctionExtensions("anyInvocationARB",       1, &E_GL_ARB_shader_group_vote);
+            symbolTable.setFunctionExtensions("allInvocationsARB",      1, &E_GL_ARB_shader_group_vote);
+            symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote);
+        }
+
+#ifdef AMD_EXTENSIONS
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("minInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("swizzleInvocationsAMD",            1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("swizzleInvocationsWithPatternAMD", 1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("writeInvocationAMD",               1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("mbcntAMD",                         1, &E_GL_AMD_shader_ballot);
+
+            symbolTable.setFunctionExtensions("minInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("min3", 1, &E_GL_AMD_shader_trinary_minmax);
+            symbolTable.setFunctionExtensions("max3", 1, &E_GL_AMD_shader_trinary_minmax);
+            symbolTable.setFunctionExtensions("mid3", 1, &E_GL_AMD_shader_trinary_minmax);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("cubeFaceIndexAMD", 1, &E_GL_AMD_gcn_shader);
+            symbolTable.setFunctionExtensions("cubeFaceCoordAMD", 1, &E_GL_AMD_gcn_shader);
+            symbolTable.setFunctionExtensions("timeAMD",          1, &E_GL_AMD_gcn_shader);
+        }
+#endif
+
+        // Compatibility variables, vertex only
+        if (spvVersion.spv == 0) {
+            BuiltInVariable("gl_Color",          EbvColor,          symbolTable);
+            BuiltInVariable("gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+            BuiltInVariable("gl_Normal",         EbvNormal,         symbolTable);
+            BuiltInVariable("gl_Vertex",         EbvVertex,         symbolTable);
+            BuiltInVariable("gl_MultiTexCoord0", EbvMultiTexCoord0, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord1", EbvMultiTexCoord1, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord2", EbvMultiTexCoord2, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord3", EbvMultiTexCoord3, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord4", EbvMultiTexCoord4, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord5", EbvMultiTexCoord5, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord6", EbvMultiTexCoord6, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord7", EbvMultiTexCoord7, symbolTable);
+            BuiltInVariable("gl_FogCoord",       EbvFogFragCoord,   symbolTable);
+        }
+
+        if (profile == EEsProfile) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture2DGradEXT",     1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeGradEXT",   1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+            }
+            if (version >= 310)
+                symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+        }
+
+        if (profile == EEsProfile) {
+            symbolTable.setFunctionExtensions("imageAtomicAdd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMin",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMax",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicAnd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicOr",       1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicXor",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicExchange", 1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic);
+        }
+
+        if (spvVersion.vulkan == 0) {
+            SpecialQualifier("gl_VertexID",   EvqVertexId,   EbvVertexId,   symbolTable);
+            SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable);
+        }
+
+        if (spvVersion.vulkan >= 100) {
+            BuiltInVariable("gl_VertexIndex",   EbvVertexIndex,   symbolTable);
+            BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable);
+        }
+
+        // Fall through
+
+    case EShLangTessControl:
+        if (profile == EEsProfile && version >= 310) {
+            symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box, AEP_primitive_bounding_box);
+            BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
+        }
+
+        // Fall through
+
+    case EShLangTessEvaluation:
+    case EShLangGeometry:
+        SpecialQualifier("gl_Position",   EvqPosition,   EbvPosition,   symbolTable);
+        SpecialQualifier("gl_PointSize",  EvqPointSize,  EbvPointSize,  symbolTable);
+        SpecialQualifier("gl_ClipVertex", EvqClipVertex, EbvClipVertex, symbolTable);
+
+        BuiltInVariable("gl_in",  "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_in",  "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_in",  "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_in",  "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        BuiltInVariable("gl_out", "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_out", "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_out", "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_out", "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        BuiltInVariable("gl_ClipDistance",    EbvClipDistance,   symbolTable);
+        BuiltInVariable("gl_CullDistance",    EbvCullDistance,   symbolTable);
+        BuiltInVariable("gl_PrimitiveIDIn",   EbvPrimitiveId,    symbolTable);
+        BuiltInVariable("gl_PrimitiveID",     EbvPrimitiveId,    symbolTable);
+        BuiltInVariable("gl_InvocationID",    EbvInvocationId,   symbolTable);
+        BuiltInVariable("gl_Layer",           EbvLayer,          symbolTable);
+        BuiltInVariable("gl_ViewportIndex",   EbvViewportIndex,  symbolTable);
+
+#ifdef NV_EXTENSIONS
+        if (language != EShLangGeometry) {
+            symbolTable.setVariableExtensions("gl_Layer",         Num_viewportEXTs, viewportEXTs);
+            symbolTable.setVariableExtensions("gl_ViewportIndex", Num_viewportEXTs, viewportEXTs);
+        }
+        symbolTable.setVariableExtensions("gl_ViewportMask",            1, &E_GL_NV_viewport_array2);
+        symbolTable.setVariableExtensions("gl_SecondaryPositionNV",     1, &E_GL_NV_stereo_view_rendering);
+        symbolTable.setVariableExtensions("gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
+
+        BuiltInVariable("gl_ViewportMask",              EbvViewportMaskNV,          symbolTable);
+        BuiltInVariable("gl_SecondaryPositionNV",       EbvSecondaryPositionNV,     symbolTable);
+        BuiltInVariable("gl_SecondaryViewportMaskNV",   EbvSecondaryViewportMaskNV, symbolTable);
+
+        if (language != EShLangVertex) 
+            BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
+
+        BuiltInVariable("gl_out", "gl_Layer",                   EbvLayer,                   symbolTable);
+        BuiltInVariable("gl_out", "gl_ViewportIndex",           EbvViewportIndex,           symbolTable);
+        BuiltInVariable("gl_out", "gl_ViewportMask",            EbvViewportMaskNV,          symbolTable);
+        BuiltInVariable("gl_out", "gl_SecondaryPositionNV",     EbvSecondaryPositionNV,     symbolTable);
+        BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
+#endif
+
+        BuiltInVariable("gl_PatchVerticesIn", EbvPatchVertices,  symbolTable);
+        BuiltInVariable("gl_TessLevelOuter",  EbvTessLevelOuter, symbolTable);
+        BuiltInVariable("gl_TessLevelInner",  EbvTessLevelInner, symbolTable);
+        BuiltInVariable("gl_TessCoord",       EbvTessCoord,      symbolTable);
+
+        if (version < 410)
+            symbolTable.setVariableExtensions("gl_ViewportIndex", 1, &E_GL_ARB_viewport_array);
+
+        // Compatibility variables
+
+        BuiltInVariable("gl_in", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        BuiltInVariable("gl_out", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_out", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_out", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_out", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_out", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_out", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_out", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        BuiltInVariable("gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        // gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
+        // (Sometimes with an instance name, sometimes anonymous).
+        // However, the current automatic extension scheme does not work per block member,
+        // so for now check when parsing.
+        //
+        // if (profile == EEsProfile) {
+        //    if (language == EShLangGeometry)
+        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+        //    else if (language == EShLangTessEvaluation || language == EShLangTessControl)
+        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+        //}
+
+        break;
+
+    case EShLangFragment:
+        SpecialQualifier("gl_FrontFacing",      EvqFace,       EbvFace,             symbolTable);
+        SpecialQualifier("gl_FragCoord",        EvqFragCoord,  EbvFragCoord,        symbolTable);
+        SpecialQualifier("gl_PointCoord",       EvqPointCoord, EbvPointCoord,       symbolTable);
+        SpecialQualifier("gl_FragColor",        EvqFragColor,  EbvFragColor,        symbolTable);
+        SpecialQualifier("gl_FragDepth",        EvqFragDepth,  EbvFragDepth,        symbolTable);
+        SpecialQualifier("gl_FragDepthEXT",     EvqFragDepth,  EbvFragDepth,        symbolTable);
+        SpecialQualifier("gl_HelperInvocation", EvqVaryingIn,  EbvHelperInvocation, symbolTable);
+
+        BuiltInVariable("gl_ClipDistance",    EbvClipDistance,   symbolTable);
+        BuiltInVariable("gl_CullDistance",    EbvCullDistance,   symbolTable);
+        BuiltInVariable("gl_PrimitiveID",     EbvPrimitiveId,    symbolTable);
+
+        if ((profile != EEsProfile && version >= 400) ||
+            (profile == EEsProfile && version >= 310)) {
+            BuiltInVariable("gl_SampleID",        EbvSampleId,       symbolTable);
+            BuiltInVariable("gl_SamplePosition",  EbvSamplePosition, symbolTable);
+            BuiltInVariable("gl_SampleMaskIn",    EbvSampleMask,     symbolTable);
+            BuiltInVariable("gl_SampleMask",      EbvSampleMask,     symbolTable);
+            if (profile == EEsProfile) {
+                symbolTable.setVariableExtensions("gl_SampleID",       1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SamplePosition", 1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SampleMaskIn",   1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SampleMask",     1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_NumSamples",     1, &E_GL_OES_sample_variables);
+            }
+        }
+
+        BuiltInVariable("gl_Layer",           EbvLayer,          symbolTable);
+        BuiltInVariable("gl_ViewportIndex",   EbvViewportIndex,  symbolTable);
+
+        // Compatibility variables
+
+        BuiltInVariable("gl_in", "gl_FogFragCoord",   EbvFogFragCoord,   symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",       EbvTexCoord,       symbolTable);
+        BuiltInVariable("gl_in", "gl_Color",          EbvColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+
+        BuiltInVariable("gl_FogFragCoord",   EbvFogFragCoord,   symbolTable);
+        BuiltInVariable("gl_TexCoord",       EbvTexCoord,       symbolTable);
+        BuiltInVariable("gl_Color",          EbvColor,          symbolTable);
+        BuiltInVariable("gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+
+        // built-in functions
+
+        if (profile == EEsProfile) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture2DLodEXT",      1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjLodEXT",  1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeLodEXT",    1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DGradEXT",     1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeGradEXT",   1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+            }
+            if (version == 100) {
+                symbolTable.setFunctionExtensions("dFdx",   1, &E_GL_OES_standard_derivatives);
+                symbolTable.setFunctionExtensions("dFdy",   1, &E_GL_OES_standard_derivatives);
+                symbolTable.setFunctionExtensions("fwidth", 1, &E_GL_OES_standard_derivatives);
+            }
+            if (version >= 310) {
+                symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+                symbolTable.setFunctionExtensions("interpolateAtCentroid", 1, &E_GL_OES_shader_multisample_interpolation);
+                symbolTable.setFunctionExtensions("interpolateAtSample",   1, &E_GL_OES_shader_multisample_interpolation);
+                symbolTable.setFunctionExtensions("interpolateAtOffset",   1, &E_GL_OES_shader_multisample_interpolation);
+            }
+        } else if (version < 130) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture1DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture3DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeLod",      1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture1DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture3DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow1DLod",         1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow2DLod",         1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow1DProjLod",     1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow2DProjLod",     1, &E_GL_ARB_shader_texture_lod);
+            }
+        }
+
+        // E_GL_ARB_shader_texture_lod functions usable only with the extension enabled
+        if (profile != EEsProfile && spvVersion.spv == 0) {
+            symbolTable.setFunctionExtensions("texture1DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture1DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture3DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture3DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("textureCubeGradARB",       1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow1DGradARB",          1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow1DProjGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DGradARB",          1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DProjGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DRectGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DRectProjGradARB", 1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DRectGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DRectProjGradARB",  1, &E_GL_ARB_shader_texture_lod);
+        }
+
+        // E_GL_ARB_shader_image_load_store
+        if (profile != EEsProfile && version < 420)
+            symbolTable.setFunctionExtensions("memoryBarrier", 1, &E_GL_ARB_shader_image_load_store);
+        // All the image access functions are protected by checks on the type of the first argument.
+
+        // E_GL_ARB_shader_atomic_counters
+        if (profile != EEsProfile && version < 420) {
+            symbolTable.setFunctionExtensions("atomicCounterIncrement", 1, &E_GL_ARB_shader_atomic_counters);
+            symbolTable.setFunctionExtensions("atomicCounterDecrement", 1, &E_GL_ARB_shader_atomic_counters);
+            symbolTable.setFunctionExtensions("atomicCounter"         , 1, &E_GL_ARB_shader_atomic_counters);
+        }
+
+        // E_GL_ARB_derivative_control
+        if (profile != EEsProfile && version < 450) {
+            symbolTable.setFunctionExtensions("dFdxFine",     1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdyFine",     1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("fwidthFine",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdxCoarse",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdyCoarse",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("fwidthCoarse", 1, &E_GL_ARB_derivative_control);
+        }
+
+        // E_GL_ARB_sparse_texture2
+        if (profile != EEsProfile)
+        {
+            symbolTable.setFunctionExtensions("sparseTextureARB",              1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureLodARB",           1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureOffsetARB",        1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelFetchARB",           1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelFetchOffsetARB",     1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureLodOffsetARB",     1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGradARB",          1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGradOffsetARB",    1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherARB",        1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherOffsetARB",  1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherOffsetsARB", 1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseImageLoadARB",            1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelsResident",          1, &E_GL_ARB_sparse_texture2);
+        }
+
+        // E_GL_ARB_sparse_texture_clamp
+        if (profile != EEsProfile)
+        {
+            symbolTable.setFunctionExtensions("sparseTextureClampARB",              1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureOffsetClampARB",        1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureGradClampARB",          1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureGradOffsetClampARB",    1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureClampARB",                    1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureOffsetClampARB",              1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureGradClampARB",                1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureGradOffsetClampARB",          1, &E_GL_ARB_sparse_texture_clamp);
+        }
+
+#ifdef AMD_EXTENSIONS
+        // E_GL_AMD_shader_explicit_vertex_parameter
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspAMD",         1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspCentroidAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspSampleAMD",   1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothAMD",          1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothCentroidAMD",  1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothSampleAMD",    1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordPullModelAMD",       1, &E_GL_AMD_shader_explicit_vertex_parameter);
+
+            symbolTable.setFunctionExtensions("interpolateAtVertexAMD",         1, &E_GL_AMD_shader_explicit_vertex_parameter);
+
+            BuiltInVariable("gl_BaryCoordNoPerspAMD",           EbvBaryCoordNoPersp,         symbolTable);
+            BuiltInVariable("gl_BaryCoordNoPerspCentroidAMD",   EbvBaryCoordNoPerspCentroid, symbolTable);
+            BuiltInVariable("gl_BaryCoordNoPerspSampleAMD",     EbvBaryCoordNoPerspSample,   symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothAMD",            EbvBaryCoordSmooth,          symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothCentroidAMD",    EbvBaryCoordSmoothCentroid,  symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothSampleAMD",      EbvBaryCoordSmoothSample,    symbolTable);
+            BuiltInVariable("gl_BaryCoordPullModelAMD",         EbvBaryCoordPullModel,       symbolTable);
+        }
+#endif
+
+        symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &E_GL_EXT_frag_depth);
+
+        if (profile == EEsProfile) {
+            symbolTable.setVariableExtensions("gl_PrimitiveID",  Num_AEP_geometry_shader, AEP_geometry_shader);
+            symbolTable.setVariableExtensions("gl_Layer",        Num_AEP_geometry_shader, AEP_geometry_shader);
+        }
+
+        if (profile == EEsProfile) {
+            symbolTable.setFunctionExtensions("imageAtomicAdd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMin",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMax",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicAnd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicOr",       1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicXor",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicExchange", 1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic);
+        }
+        break;
+
+    case EShLangCompute:
+        BuiltInVariable("gl_NumWorkGroups",         EbvNumWorkGroups,        symbolTable);
+        BuiltInVariable("gl_WorkGroupSize",         EbvWorkGroupSize,        symbolTable);
+        BuiltInVariable("gl_WorkGroupID",           EbvWorkGroupId,          symbolTable);
+        BuiltInVariable("gl_LocalInvocationID",     EbvLocalInvocationId,    symbolTable);
+        BuiltInVariable("gl_GlobalInvocationID",    EbvGlobalInvocationId,   symbolTable);
+        BuiltInVariable("gl_LocalInvocationIndex",  EbvLocalInvocationIndex, symbolTable);
+
+        if (profile != EEsProfile && version < 430) {
+            symbolTable.setVariableExtensions("gl_NumWorkGroups",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_WorkGroupSize",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_WorkGroupID",          1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_LocalInvocationID",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_GlobalInvocationID",   1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_ARB_compute_shader);
+
+            symbolTable.setVariableExtensions("gl_MaxComputeWorkGroupCount",       1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeWorkGroupSize",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeUniformComponents",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeTextureImageUnits",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeImageUniforms",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeAtomicCounters",       1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeAtomicCounterBuffers", 1, &E_GL_ARB_compute_shader);
+
+            symbolTable.setFunctionExtensions("barrier",                    1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierAtomicCounter", 1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierBuffer",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierImage",         1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierShared",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("groupMemoryBarrier",         1, &E_GL_ARB_compute_shader);
+        }
+        break;
+
+    default:
+        assert(false && "Language not supported");
+        break;
+    }
+
+    //
+    // Next, identify which built-ins have a mapping to an operator.
+    // If PureOperatorBuiltins is false, those that are not identified as such are
+    // expected to be resolved through a library of functions, versus as
+    // operations.
+    //
+    symbolTable.relateToOperator("not",              EOpVectorLogicalNot);
+
+    symbolTable.relateToOperator("matrixCompMult",   EOpMul);
+    // 120 and 150 are correct for both ES and desktop
+    if (version >= 120) {
+        symbolTable.relateToOperator("outerProduct", EOpOuterProduct);
+        symbolTable.relateToOperator("transpose", EOpTranspose);
+        if (version >= 150) {
+            symbolTable.relateToOperator("determinant", EOpDeterminant);
+            symbolTable.relateToOperator("inverse", EOpMatrixInverse);
+        }
+    }
+
+    symbolTable.relateToOperator("mod",              EOpMod);
+    symbolTable.relateToOperator("modf",             EOpModf);
+
+    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("sinh",         EOpSinh);
+    symbolTable.relateToOperator("cosh",         EOpCosh);
+    symbolTable.relateToOperator("tanh",         EOpTanh);
+    symbolTable.relateToOperator("asinh",        EOpAsinh);
+    symbolTable.relateToOperator("acosh",        EOpAcosh);
+    symbolTable.relateToOperator("atanh",        EOpAtanh);
+
+    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("trunc",        EOpTrunc);
+    symbolTable.relateToOperator("round",        EOpRound);
+    symbolTable.relateToOperator("roundEven",    EOpRoundEven);
+    symbolTable.relateToOperator("ceil",         EOpCeil);
+    symbolTable.relateToOperator("fract",        EOpFract);
+    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("isnan",  EOpIsNan);
+    symbolTable.relateToOperator("isinf",  EOpIsInf);
+
+    symbolTable.relateToOperator("floatBitsToInt",  EOpFloatBitsToInt);
+    symbolTable.relateToOperator("floatBitsToUint", EOpFloatBitsToUint);
+    symbolTable.relateToOperator("intBitsToFloat",  EOpIntBitsToFloat);
+    symbolTable.relateToOperator("uintBitsToFloat", EOpUintBitsToFloat);
+    symbolTable.relateToOperator("doubleBitsToInt64",  EOpDoubleBitsToInt64);
+    symbolTable.relateToOperator("doubleBitsToUint64", EOpDoubleBitsToUint64);
+    symbolTable.relateToOperator("int64BitsToDouble",  EOpInt64BitsToDouble);
+    symbolTable.relateToOperator("uint64BitsToDouble", EOpUint64BitsToDouble);
+
+    symbolTable.relateToOperator("packSnorm2x16",   EOpPackSnorm2x16);
+    symbolTable.relateToOperator("unpackSnorm2x16", EOpUnpackSnorm2x16);
+    symbolTable.relateToOperator("packUnorm2x16",   EOpPackUnorm2x16);
+    symbolTable.relateToOperator("unpackUnorm2x16", EOpUnpackUnorm2x16);
+
+    symbolTable.relateToOperator("packSnorm4x8",    EOpPackSnorm4x8);
+    symbolTable.relateToOperator("unpackSnorm4x8",  EOpUnpackSnorm4x8);
+    symbolTable.relateToOperator("packUnorm4x8",    EOpPackUnorm4x8);
+    symbolTable.relateToOperator("unpackUnorm4x8",  EOpUnpackUnorm4x8);
+
+    symbolTable.relateToOperator("packDouble2x32",    EOpPackDouble2x32);
+    symbolTable.relateToOperator("unpackDouble2x32",  EOpUnpackDouble2x32);
+
+    symbolTable.relateToOperator("packHalf2x16",    EOpPackHalf2x16);
+    symbolTable.relateToOperator("unpackHalf2x16",  EOpUnpackHalf2x16);
+
+    symbolTable.relateToOperator("packInt2x32",     EOpPackInt2x32);
+    symbolTable.relateToOperator("unpackInt2x32",   EOpUnpackInt2x32);
+    symbolTable.relateToOperator("packUint2x32",    EOpPackUint2x32);
+    symbolTable.relateToOperator("unpackUint2x32",  EOpUnpackUint2x32);
+
+#ifdef AMD_EXTENSIONS
+    symbolTable.relateToOperator("packFloat2x16",   EOpPackFloat2x16);
+    symbolTable.relateToOperator("unpackFloat2x16", EOpUnpackFloat2x16);
+#endif
+
+    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("barrier",                    EOpBarrier);
+    symbolTable.relateToOperator("memoryBarrier",              EOpMemoryBarrier);
+    symbolTable.relateToOperator("memoryBarrierAtomicCounter", EOpMemoryBarrierAtomicCounter);
+    symbolTable.relateToOperator("memoryBarrierBuffer",        EOpMemoryBarrierBuffer);
+    symbolTable.relateToOperator("memoryBarrierImage",         EOpMemoryBarrierImage);
+
+    symbolTable.relateToOperator("atomicAdd",      EOpAtomicAdd);
+    symbolTable.relateToOperator("atomicMin",      EOpAtomicMin);
+    symbolTable.relateToOperator("atomicMax",      EOpAtomicMax);
+    symbolTable.relateToOperator("atomicAnd",      EOpAtomicAnd);
+    symbolTable.relateToOperator("atomicOr",       EOpAtomicOr);
+    symbolTable.relateToOperator("atomicXor",      EOpAtomicXor);
+    symbolTable.relateToOperator("atomicExchange", EOpAtomicExchange);
+    symbolTable.relateToOperator("atomicCompSwap", EOpAtomicCompSwap);
+
+    symbolTable.relateToOperator("atomicCounterIncrement", EOpAtomicCounterIncrement);
+    symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement);
+    symbolTable.relateToOperator("atomicCounter",          EOpAtomicCounter);
+
+    symbolTable.relateToOperator("fma",               EOpFma);
+    symbolTable.relateToOperator("frexp",             EOpFrexp);
+    symbolTable.relateToOperator("ldexp",             EOpLdexp);
+    symbolTable.relateToOperator("uaddCarry",         EOpAddCarry);
+    symbolTable.relateToOperator("usubBorrow",        EOpSubBorrow);
+    symbolTable.relateToOperator("umulExtended",      EOpUMulExtended);
+    symbolTable.relateToOperator("imulExtended",      EOpIMulExtended);
+    symbolTable.relateToOperator("bitfieldExtract",   EOpBitfieldExtract);
+    symbolTable.relateToOperator("bitfieldInsert",    EOpBitfieldInsert);
+    symbolTable.relateToOperator("bitfieldReverse",   EOpBitFieldReverse);
+    symbolTable.relateToOperator("bitCount",          EOpBitCount);
+    symbolTable.relateToOperator("findLSB",           EOpFindLSB);
+    symbolTable.relateToOperator("findMSB",           EOpFindMSB);
+
+    if (PureOperatorBuiltins) {
+        symbolTable.relateToOperator("imageSize",               EOpImageQuerySize);
+        symbolTable.relateToOperator("imageSamples",            EOpImageQuerySamples);
+        symbolTable.relateToOperator("imageLoad",               EOpImageLoad);
+        symbolTable.relateToOperator("imageStore",              EOpImageStore);
+        symbolTable.relateToOperator("imageAtomicAdd",          EOpImageAtomicAdd);
+        symbolTable.relateToOperator("imageAtomicMin",          EOpImageAtomicMin);
+        symbolTable.relateToOperator("imageAtomicMax",          EOpImageAtomicMax);
+        symbolTable.relateToOperator("imageAtomicAnd",          EOpImageAtomicAnd);
+        symbolTable.relateToOperator("imageAtomicOr",           EOpImageAtomicOr);
+        symbolTable.relateToOperator("imageAtomicXor",          EOpImageAtomicXor);
+        symbolTable.relateToOperator("imageAtomicExchange",     EOpImageAtomicExchange);
+        symbolTable.relateToOperator("imageAtomicCompSwap",     EOpImageAtomicCompSwap);
+
+        symbolTable.relateToOperator("subpassLoad",             EOpSubpassLoad);
+        symbolTable.relateToOperator("subpassLoadMS",           EOpSubpassLoadMS);
+
+        symbolTable.relateToOperator("textureSize",             EOpTextureQuerySize);
+        symbolTable.relateToOperator("textureQueryLod",         EOpTextureQueryLod);
+        symbolTable.relateToOperator("textureQueryLevels",      EOpTextureQueryLevels);
+        symbolTable.relateToOperator("textureSamples",          EOpTextureQuerySamples);
+        symbolTable.relateToOperator("texture",                 EOpTexture);
+        symbolTable.relateToOperator("textureProj",             EOpTextureProj);
+        symbolTable.relateToOperator("textureLod",              EOpTextureLod);
+        symbolTable.relateToOperator("textureOffset",           EOpTextureOffset);
+        symbolTable.relateToOperator("texelFetch",              EOpTextureFetch);
+        symbolTable.relateToOperator("texelFetchOffset",        EOpTextureFetchOffset);
+        symbolTable.relateToOperator("textureProjOffset",       EOpTextureProjOffset);
+        symbolTable.relateToOperator("textureLodOffset",        EOpTextureLodOffset);
+        symbolTable.relateToOperator("textureProjLod",          EOpTextureProjLod);
+        symbolTable.relateToOperator("textureProjLodOffset",    EOpTextureProjLodOffset);
+        symbolTable.relateToOperator("textureGrad",             EOpTextureGrad);
+        symbolTable.relateToOperator("textureGradOffset",       EOpTextureGradOffset);
+        symbolTable.relateToOperator("textureProjGrad",         EOpTextureProjGrad);
+        symbolTable.relateToOperator("textureProjGradOffset",   EOpTextureProjGradOffset);
+        symbolTable.relateToOperator("textureGather",           EOpTextureGather);
+        symbolTable.relateToOperator("textureGatherOffset",     EOpTextureGatherOffset);
+        symbolTable.relateToOperator("textureGatherOffsets",    EOpTextureGatherOffsets);
+
+        symbolTable.relateToOperator("noise1", EOpNoise);
+        symbolTable.relateToOperator("noise2", EOpNoise);
+        symbolTable.relateToOperator("noise3", EOpNoise);
+        symbolTable.relateToOperator("noise4", EOpNoise);
+
+        if (spvVersion.spv == 0 && (IncludeLegacy(version, profile, spvVersion) ||
+            (profile == EEsProfile && version == 100))) {
+            symbolTable.relateToOperator("ftransform",               EOpFtransform);
+
+            symbolTable.relateToOperator("texture1D",                EOpTexture);
+            symbolTable.relateToOperator("texture1DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture1DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture1DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture1DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture1DProjLod",         EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture2DRect",            EOpTexture);
+            symbolTable.relateToOperator("texture2DRectProj",        EOpTextureProj);
+            symbolTable.relateToOperator("texture2DRectGradARB",     EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DRectProjGradARB", EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DRect",             EOpTexture);
+            symbolTable.relateToOperator("shadow2DRectProj",         EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DRectGradARB",      EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2DRectProjGradARB",  EOpTextureProjGrad);
+
+            symbolTable.relateToOperator("texture2D",                EOpTexture);
+            symbolTable.relateToOperator("texture2DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture2DGradEXT",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DProjGradEXT",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture2DLodEXT",          EOpTextureLod);
+            symbolTable.relateToOperator("texture2DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("texture2DProjLodEXT",      EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture3D",                EOpTexture);
+            symbolTable.relateToOperator("texture3DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture3DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture3DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture3DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture3DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("textureCube",              EOpTexture);
+            symbolTable.relateToOperator("textureCubeGradEXT",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeGradARB",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeLod",           EOpTextureLod);
+            symbolTable.relateToOperator("textureCubeLodEXT",        EOpTextureLod);
+            symbolTable.relateToOperator("shadow1D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow1DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow2DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow1DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow1DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow1DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow2DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow1DProjLod",          EOpTextureProjLod);
+            symbolTable.relateToOperator("shadow2DProjLod",          EOpTextureProjLod);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.relateToOperator("sparseTextureARB",                EOpSparseTexture);
+            symbolTable.relateToOperator("sparseTextureLodARB",             EOpSparseTextureLod);
+            symbolTable.relateToOperator("sparseTextureOffsetARB",          EOpSparseTextureOffset);
+            symbolTable.relateToOperator("sparseTexelFetchARB",             EOpSparseTextureFetch);
+            symbolTable.relateToOperator("sparseTexelFetchOffsetARB",       EOpSparseTextureFetchOffset);
+            symbolTable.relateToOperator("sparseTextureLodOffsetARB",       EOpSparseTextureLodOffset);
+            symbolTable.relateToOperator("sparseTextureGradARB",            EOpSparseTextureGrad);
+            symbolTable.relateToOperator("sparseTextureGradOffsetARB",      EOpSparseTextureGradOffset);
+            symbolTable.relateToOperator("sparseTextureGatherARB",          EOpSparseTextureGather);
+            symbolTable.relateToOperator("sparseTextureGatherOffsetARB",    EOpSparseTextureGatherOffset);
+            symbolTable.relateToOperator("sparseTextureGatherOffsetsARB",   EOpSparseTextureGatherOffsets);
+            symbolTable.relateToOperator("sparseImageLoadARB",              EOpSparseImageLoad);
+            symbolTable.relateToOperator("sparseTexelsResidentARB",         EOpSparseTexelsResident);
+
+            symbolTable.relateToOperator("sparseTextureClampARB",           EOpSparseTextureClamp);
+            symbolTable.relateToOperator("sparseTextureOffsetClampARB",     EOpSparseTextureOffsetClamp);
+            symbolTable.relateToOperator("sparseTextureGradClampARB",       EOpSparseTextureGradClamp);
+            symbolTable.relateToOperator("sparseTextureGradOffsetClampARB", EOpSparseTextureGradOffsetClamp);
+            symbolTable.relateToOperator("textureClampARB",                 EOpTextureClamp);
+            symbolTable.relateToOperator("textureOffsetClampARB",           EOpTextureOffsetClamp);
+            symbolTable.relateToOperator("textureGradClampARB",             EOpTextureGradClamp);
+            symbolTable.relateToOperator("textureGradOffsetClampARB",       EOpTextureGradOffsetClamp);
+
+            symbolTable.relateToOperator("ballotARB",                       EOpBallot);
+            symbolTable.relateToOperator("readInvocationARB",               EOpReadInvocation);
+            symbolTable.relateToOperator("readFirstInvocationARB",          EOpReadFirstInvocation);
+
+            symbolTable.relateToOperator("anyInvocationARB",                EOpAnyInvocation);
+            symbolTable.relateToOperator("allInvocationsARB",               EOpAllInvocations);
+            symbolTable.relateToOperator("allInvocationsEqualARB",          EOpAllInvocationsEqual);
+
+#ifdef AMD_EXTENSIONS
+            symbolTable.relateToOperator("minInvocationsAMD",                           EOpMinInvocations);
+            symbolTable.relateToOperator("maxInvocationsAMD",                           EOpMaxInvocations);
+            symbolTable.relateToOperator("addInvocationsAMD",                           EOpAddInvocations);
+            symbolTable.relateToOperator("minInvocationsNonUniformAMD",                 EOpMinInvocationsNonUniform);
+            symbolTable.relateToOperator("maxInvocationsNonUniformAMD",                 EOpMaxInvocationsNonUniform);
+            symbolTable.relateToOperator("addInvocationsNonUniformAMD",                 EOpAddInvocationsNonUniform);
+            symbolTable.relateToOperator("minInvocationsInclusiveScanAMD",              EOpMinInvocationsInclusiveScan);
+            symbolTable.relateToOperator("maxInvocationsInclusiveScanAMD",              EOpMaxInvocationsInclusiveScan);
+            symbolTable.relateToOperator("addInvocationsInclusiveScanAMD",              EOpAddInvocationsInclusiveScan);
+            symbolTable.relateToOperator("minInvocationsInclusiveScanNonUniformAMD",    EOpMinInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("maxInvocationsInclusiveScanNonUniformAMD",    EOpMaxInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("addInvocationsInclusiveScanNonUniformAMD",    EOpAddInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("minInvocationsExclusiveScanAMD",              EOpMinInvocationsExclusiveScan);
+            symbolTable.relateToOperator("maxInvocationsExclusiveScanAMD",              EOpMaxInvocationsExclusiveScan);
+            symbolTable.relateToOperator("addInvocationsExclusiveScanAMD",              EOpAddInvocationsExclusiveScan);
+            symbolTable.relateToOperator("minInvocationsExclusiveScanNonUniformAMD",    EOpMinInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("maxInvocationsExclusiveScanNonUniformAMD",    EOpMaxInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("addInvocationsExclusiveScanNonUniformAMD",    EOpAddInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("swizzleInvocationsAMD",                       EOpSwizzleInvocations);
+            symbolTable.relateToOperator("swizzleInvocationsMaskedAMD",                 EOpSwizzleInvocationsMasked);
+            symbolTable.relateToOperator("writeInvocationAMD",                          EOpWriteInvocation);
+            symbolTable.relateToOperator("mbcntAMD",                                    EOpMbcnt);
+
+            symbolTable.relateToOperator("min3",    EOpMin3);
+            symbolTable.relateToOperator("max3",    EOpMax3);
+            symbolTable.relateToOperator("mid3",    EOpMid3);
+
+            symbolTable.relateToOperator("cubeFaceIndexAMD",    EOpCubeFaceIndex);
+            symbolTable.relateToOperator("cubeFaceCoordAMD",    EOpCubeFaceCoord);
+            symbolTable.relateToOperator("timeAMD",             EOpTime);
+#endif
+        }
+    }
+
+    switch(language) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        break;
+
+    case EShLangGeometry:
+        symbolTable.relateToOperator("EmitStreamVertex",   EOpEmitStreamVertex);
+        symbolTable.relateToOperator("EndStreamPrimitive", EOpEndStreamPrimitive);
+        symbolTable.relateToOperator("EmitVertex",         EOpEmitVertex);
+        symbolTable.relateToOperator("EndPrimitive",       EOpEndPrimitive);
+        break;
+
+    case EShLangFragment:
+        symbolTable.relateToOperator("dFdx",         EOpDPdx);
+        symbolTable.relateToOperator("dFdy",         EOpDPdy);
+        symbolTable.relateToOperator("fwidth",       EOpFwidth);
+        if (profile != EEsProfile && version >= 400) {
+            symbolTable.relateToOperator("dFdxFine",     EOpDPdxFine);
+            symbolTable.relateToOperator("dFdyFine",     EOpDPdyFine);
+            symbolTable.relateToOperator("fwidthFine",   EOpFwidthFine);
+            symbolTable.relateToOperator("dFdxCoarse",   EOpDPdxCoarse);
+            symbolTable.relateToOperator("dFdyCoarse",   EOpDPdyCoarse);
+            symbolTable.relateToOperator("fwidthCoarse", EOpFwidthCoarse);
+        }
+        symbolTable.relateToOperator("interpolateAtCentroid", EOpInterpolateAtCentroid);
+        symbolTable.relateToOperator("interpolateAtSample",   EOpInterpolateAtSample);
+        symbolTable.relateToOperator("interpolateAtOffset",   EOpInterpolateAtOffset);
+
+#ifdef AMD_EXTENSIONS
+        if (profile != EEsProfile)
+            symbolTable.relateToOperator("interpolateAtVertexAMD", EOpInterpolateAtVertex);
+        break;
+#endif
+
+    case EShLangCompute:
+        symbolTable.relateToOperator("memoryBarrierShared",     EOpMemoryBarrierShared);
+        symbolTable.relateToOperator("groupMemoryBarrier",      EOpGroupMemoryBarrier);
+        break;
+
+    default:
+        assert(false && "Language not supported");
+    }
+}
+
+//
+// Add context-dependent (resource-specific) built-ins not handled by the above.  These
+// would be ones that need to be programmatically added because they cannot
+// be added by simple text strings.  For these, also
+// 1) Map built-in functions to operators, for those that will turn into an operation node
+//    instead of remaining a function call.
+// 2) Tag extension-related symbols added to their base version with their extensions, so
+//    that if an early version has the extension turned off, there is an error reported on use.
+//
+void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
+{
+    if (profile != EEsProfile && version >= 430 && version < 440) {
+        symbolTable.setVariableExtensions("gl_MaxTransformFeedbackBuffers", 1, &E_GL_ARB_enhanced_layouts);
+        symbolTable.setVariableExtensions("gl_MaxTransformFeedbackInterleavedComponents", 1, &E_GL_ARB_enhanced_layouts);
+    }
+    if (profile != EEsProfile && version >= 130 && version < 420) {
+        symbolTable.setVariableExtensions("gl_MinProgramTexelOffset", 1, &E_GL_ARB_shading_language_420pack);
+        symbolTable.setVariableExtensions("gl_MaxProgramTexelOffset", 1, &E_GL_ARB_shading_language_420pack);
+    }
+    if (profile != EEsProfile && version >= 150 && version < 410)
+        symbolTable.setVariableExtensions("gl_MaxViewports", 1, &E_GL_ARB_viewport_array);
+
+    switch(language) {
+    case EShLangFragment:
+        // Set up gl_FragData based on current array size.
+        if (version == 100 || IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && profile != EEsProfile && version < 420)) {
+            TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone;
+            TType fragData(EbtFloat, EvqFragColor, pq, 4);
+            TArraySizes& arraySizes = *new TArraySizes;
+            arraySizes.addInnerSize(resources.maxDrawBuffers);
+            fragData.newArraySizes(arraySizes);
+            symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
+            SpecialQualifier("gl_FragData", EvqFragColor, EbvFragData, symbolTable);
+        }
+        break;
+
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        // Because of the context-dependent array size (gl_MaxPatchVertices),
+        // these variables were added later than the others and need to be mapped now.
+
+        // standard members
+        BuiltInVariable("gl_in", "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_in", "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_in", "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_in", "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        // compatibility members
+        BuiltInVariable("gl_in", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+        break;
+
+    default:
+        break;
+    }
+}
+
+} // end namespace glslang

+ 112 - 0
src/libraries/glslang/glslang/MachineIndependent/Initialize.h

@@ -0,0 +1,112 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "../Include/ResourceLimits.h"
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+#include "SymbolTable.h"
+#include "Versions.h"
+
+namespace glslang {
+
+//
+// This is made to hold parseable strings for almost all the built-in
+// functions and variables for one specific combination of version
+// and profile.  (Some still need to be added programmatically.)
+// This is a base class for language-specific derivations, which
+// can be used for language independent builtins.
+//
+// The strings are organized by
+//    commonBuiltins:  intersection of all stages' built-ins, processed just once
+//    stageBuiltins[]: anything a stage needs that's not in commonBuiltins
+//
+class TBuiltInParseables {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    TBuiltInParseables();
+    virtual ~TBuiltInParseables();
+    virtual void initialize(int version, EProfile, const SpvVersion& spvVersion) = 0;
+    virtual void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage) = 0;
+    virtual const TString& getCommonString() const { return commonBuiltins; }
+    virtual const TString& getStageString(EShLanguage language) const { return stageBuiltins[language]; }
+
+    virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable) = 0;
+
+    virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) = 0;
+
+protected:
+    TString commonBuiltins;
+    TString stageBuiltins[EShLangCount];
+};
+
+//
+// This is a GLSL specific derivation of TBuiltInParseables.  To present a stable
+// interface and match other similar code, it is called TBuiltIns, rather
+// than TBuiltInParseablesGlsl.
+//
+class TBuiltIns : public TBuiltInParseables {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    TBuiltIns();
+    virtual ~TBuiltIns();
+    void initialize(int version, EProfile, const SpvVersion& spvVersion);
+    void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage);
+
+    void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable);
+
+    void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources);
+
+protected:
+    void add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion);
+    void addSubpassSampling(TSampler, TString& typeName, int version, EProfile profile);
+    void addQueryFunctions(TSampler, TString& typeName, int version, EProfile profile);
+    void addImageFunctions(TSampler, TString& typeName, int version, EProfile profile);
+    void addSamplingFunctions(TSampler, TString& typeName, int version, EProfile profile);
+    void addGatherFunctions(TSampler, TString& typeName, int version, EProfile profile);
+
+    // Helpers for making textual representations of the permutations
+    // of texturing/imaging functions.
+    const char* postfixes[5];
+    const char* prefixes[EbtNumTypes];
+    int dimMap[EsdNumDims];
+};
+
+} // end namespace glslang
+
+#endif // _INITIALIZE_INCLUDED_

+ 302 - 0
src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp

@@ -0,0 +1,302 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// Copyright (c) 2002-2010 The ANGLE Project Authors.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/intermediate.h"
+
+namespace glslang {
+
+//
+// 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 straightforward....
+//
+void TIntermMethod::traverse(TIntermTraverser*)
+{
+    // Tree should always resolve all methods as a non-method.
+}
+
+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(EvPreVisit, 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(EvInVisit, this);
+
+            if (visit && left)
+                left->traverse(it);
+        } else {
+            if (left)
+                left->traverse(it);
+
+            if (it->inVisit)
+                visit = it->visitBinary(EvInVisit, this);
+
+            if (visit && right)
+                right->traverse(it);
+        }
+
+        it->decrementDepth();
+    }
+
+    //
+    // Visit the node after the children, if requested and the traversal
+    // hasn't been canceled yet.
+    //
+    if (visit && it->postVisit)
+        it->visitBinary(EvPostVisit, 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(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+        operand->traverse(it);
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitUnary(EvPostVisit, 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(EvPreVisit, 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(EvInVisit, 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(EvInVisit, this);
+                }
+            }
+        }
+
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitAggregate(EvPostVisit, 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(EvPreVisit, 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(EvPostVisit, 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(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+
+        if (it->rightToLeft) {
+            if (terminal)
+                terminal->traverse(it);
+
+            if (body)
+                body->traverse(it);
+
+            if (test)
+                test->traverse(it);
+        } else {
+            if (test)
+                test->traverse(it);
+
+            if (body)
+                body->traverse(it);
+
+            if (terminal)
+                terminal->traverse(it);
+        }
+
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitLoop(EvPostVisit, 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(EvPreVisit, this);
+
+    if (visit && expression) {
+        it->incrementDepth(this);
+        expression->traverse(it);
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitBranch(EvPostVisit, this);
+}
+
+//
+// Traverse a switch node.
+//
+void TIntermSwitch::traverse(TIntermTraverser* it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitSwitch(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+        if (it->rightToLeft) {
+            body->traverse(it);
+            condition->traverse(it);
+        } else {
+            condition->traverse(it);
+            body->traverse(it);
+        }
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitSwitch(EvPostVisit, this);
+}
+
+} // end namespace glslang

+ 2642 - 0
src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp

@@ -0,0 +1,2642 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2015 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include "localintermediate.h"
+#include "RemoveTree.h"
+#include "SymbolTable.h"
+#include "propagateNoContraction.h"
+
+#include <cfloat>
+#include <utility>
+
+namespace glslang {
+
+////////////////////////////////////////////////////////////////////////////
+//
+// 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 TConstUnionArray& constArray,
+                                        TIntermTyped* constSubtree, const TSourceLoc& loc)
+{
+    TIntermSymbol* node = new TIntermSymbol(id, name, type);
+    node->setLoc(loc);
+    node->setConstArray(constArray);
+    node->setConstSubtree(constSubtree);
+
+    return node;
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol)
+{
+    return addSymbol(intermSymbol.getId(),
+                     intermSymbol.getName(),
+                     intermSymbol.getType(),
+                     intermSymbol.getConstArray(),
+                     intermSymbol.getConstSubtree(),
+                     intermSymbol.getLoc());
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
+{
+    glslang::TSourceLoc loc; // just a null location
+    loc.init();
+
+    return addSymbol(variable, loc);
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
+{
+    return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
+{
+    TConstUnionArray unionArray;  // just a null constant
+
+    return addSymbol(0, "", type, unionArray, nullptr, loc);
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+// Returns nullptr if the working conversions and promotions could not be found.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
+{
+    // No operations work on blocks
+    if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    // Try converting the children's base types to compatible types.
+    TIntermTyped* child = addConversion(op, left->getType(), right);
+    if (child)
+        right = child;
+    else {
+        child = addConversion(op, right->getType(), left);
+        if (child)
+            left = child;
+        else
+            return nullptr;
+    }
+
+    // Convert the children's type shape to be compatible.
+    right = addShapeConversion(op,  left->getType(), right);
+    left  = addShapeConversion(op, right->getType(),  left);
+
+    //
+    // Need a new node holding things together.  Make
+    // one and promote it to the right type.
+    //
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    //
+    // If they are both (non-specialization) constants, they must be folded.
+    // (Unless it's the sequence (comma) operator, but that's handled in addComma().)
+    //
+    TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+    TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+    if (leftTempConstant && rightTempConstant) {
+        TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant);
+        if (folded)
+            return folded;
+    }
+
+    // If either is a specialization constant, while the other is
+    // a constant (or specialization constant), the result is still
+    // a specialization constant, if the operation is an allowed
+    // specialization-constant operation.
+    if (( left->getType().getQualifier().isSpecConstant() && right->getType().getQualifier().isConstant()) ||
+        (right->getType().getQualifier().isSpecConstant() &&  left->getType().getQualifier().isConstant()))
+        if (isSpecializationOperation(*node))
+            node->getWritableType().getQualifier().makeSpecConstant();
+
+    return node;
+}
+
+//
+// Low level: add binary node (no promotions or other argument modifications)
+//
+TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) const
+{
+    // build the node
+    TIntermBinary* node = new TIntermBinary(op);
+    if (loc.line == 0)
+        loc = left->getLoc();
+    node->setLoc(loc);
+    node->setLeft(left);
+    node->setRight(right);
+
+    return node;
+}
+
+//
+// like non-type form, but sets node's type.
+//
+TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc, const TType& type) const
+{
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+    node->setType(type);
+    return node;
+}
+
+//
+// Low level: add unary node (no promotions or other argument modifications)
+//
+TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc) const
+{
+    TIntermUnary* node = new TIntermUnary(op);
+    if (loc.line == 0)
+        loc = child->getLoc();
+    node->setLoc(loc);
+    node->setOperand(child);
+
+    return node;
+}
+
+//
+// like non-type form, but sets node's type.
+//
+TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc, const TType& type) const
+{
+    TIntermUnary* node = addUnaryNode(op, child, loc);
+    node->setType(type);
+    return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+// Returns nullptr if the 'right' type could not be converted to match the 'left' type,
+// or the resulting operation cannot be properly promoted.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
+{
+    // No block assignment
+    if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    //
+    // Like adding binary math, except the conversion can only go
+    // from right to left.
+    //
+
+    // convert base types, nullptr return means not possible
+    right = addConversion(op, left->getType(), right);
+    if (right == nullptr)
+        return nullptr;
+
+    // convert shape
+    right = addShapeConversion(op, left->getType(), right);
+
+    // build the node
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    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, TSourceLoc loc)
+{
+    // caller should set the type
+    return addBinaryNode(op, base, index, loc);
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSourceLoc loc)
+{
+    if (child == 0)
+        return nullptr;
+
+    if (child->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    switch (op) {
+    case EOpLogicalNot:
+        if (source == EShSourceHlsl) {
+            break; // HLSL can promote logical not
+        }
+
+        if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+            return nullptr;
+        }
+        break;
+
+    case EOpPostIncrement:
+    case EOpPreIncrement:
+    case EOpPostDecrement:
+    case EOpPreDecrement:
+    case EOpNegative:
+        if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+            return nullptr;
+    default: break; // some compilers want this
+    }
+
+    //
+    // Do we need to promote the operand?
+    //
+    TBasicType newType = EbtVoid;
+    switch (op) {
+    case EOpConstructInt:    newType = EbtInt;    break;
+    case EOpConstructUint:   newType = EbtUint;   break;
+    case EOpConstructInt64:  newType = EbtInt64;  break;
+    case EOpConstructUint64: newType = EbtUint64; break;
+    case EOpConstructBool:   newType = EbtBool;   break;
+    case EOpConstructFloat:  newType = EbtFloat;  break;
+    case EOpConstructDouble: newType = EbtDouble; break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16: newType = EbtFloat16; break;
+#endif
+    default: break; // some compilers want this
+    }
+
+    if (newType != EbtVoid) {
+        child = addConversion(op, TType(newType, EvqTemporary, child->getVectorSize(),
+                                                               child->getMatrixCols(),
+                                                               child->getMatrixRows(),
+                                                               child->isVector()),
+                              child);
+        if (child == nullptr)
+            return nullptr;
+    }
+
+    //
+    // For constructors, we are now done, it was all in the conversion.
+    // TODO: but, did this bypass constant folding?
+    //
+    switch (op) {
+    case EOpConstructInt:
+    case EOpConstructUint:
+    case EOpConstructInt64:
+    case EOpConstructUint64:
+    case EOpConstructBool:
+    case EOpConstructFloat:
+    case EOpConstructDouble:
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16:
+#endif
+        return child;
+    default: break; // some compilers want this
+    }
+
+    //
+    // Make a new node for the operator.
+    //
+    TIntermUnary* node = addUnaryNode(op, child, loc);
+
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    // If it's a (non-specialization) constant, it must be folded.
+    if (child->getAsConstantUnion())
+        return child->getAsConstantUnion()->fold(op, node->getType());
+
+    // If it's a specialization constant, the result is too,
+    // if the operation is allowed for specialization constants.
+    if (child->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node))
+        node->getWritableType().getQualifier().makeSpecConstant();
+
+    return node;
+}
+
+TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary, TIntermNode* childNode, const TType& returnType)
+{
+    if (unary) {
+        //
+        // Treat it like a unary operator.
+        // addUnaryMath() should get the type correct on its own;
+        // including constness (which would differ from the prototype).
+        //
+        TIntermTyped* child = childNode->getAsTyped();
+        if (child == nullptr)
+            return nullptr;
+
+        if (child->getAsConstantUnion()) {
+            TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType);
+            if (folded)
+                return folded;
+        }
+
+        return addUnaryNode(op, child, child->getLoc(), returnType);
+    } else {
+        // setAggregateOperater() calls fold() for constant folding
+        TIntermTyped* node = setAggregateOperator(childNode, op, returnType, loc);
+
+        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 directly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate.
+//
+TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type, TSourceLoc loc)
+{
+    TIntermAggregate* aggNode;
+
+    //
+    // Make sure we have an aggregate.  If not turn it into one.
+    //
+    if (node) {
+        aggNode = node->getAsAggregate();
+        if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
+            //
+            // Make an aggregate containing this node.
+            //
+            aggNode = new TIntermAggregate();
+            aggNode->getSequence().push_back(node);
+            if (loc.line == 0)
+                loc = node->getLoc();
+        }
+    } else
+        aggNode = new TIntermAggregate();
+
+    //
+    // Set the operator.
+    //
+    aggNode->setOperator(op);
+    if (loc.line != 0)
+        aggNode->setLoc(loc);
+
+    aggNode->setType(type);
+
+    return fold(aggNode);
+}
+
+//
+// Convert the node's type to the given type, as allowed by the operation involved: 'op'.
+// For implicit conversions, 'op' is not the requested conversion, it is the explicit
+// operation requiring the implicit conversion.
+//
+// Returns a node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Generally, this is focused on basic type conversion, not shape conversion.
+// See addShapeConversion().
+//
+// Return nullptr if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
+{
+    //
+    // Does the base type even allow the operation?
+    //
+    switch (node->getBasicType()) {
+    case EbtVoid:
+        return nullptr;
+    case EbtAtomicUint:
+    case EbtSampler:
+        // opaque types can be passed to functions
+        if (op == EOpFunction)
+            break;
+
+        // HLSL can assign samplers directly (no constructor)
+        if (source == EShSourceHlsl && node->getBasicType() == EbtSampler)
+            break;
+
+        // samplers can get assigned via a sampler constructor
+        // (well, not yet, but code in the rest of this function is ready for it)
+        if (node->getBasicType() == EbtSampler && op == EOpAssign &&
+            node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
+            break;
+
+        // otherwise, opaque types can't even be operated on, let alone converted
+        return nullptr;
+    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.isStruct() || node->isStruct())
+        return nullptr;
+
+    // If one's an array, then no conversions.
+    if (type.isArray() || node->getType().isArray())
+        return nullptr;
+
+    // Note: callers are responsible for other aspects of shape,
+    // like vector and matrix sizes.
+
+    TBasicType promoteTo;
+
+    switch (op) {
+    //
+    // Explicit conversions (unary operations)
+    //
+    case EOpConstructBool:
+        promoteTo = EbtBool;
+        break;
+    case EOpConstructFloat:
+        promoteTo = EbtFloat;
+        break;
+    case EOpConstructDouble:
+        promoteTo = EbtDouble;
+        break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16:
+        promoteTo = EbtFloat16;
+        break;
+#endif
+    case EOpConstructInt:
+        promoteTo = EbtInt;
+        break;
+    case EOpConstructUint:
+        promoteTo = EbtUint;
+        break;
+    case EOpConstructInt64:
+        promoteTo = EbtInt64;
+        break;
+    case EOpConstructUint64:
+        promoteTo = EbtUint64;
+        break;
+
+    //
+    // List all the binary ops that can implicitly convert one operand to the other's type;
+    // This implements the 'policy' for implicit type conversion.
+    //
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+    case EOpEqual:
+    case EOpNotEqual:
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpMul:
+    case EOpDiv:
+    case EOpMod:
+
+    case EOpVectorTimesScalar:
+    case EOpVectorTimesMatrix:
+    case EOpMatrixTimesVector:
+    case EOpMatrixTimesScalar:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLogicalNot:
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+
+    case EOpFunctionCall:
+    case EOpReturn:
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpVectorTimesScalarAssign:
+    case EOpMatrixTimesScalarAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+
+    case EOpAtan:
+    case EOpClamp:
+    case EOpCross:
+    case EOpDistance:
+    case EOpDot:
+    case EOpDst:
+    case EOpFaceForward:
+    case EOpFma:
+    case EOpFrexp:
+    case EOpLdexp:
+    case EOpMix:
+    case EOpLit:
+    case EOpMax:
+    case EOpMin:
+    case EOpModf:
+    case EOpPow:
+    case EOpReflect:
+    case EOpRefract:
+    case EOpSmoothStep:
+    case EOpStep:
+
+    case EOpSequence:
+    case EOpConstructStruct:
+
+        if (type.getBasicType() == node->getType().getBasicType())
+            return node;
+
+        if (canImplicitlyPromote(node->getType().getBasicType(), type.getBasicType(), op))
+            promoteTo = type.getBasicType();
+        else
+            return nullptr;
+
+        break;
+
+    // Shifts can have mixed types as long as they are integer, without converting.
+    // It's the left operand's type that determines the resulting type, so no issue
+    // with assign shift ops either.
+    case EOpLeftShift:
+    case EOpRightShift:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        if ((type.getBasicType() == EbtInt ||
+             type.getBasicType() == EbtUint ||
+             type.getBasicType() == EbtInt64 ||
+             type.getBasicType() == EbtUint64) &&
+            (node->getType().getBasicType() == EbtInt ||
+             node->getType().getBasicType() == EbtUint ||
+             node->getType().getBasicType() == EbtInt64 ||
+             node->getType().getBasicType() == EbtUint64))
+
+            return node;
+        else
+            return nullptr;
+
+    default:
+        // default is to require a match; all exceptions should have case statements above
+
+        if (type.getBasicType() == node->getType().getBasicType())
+            return node;
+        else
+            return nullptr;
+    }
+
+    if (node->getAsConstantUnion())
+        return promoteConstantUnion(promoteTo, node->getAsConstantUnion());
+
+    //
+    // Add a new newNode for the conversion.
+    //
+    TIntermUnary* newNode = nullptr;
+
+    TOperator newOp = EOpNull;
+
+    // This is 'mechanism' here, it does any conversion told.  The policy comes
+    // from the shader or the above code.
+    switch (promoteTo) {
+    case EbtDouble:
+        switch (node->getBasicType()) {
+        case EbtInt:   newOp = EOpConvIntToDouble;   break;
+        case EbtUint:  newOp = EOpConvUintToDouble;  break;
+        case EbtBool:  newOp = EOpConvBoolToDouble;  break;
+        case EbtFloat: newOp = EOpConvFloatToDouble; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToDouble; break;
+#endif
+        case EbtInt64: newOp = EOpConvInt64ToDouble; break;
+        case EbtUint64: newOp = EOpConvUint64ToDouble; break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtFloat:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToFloat;    break;
+        case EbtUint:   newOp = EOpConvUintToFloat;   break;
+        case EbtBool:   newOp = EOpConvBoolToFloat;   break;
+        case EbtDouble: newOp = EOpConvDoubleToFloat; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToFloat; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToFloat;  break;
+        case EbtUint64: newOp = EOpConvUint64ToFloat; break;
+        default:
+            return nullptr;
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToFloat16;    break;
+        case EbtUint:   newOp = EOpConvUintToFloat16;   break;
+        case EbtBool:   newOp = EOpConvBoolToFloat16;   break;
+        case EbtFloat:  newOp = EOpConvFloatToFloat16;  break;
+        case EbtDouble: newOp = EOpConvDoubleToFloat16; break;
+        case EbtInt64:  newOp = EOpConvInt64ToFloat16;  break;
+        case EbtUint64: newOp = EOpConvUint64ToFloat16; break;
+        default:
+            return nullptr;
+        }
+        break;
+#endif
+    case EbtBool:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToBool;    break;
+        case EbtUint:   newOp = EOpConvUintToBool;   break;
+        case EbtFloat:  newOp = EOpConvFloatToBool;  break;
+        case EbtDouble: newOp = EOpConvDoubleToBool; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToBool; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToBool;  break;
+        case EbtUint64: newOp = EOpConvUint64ToBool; break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtInt:
+        switch (node->getBasicType()) {
+        case EbtUint:   newOp = EOpConvUintToInt;   break;
+        case EbtBool:   newOp = EOpConvBoolToInt;   break;
+        case EbtFloat:  newOp = EOpConvFloatToInt;  break;
+        case EbtDouble: newOp = EOpConvDoubleToInt; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToInt; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToInt;  break;
+        case EbtUint64: newOp = EOpConvUint64ToInt; break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtUint:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToUint;    break;
+        case EbtBool:   newOp = EOpConvBoolToUint;   break;
+        case EbtFloat:  newOp = EOpConvFloatToUint;  break;
+        case EbtDouble: newOp = EOpConvDoubleToUint; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToUint; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToUint;  break;
+        case EbtUint64: newOp = EOpConvUint64ToUint; break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtInt64:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToInt64;    break;
+        case EbtUint:   newOp = EOpConvUintToInt64;   break;
+        case EbtBool:   newOp = EOpConvBoolToInt64;   break;
+        case EbtFloat:  newOp = EOpConvFloatToInt64;  break;
+        case EbtDouble: newOp = EOpConvDoubleToInt64; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToInt64; break;
+#endif
+        case EbtUint64: newOp = EOpConvUint64ToInt64; break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtUint64:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToUint64;    break;
+        case EbtUint:   newOp = EOpConvUintToUint64;   break;
+        case EbtBool:   newOp = EOpConvBoolToUint64;   break;
+        case EbtFloat:  newOp = EOpConvFloatToUint64;  break;
+        case EbtDouble: newOp = EOpConvDoubleToUint64; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToUint64; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToUint64;  break;
+        default:
+            return nullptr;
+        }
+        break;
+    default:
+        return nullptr;
+    }
+
+    TType newType(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
+    newNode = addUnaryNode(newOp, node, node->getLoc(), newType);
+
+    // TODO: it seems that some unary folding operations should occur here, but are not
+
+    // Propagate specialization-constant-ness, if allowed
+    if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode))
+        newNode->getWritableType().getQualifier().makeSpecConstant();
+
+    return newNode;
+}
+
+// Convert the node's shape of type for the given type, as allowed by the
+// operation involved: 'op'.
+//
+// Generally, the AST represents allowed GLSL shapes, so this isn't needed
+// for GLSL.  Bad shapes are caught in conversion or promotion.
+//
+// Return 'node' if no conversion was done. Promotion handles final shape
+// checking.
+//
+TIntermTyped* TIntermediate::addShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+    // some source languages don't do this
+    switch (source) {
+    case EShSourceHlsl:
+        break;
+    case EShSourceGlsl:
+    default:
+        return node;
+    }
+
+    // some operations don't do this
+    switch (op) {
+    case EOpAssign:
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+    case EOpEqual:
+    case EOpNotEqual:
+    case EOpFunctionCall:
+    case EOpReturn:
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+        break;
+    default:
+        return node;
+    }
+
+    // structures and arrays don't change shape, either to or from
+    if (node->getType().isStruct() || node->getType().isArray() ||
+        type.isStruct() || type.isArray())
+        return node;
+
+    // The new node that handles the conversion
+    TOperator constructorOp = mapTypeToConstructorOp(type);
+
+    // scalar -> smeared -> vector, or
+    // vec1 -> scalar, or
+    // bigger vector -> smaller vector or scalar
+    if ((type.isVector() && node->getType().isScalar()) ||
+        (node->getType().isVector() && node->getVectorSize() == 1 && type.isScalar()) ||
+        (node->getVectorSize() > type.getVectorSize() && type.isVector()))
+        return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
+
+    return node;
+}
+
+//
+// See if the 'from' type is allowed to be implicitly converted to the
+// 'to' type.  This is not about vector/array/struct, only about basic type.
+//
+bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const
+{
+    if (profile == EEsProfile || version == 110)
+        return false;
+
+    if (from == to)
+        return true;
+
+    // TODO: Move more policies into language-specific handlers.
+    // Some languages allow more general (or potentially, more specific) conversions under some conditions.
+    if (source == EShSourceHlsl) {
+        const bool fromConvertable = (from == EbtFloat || from == EbtDouble || from == EbtInt || from == EbtUint || from == EbtBool);
+        const bool toConvertable = (to == EbtFloat || to == EbtDouble || to == EbtInt || to == EbtUint || to == EbtBool);
+
+        if (fromConvertable && toConvertable) {
+            switch (op) {
+            case EOpAndAssign:               // assignments can perform arbitrary conversions
+            case EOpInclusiveOrAssign:       // ...
+            case EOpExclusiveOrAssign:       // ...
+            case EOpAssign:                  // ...
+            case EOpAddAssign:               // ...
+            case EOpSubAssign:               // ...
+            case EOpMulAssign:               // ...
+            case EOpVectorTimesScalarAssign: // ...
+            case EOpMatrixTimesScalarAssign: // ...
+            case EOpDivAssign:               // ...
+            case EOpModAssign:               // ...
+            case EOpReturn:                  // function returns can also perform arbitrary conversions
+            case EOpFunctionCall:            // conversion of a calling parameter
+            case EOpLogicalNot:
+            case EOpLogicalAnd:
+            case EOpLogicalOr:
+            case EOpLogicalXor:
+            case EOpConstructStruct:
+                return true;
+            default:
+                break;
+            }
+        }
+    }
+
+    switch (to) {
+    case EbtDouble:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+        case EbtFloat:
+        case EbtDouble:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    case EbtFloat:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+        case EbtFloat:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtUint:
+        switch (from) {
+        case EbtInt:
+            return version >= 400;
+        case EbtUint:
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtInt:
+        switch (from) {
+        case EbtInt:
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtUint64:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+            return true;
+        default:
+            return false;
+        }
+    case EbtInt64:
+        switch (from) {
+        case EbtInt:
+        case EbtInt64:
+            return true;
+        default:
+            return false;
+        }
+    default:
+        return false;
+    }
+}
+
+//
+// Given a type, find what operation would fully construct it.
+//
+TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
+{
+    TOperator op = EOpNull;
+
+    switch (type.getBasicType()) {
+    case EbtStruct:
+        op = EOpConstructStruct;
+        break;
+    case EbtSampler:
+        if (type.getSampler().combined)
+            op = EOpConstructTextureSampler;
+        break;
+    case EbtFloat:
+        if (type.isMatrix()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat2x2; break;
+                case 3: op = EOpConstructMat2x3; break;
+                case 4: op = EOpConstructMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat3x2; break;
+                case 3: op = EOpConstructMat3x3; break;
+                case 4: op = EOpConstructMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat4x2; break;
+                case 3: op = EOpConstructMat4x3; break;
+                case 4: op = EOpConstructMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            default: break; // some compilers want this
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructFloat; break;
+            case 2: op = EOpConstructVec2;  break;
+            case 3: op = EOpConstructVec3;  break;
+            case 4: op = EOpConstructVec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+    case EbtDouble:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat2x2; break;
+                case 3: op = EOpConstructDMat2x3; break;
+                case 4: op = EOpConstructDMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat3x2; break;
+                case 3: op = EOpConstructDMat3x3; break;
+                case 4: op = EOpConstructDMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat4x2; break;
+                case 3: op = EOpConstructDMat4x3; break;
+                case 4: op = EOpConstructDMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructDouble; break;
+            case 2: op = EOpConstructDVec2;  break;
+            case 3: op = EOpConstructDVec3;  break;
+            case 4: op = EOpConstructDVec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat2x2; break;
+                case 3: op = EOpConstructF16Mat2x3; break;
+                case 4: op = EOpConstructF16Mat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat3x2; break;
+                case 3: op = EOpConstructF16Mat3x3; break;
+                case 4: op = EOpConstructF16Mat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat4x2; break;
+                case 3: op = EOpConstructF16Mat4x3; break;
+                case 4: op = EOpConstructF16Mat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        }
+        else {
+            switch (type.getVectorSize()) {
+            case 1: op = EOpConstructFloat16;  break;
+            case 2: op = EOpConstructF16Vec2;  break;
+            case 3: op = EOpConstructF16Vec3;  break;
+            case 4: op = EOpConstructF16Vec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+#endif
+    case EbtInt:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructInt;   break;
+        case 2: op = EOpConstructIVec2; break;
+        case 3: op = EOpConstructIVec3; break;
+        case 4: op = EOpConstructIVec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtUint:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructUint;  break;
+        case 2: op = EOpConstructUVec2; break;
+        case 3: op = EOpConstructUVec3; break;
+        case 4: op = EOpConstructUVec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtInt64:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructInt64;   break;
+        case 2: op = EOpConstructI64Vec2; break;
+        case 3: op = EOpConstructI64Vec3; break;
+        case 4: op = EOpConstructI64Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtUint64:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructUint64;  break;
+        case 2: op = EOpConstructU64Vec2; break;
+        case 3: op = EOpConstructU64Vec3; break;
+        case 4: op = EOpConstructU64Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtBool:
+        switch(type.getVectorSize()) {
+        case 1:  op = EOpConstructBool;  break;
+        case 2:  op = EOpConstructBVec2; break;
+        case 3:  op = EOpConstructBVec3; break;
+        case 4:  op = EOpConstructBVec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    default:
+        break;
+    }
+
+    return op;
+}
+
+//
+// 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 nullptr was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right)
+{
+    if (left == nullptr && right == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = nullptr;
+    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);
+
+    return aggNode;
+}
+
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& loc)
+{
+    TIntermAggregate* aggNode = growAggregate(left, right);
+    if (aggNode)
+        aggNode->setLoc(loc);
+
+    return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless nullptr was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node)
+{
+    if (node == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->getSequence().push_back(node);
+    aggNode->setLoc(node->getLoc());
+
+    return aggNode;
+}
+
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& loc)
+{
+    if (node == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->getSequence().push_back(node);
+    aggNode->setLoc(loc);
+
+    return aggNode;
+}
+
+//
+// Make an aggregate with an empty sequence.
+//
+TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
+{
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->setLoc(loc);
+
+    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& loc)
+{
+    //
+    // Don't prune the false path for compile-time constants; it's needed
+    // for static access analysis.
+    //
+
+    TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+    node->setLoc(loc);
+
+    return node;
+}
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
+{
+    // However, the lowest precedence operators of the sequence operator ( , ) and the assignment operators
+    // ... are not included in the operators that can create a constant expression.
+    //
+    // if (left->getType().getQualifier().storage == EvqConst &&
+    //    right->getType().getQualifier().storage == EvqConst) {
+
+    //    return right;
+    //}
+
+    TIntermTyped *commaAggregate = growAggregate(left, right, loc);
+    commaAggregate->getAsAggregate()->setOperator(EOpComma);
+    commaAggregate->setType(right->getType());
+    commaAggregate->getWritableType().getQualifier().makeTemporary();
+
+    return commaAggregate;
+}
+
+TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type, const TString* name, const TSourceLoc& loc)
+{
+    TIntermMethod* method = new TIntermMethod(object, type, *name);
+    method->setLoc(loc);
+
+    return method;
+}
+
+//
+// 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 nullptr if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc)
+{
+    //
+    // 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 nullptr;
+    }
+
+    // After conversion, types have to match.
+    if (falseBlock->getType() != trueBlock->getType())
+        return nullptr;
+
+    //
+    // See if all the operands are constant, then fold it otherwise not.
+    //
+
+    if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+        if (cond->getAsConstantUnion()->getConstArray()[0].getBConst())
+            return trueBlock;
+        else
+            return falseBlock;
+    }
+
+    //
+    // Make a selection node.
+    //
+    TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+    node->getQualifier().makeTemporary();
+    node->setLoc(loc);
+    node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
+
+    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 TConstUnionArray& unionArray, const TType& t, const TSourceLoc& loc, bool literal) const
+{
+    TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
+    node->getQualifier().storage = EvqConst;
+    node->setLoc(loc);
+    if (literal)
+        node->setLiteral();
+
+    return node;
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(int i, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setIConst(i);
+
+    return addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned int u, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setUConst(u);
+
+    return addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(long long i64, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setI64Const(i64);
+
+    return addConstantUnion(unionArray, TType(EbtInt64, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned long long u64, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setU64Const(u64);
+
+    return addConstantUnion(unionArray, TType(EbtUint64, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(bool b, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setBConst(b);
+
+    return addConstantUnion(unionArray, TType(EbtBool, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseType, const TSourceLoc& loc, bool literal) const
+{
+#ifdef AMD_EXTENSIONS
+    assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16);
+#else
+    assert(baseType == EbtFloat || baseType == EbtDouble);
+#endif
+
+    TConstUnionArray unionArray(1);
+    unionArray[0].setDConst(d);
+
+    return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
+}
+
+// Put vector swizzle selectors onto the given sequence
+void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
+{
+    TIntermConstantUnion* constIntNode = addConstantUnion(selector, loc);
+    sequence.push_back(constIntNode);
+}
+
+// Put matrix swizzle selectors onto the given sequence
+void TIntermediate::pushSelector(TIntermSequence& sequence, const TMatrixSelector& selector, const TSourceLoc& loc)
+{
+    TIntermConstantUnion* constIntNode = addConstantUnion(selector.coord1, loc);
+    sequence.push_back(constIntNode);
+    constIntNode = addConstantUnion(selector.coord2, loc);
+    sequence.push_back(constIntNode);
+}
+
+// Make an aggregate node that has a sequence of all selectors.
+template TIntermTyped* TIntermediate::addSwizzle<TVectorSelector>(TSwizzleSelectors<TVectorSelector>& selector, const TSourceLoc& loc);
+template TIntermTyped* TIntermediate::addSwizzle<TMatrixSelector>(TSwizzleSelectors<TMatrixSelector>& selector, const TSourceLoc& loc);
+template<typename selectorType>
+TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors<selectorType>& selector, const TSourceLoc& loc)
+{
+    TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+    node->setLoc(loc);
+    TIntermSequence &sequenceVector = node->getSequence();
+
+    for (int i = 0; i < selector.size(); i++)
+        pushSelector(sequenceVector, selector[i], loc);
+
+    return node;
+}
+
+//
+// Follow the left branches down to the root of an l-value
+// expression (just "." and []).
+//
+// Return the base of the l-value (where following indexing quits working).
+// Return nullptr if a chain following dereferences cannot be followed.
+//
+// 'swizzleOkay' says whether or not it is okay to consider a swizzle
+// a valid part of the dereference chain.
+//
+const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay)
+{
+    do {
+        const TIntermBinary* binary = node->getAsBinaryNode();
+        if (binary == nullptr)
+            return node;
+        TOperator op = binary->getOp();
+        if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle)
+            return nullptr;
+        if (! swizzleOkay) {
+            if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle)
+                return nullptr;
+            if ((op == EOpIndexDirect || op == EOpIndexIndirect) &&
+                (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) &&
+                ! binary->getLeft()->getType().isArray())
+                return nullptr;
+        }
+        node = node->getAsBinaryNode()->getLeft();
+    } while (true);
+}
+
+//
+// Create while and do-while loop nodes.
+//
+TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
+{
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node->setLoc(loc);
+
+    return node;
+}
+
+//
+// Create a for-loop sequence.
+//
+TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
+{
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node->setLoc(loc);
+
+    // make a sequence of the initializer and statement
+    TIntermAggregate* loopSequence = makeAggregate(initializer, loc);
+    loopSequence = growAggregate(loopSequence, node);
+    loopSequence->setOperator(EOpSequence);
+
+    return loopSequence;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc)
+{
+    return addBranch(branchOp, nullptr, loc);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& loc)
+{
+    TIntermBranch* node = new TIntermBranch(branchOp, expression);
+    node->setLoc(loc);
+
+    return node;
+}
+
+//
+// This is to be executed after the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
+{
+    if (root == nullptr)
+        return true;
+
+    // Finish off the top-level sequence
+    TIntermAggregate* aggRoot = root->getAsAggregate();
+    if (aggRoot && aggRoot->getOp() == EOpNull)
+        aggRoot->setOperator(EOpSequence);
+
+    // Propagate 'noContraction' label in backward from 'precise' variables.
+    glslang::PropagateNoContraction(*this);
+
+    return true;
+}
+
+void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
+{
+    // Add top-level nodes for declarations that must be checked cross
+    // compilation unit by a linker, yet might not have been referenced
+    // by the AST.
+    //
+    // Almost entirely, translation of symbols is driven by what's present
+    // in the AST traversal, not by translating the symbol table.
+    //
+    // However, there are some special cases:
+    //  - From the specification: "Special built-in inputs gl_VertexID and
+    //    gl_InstanceID are also considered active vertex attributes."
+    //  - Linker-based type mismatch error reporting needs to see all
+    //    uniforms/ins/outs variables and blocks.
+    //  - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active.
+    //
+
+    // if (ftransformUsed) {
+        // TODO: 1.1 lowering functionality: track ftransform() usage
+    //    addSymbolLinkageNode(root, symbolTable, "gl_Vertex");
+    //    addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix");
+    //}
+
+    if (language == EShLangVertex) {
+        // the names won't be found in the symbol table unless the versions are right,
+        // so version logic does not need to be repeated here
+        addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID");
+        addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID");
+    }
+
+    // Add a child to the root node for the linker objects
+    linkage->setOperator(EOpLinkerObjects);
+    treeRoot = growAggregate(treeRoot, linkage);
+}
+
+//
+// Add the given name or symbol to the list of nodes at the end of the tree used
+// for link-time checking and external linkage.
+//
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (symbol)
+        addSymbolLinkageNode(linkage, *symbol->getAsVariable());
+}
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
+{
+    const TVariable* variable = symbol.getAsVariable();
+    if (! variable) {
+        // This must be a member of an anonymous block, and we need to add the whole block
+        const TAnonMember* anon = symbol.getAsAnonMember();
+        variable = &anon->getAnonContainer();
+    }
+    TIntermSymbol* node = addSymbol(*variable);
+    linkage = growAggregate(linkage, node);
+}
+
+//
+// Add a caller->callee relationship to the call graph.
+// Assumes the strings are unique per signature.
+//
+void TIntermediate::addToCallGraph(TInfoSink& /*infoSink*/, const TString& caller, const TString& callee)
+{
+    // Duplicates are okay, but faster to not keep them, and they come grouped by caller,
+    // as long as new ones are push on the same end we check on for duplicates
+    for (TGraph::const_iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        if (call->caller != caller)
+            break;
+        if (call->callee == callee)
+            return;
+    }
+
+    callGraph.push_front(TCall(caller, callee));
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::removeTree()
+{
+    if (treeRoot)
+        RemoveAllTreeNodes(treeRoot);
+}
+
+//
+// Implement the part of KHR_vulkan_glsl that lists the set of operations
+// that can result in a specialization constant operation.
+//
+// "5.x Specialization Constant Operations"
+//
+//    Only some operations discussed in this section may be applied to a
+//    specialization constant and still yield a result that is as
+//    specialization constant.  The operations allowed are listed below.
+//    When a specialization constant is operated on with one of these
+//    operators and with another constant or specialization constant, the
+//    result is implicitly a specialization constant.
+//
+//     - int(), uint(), and bool() constructors for type conversions
+//       from any of the following types to any of the following types:
+//         * int
+//         * uint
+//         * bool
+//     - vector versions of the above conversion constructors
+//     - allowed implicit conversions of the above
+//     - swizzles (e.g., foo.yx)
+//     - The following when applied to integer or unsigned integer types:
+//         * unary negative ( - )
+//         * binary operations ( + , - , * , / , % )
+//         * shift ( <<, >> )
+//         * bitwise operations ( & , | , ^ )
+//     - The following when applied to integer or unsigned integer scalar types:
+//         * comparison ( == , != , > , >= , < , <= )
+//     - The following when applied to the Boolean scalar type:
+//         * not ( ! )
+//         * logical operations ( && , || , ^^ )
+//         * comparison ( == , != )"
+//
+// This function just handles binary and unary nodes.  Construction
+// rules are handled in construction paths that are not covered by the unary
+// and binary paths, while required conversions will still show up here
+// as unary converters in the from a construction operator.
+//
+bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
+{
+    // The operations resulting in floating point are quite limited
+    // (However, some floating-point operations result in bool, like ">",
+    // so are handled later.)
+    if (node.getType().isFloatingDomain()) {
+        switch (node.getOp()) {
+        case EOpIndexDirect:
+        case EOpIndexIndirect:
+        case EOpIndexDirectStruct:
+        case EOpVectorSwizzle:
+        case EOpConvFloatToDouble:
+        case EOpConvDoubleToFloat:
+#ifdef AMD_EXTENSIONS
+        case EOpConvFloat16ToFloat:
+        case EOpConvFloatToFloat16:
+        case EOpConvFloat16ToDouble:
+        case EOpConvDoubleToFloat16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // Check for floating-point arguments
+    if (const TIntermBinary* bin = node.getAsBinaryNode())
+        if (bin->getLeft() ->getType().isFloatingDomain() ||
+            bin->getRight()->getType().isFloatingDomain())
+            return false;
+
+    // So, for now, we can assume everything left is non-floating-point...
+
+    // Now check for integer/bool-based operations
+    switch (node.getOp()) {
+
+    // dereference/swizzle
+    case EOpIndexDirect:
+    case EOpIndexIndirect:
+    case EOpIndexDirectStruct:
+    case EOpVectorSwizzle:
+
+    // conversion constructors
+    case EOpConvIntToBool:
+    case EOpConvUintToBool:
+    case EOpConvUintToInt:
+    case EOpConvBoolToInt:
+    case EOpConvIntToUint:
+    case EOpConvBoolToUint:
+    case EOpConvInt64ToBool:
+    case EOpConvBoolToInt64:
+    case EOpConvUint64ToBool:
+    case EOpConvBoolToUint64:
+    case EOpConvInt64ToInt:
+    case EOpConvIntToInt64:
+    case EOpConvUint64ToUint:
+    case EOpConvUintToUint64:
+    case EOpConvInt64ToUint64:
+    case EOpConvUint64ToInt64:
+    case EOpConvInt64ToUint:
+    case EOpConvUintToInt64:
+    case EOpConvUint64ToInt:
+    case EOpConvIntToUint64:
+
+    // unary operations
+    case EOpNegative:
+    case EOpLogicalNot:
+    case EOpBitwiseNot:
+
+    // binary operations
+    case EOpAdd:
+    case EOpSub:
+    case EOpMul:
+    case EOpVectorTimesScalar:
+    case EOpDiv:
+    case EOpMod:
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+    case EOpLogicalAnd:
+    case EOpEqual:
+    case EOpNotEqual:
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        return true;
+    default:
+        return false;
+    }
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+// Returns true if state is modified.
+//
+bool TIntermOperator::modifiesState() 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:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        return true;
+    default:
+        return false;
+    }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+    return op > EOpConstructGuardStart && op < EOpConstructGuardEnd;
+}
+
+//
+// Make sure the type of an operator is appropriate for its
+// combination of operation and operand type.  This will invoke
+// promoteUnary, promoteBinary, etc as needed.
+//
+// Returns false if nothing makes sense.
+//
+bool TIntermediate::promote(TIntermOperator* node)
+{
+    if (node == nullptr)
+        return false;
+
+    if (node->getAsUnaryNode())
+        return promoteUnary(*node->getAsUnaryNode());
+
+    if (node->getAsBinaryNode())
+        return promoteBinary(*node->getAsBinaryNode());
+
+    if (node->getAsAggregate())
+        return promoteAggregate(*node->getAsAggregate());
+
+    return false;
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteUnary(TIntermUnary& node)
+{
+    const TOperator op    = node.getOp();
+    TIntermTyped* operand = node.getOperand();
+
+    switch (op) {
+    case EOpLogicalNot:
+        // Convert operand to a boolean type
+        if (operand->getBasicType() != EbtBool) {
+            // Add constructor to boolean type. If that fails, we can't do it, so return false.
+            TIntermTyped* converted = convertToBasicType(op, EbtBool, operand);
+            if (converted == nullptr)
+                return false;
+
+            // Use the result of converting the node to a bool.
+            node.setOperand(operand = converted); // also updates stack variable
+        }
+        break;
+    case EOpBitwiseNot:
+        if (operand->getBasicType() != EbtInt &&
+            operand->getBasicType() != EbtUint &&
+            operand->getBasicType() != EbtInt64 &&
+            operand->getBasicType() != EbtUint64)
+
+            return false;
+        break;
+    case EOpNegative:
+    case EOpPostIncrement:
+    case EOpPostDecrement:
+    case EOpPreIncrement:
+    case EOpPreDecrement:
+        if (operand->getBasicType() != EbtInt &&
+            operand->getBasicType() != EbtUint &&
+            operand->getBasicType() != EbtInt64 &&
+            operand->getBasicType() != EbtUint64 &&
+            operand->getBasicType() != EbtFloat &&
+#ifdef AMD_EXTENSIONS
+            operand->getBasicType() != EbtFloat16 &&
+#endif
+            operand->getBasicType() != EbtDouble)
+
+            return false;
+        break;
+
+    default:
+        if (operand->getBasicType() != EbtFloat)
+
+            return false;
+    }
+
+    node.setType(operand->getType());
+    node.getWritableType().getQualifier().makeTemporary();
+
+    return true;
+}
+
+void TIntermUnary::updatePrecision()
+{
+#ifdef AMD_EXTENSIONS
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
+#else
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) {
+#endif
+        if (operand->getQualifier().precision > getQualifier().precision)
+            getQualifier().precision = operand->getQualifier().precision;
+    }
+}
+
+// If it is not already, convert this node to the given basic type.
+TIntermTyped* TIntermediate::convertToBasicType(TOperator op, TBasicType basicType, TIntermTyped* node) const
+{
+    if (node == nullptr)
+        return nullptr;
+
+    // It's already this basic type: nothing needs to be done, so use the node directly.
+    if (node->getBasicType() == basicType)
+        return node;
+
+    const TType& type = node->getType();
+    const TType newType(basicType, type.getQualifier().storage,
+                        type.getVectorSize(), type.getMatrixCols(), type.getMatrixRows(), type.isVector());
+
+    // Add constructor to the right vectorness of the right type. If that fails, we can't do it, so return nullptr.
+    return addConversion(op, newType, node);
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteBinary(TIntermBinary& node)
+{
+    TOperator     op    = node.getOp();
+    TIntermTyped* left  = node.getLeft();
+    TIntermTyped* right = node.getRight();
+
+    // Arrays and structures have to be exact matches.
+    if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct)
+        && left->getType() != right->getType())
+        return false;
+
+    // Base assumption:  just make the type the same as the left
+    // operand.  Only deviations from this will be coded.
+    node.setType(left->getType());
+    node.getWritableType().getQualifier().clear();
+
+    // Composite and opaque types don't having pending operator changes, e.g.,
+    // array, structure, and samplers.  Just establish final type and correctness.
+    if (left->isArray() || left->getBasicType() == EbtStruct || left->getBasicType() == EbtSampler) {
+        switch (op) {
+        case EOpEqual:
+        case EOpNotEqual:
+            if (left->getBasicType() == EbtSampler) {
+                // can't compare samplers
+                return false;
+            } else {
+                // Promote to conditional
+                node.setType(TType(EbtBool));
+            }
+
+            return true;
+
+        case EOpAssign:
+            // Keep type from above
+
+            return true;
+
+        default:
+            return false;
+        }
+    }
+
+    //
+    // We now have only scalars, vectors, and matrices to worry about.
+    //
+
+    // Do general type checks against individual operands (comparing left and right is coming up, checking mixed shapes after that)
+    switch (op) {
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        // Relational comparisons need numeric types and will promote to scalar Boolean.
+        if (left->getBasicType() == EbtBool)
+            return false;
+
+        node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
+        break;
+
+    case EOpEqual:
+    case EOpNotEqual:
+        if (getSource() == EShSourceHlsl) {
+            const int resultWidth = std::max(left->getVectorSize(), right->getVectorSize());
+
+            // In HLSL, == or != on vectors means component-wise comparison.
+            if (resultWidth > 1) {
+                op = (op == EOpEqual) ? EOpVectorEqual : EOpVectorNotEqual;
+                node.setOp(op);
+            }
+
+            node.setType(TType(EbtBool, EvqTemporary, resultWidth));
+        } else {
+            // All the above comparisons result in a bool (but not the vector compares)
+            node.setType(TType(EbtBool));
+        }
+        break;
+
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+        if (getSource() == EShSourceHlsl) {
+            TIntermTyped* convertedL = convertToBasicType(op, EbtBool, left);
+            TIntermTyped* convertedR = convertToBasicType(op, EbtBool, right);
+            if (convertedL == nullptr || convertedR == nullptr)
+                return false;
+            node.setLeft(left = convertedL);   // also updates stack variable
+            node.setRight(right = convertedR); // also updates stack variable
+        } else {
+            // logical ops operate only on scalar Booleans and will promote to scalar Boolean.
+            if (left->getBasicType() != EbtBool || left->isVector() || left->isMatrix())
+                return false;
+        }
+
+        node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
+
+        break;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+
+    case EOpMod:
+    case EOpModAssign:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+        if (getSource() == EShSourceHlsl)
+            break;
+
+        // Check for integer-only operands.
+        if ((left->getBasicType() != EbtInt &&  left->getBasicType() != EbtUint &&
+             left->getBasicType() != EbtInt64 &&  left->getBasicType() != EbtUint64) ||
+            (right->getBasicType() != EbtInt && right->getBasicType() != EbtUint &&
+             right->getBasicType() != EbtInt64 && right->getBasicType() != EbtUint64))
+            return false;
+        if (left->isMatrix() || right->isMatrix())
+            return false;
+
+        break;
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+    case EOpMul:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpDivAssign:
+        // check for non-Boolean operands
+        if (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)
+            return false;
+
+    default:
+        break;
+    }
+
+    // Compare left and right, and finish with the cases where the operand types must match
+    switch (op) {
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+
+    case EOpEqual:
+    case EOpNotEqual:
+    case EOpVectorEqual:
+    case EOpVectorNotEqual:
+
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+        return left->getType() == right->getType();
+
+    // no shifts: they can mix types (scalar int can shift a vector uint, etc.)
+
+    case EOpMod:
+    case EOpModAssign:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+        // Quick out in case the types do match
+        if (left->getType() == right->getType())
+            return true;
+
+        // Fall through
+
+    case EOpMul:
+    case EOpMulAssign:
+        // At least the basic type has to match
+        if (left->getBasicType() != right->getBasicType())
+            return false;
+
+    default:
+        break;
+    }
+
+    // Finish handling the case, for all ops, where both operands are scalars.
+    if (left->isScalar() && right->isScalar())
+        return true;
+
+    // Finish handling the case, for all ops, where there are two vectors of different sizes
+    if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
+        return false;
+
+    //
+    // We now have a mix of scalars, vectors, or matrices, for non-relational operations.
+    //
+
+    // Can these two operands be combined, what is the resulting type?
+    TBasicType basicType = left->getBasicType();
+    switch (op) {
+    case EOpMul:
+        if (!left->isMatrix() && right->isMatrix()) {
+            if (left->isVector()) {
+                if (left->getVectorSize() != right->getMatrixRows())
+                    return false;
+                node.setOp(op = EOpVectorTimesMatrix);
+                node.setType(TType(basicType, EvqTemporary, right->getMatrixCols()));
+            } else {
+                node.setOp(op = EOpMatrixTimesScalar);
+                node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows()));
+            }
+        } else if (left->isMatrix() && !right->isMatrix()) {
+            if (right->isVector()) {
+                if (left->getMatrixCols() != right->getVectorSize())
+                    return false;
+                node.setOp(op = EOpMatrixTimesVector);
+                node.setType(TType(basicType, EvqTemporary, left->getMatrixRows()));
+            } else {
+                node.setOp(op = EOpMatrixTimesScalar);
+            }
+        } else if (left->isMatrix() && right->isMatrix()) {
+            if (left->getMatrixCols() != right->getMatrixRows())
+                return false;
+            node.setOp(op = EOpMatrixTimesMatrix);
+            node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows()));
+        } else if (! left->isMatrix() && ! right->isMatrix()) {
+            if (left->isVector() && right->isVector()) {
+                ; // leave as component product
+            } else if (left->isVector() || right->isVector()) {
+                node.setOp(op = EOpVectorTimesScalar);
+                if (right->isVector())
+                    node.setType(TType(basicType, EvqTemporary, right->getVectorSize()));
+            }
+        } else {
+            return false;
+        }
+        break;
+    case EOpMulAssign:
+        if (! left->isMatrix() && right->isMatrix()) {
+            if (left->isVector()) {
+                if (left->getVectorSize() != right->getMatrixRows() || left->getVectorSize() != right->getMatrixCols())
+                    return false;
+                node.setOp(op = EOpVectorTimesMatrixAssign);
+            } else {
+                return false;
+            }
+        } else if (left->isMatrix() && !right->isMatrix()) {
+            if (right->isVector()) {
+                return false;
+            } else {
+                node.setOp(op = EOpMatrixTimesScalarAssign);
+            }
+        } else if (left->isMatrix() && right->isMatrix()) {
+            if (left->getMatrixCols() != left->getMatrixRows() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows())
+                return false;
+            node.setOp(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;
+                node.setOp(op = EOpVectorTimesScalarAssign);
+            }
+        } else {
+            return false;
+        }
+        break;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+        if (right->isVector() && (! left->isVector() || right->getVectorSize() != left->getVectorSize()))
+            return false;
+        break;
+
+    case EOpAssign:
+        if (left->getVectorSize() != right->getVectorSize() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows())
+            return false;
+        // fall through
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+    case EOpMod:
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+
+        if ((left->isMatrix() && right->isVector()) ||
+            (left->isVector() && right->isMatrix()) ||
+            left->getBasicType() != right->getBasicType())
+            return false;
+        if (left->isMatrix() && right->isMatrix() && (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows()))
+            return false;
+        if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
+            return false;
+        if (right->isVector() || right->isMatrix()) {
+            node.getWritableType().shallowCopy(right->getType());
+            node.getWritableType().getQualifier().makeTemporary();
+        }
+        break;
+
+    default:
+        return false;
+    }
+
+    //
+    // One more check for assignment.
+    //
+    switch (op) {
+    // The resulting type has to match the left operand.
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        if (node.getType() != left->getType())
+            return false;
+        break;
+    default:
+        break;
+    }
+
+    return true;
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteAggregate(TIntermAggregate& node)
+{
+    TOperator op = node.getOp();
+    TIntermSequence& args = node.getSequence();
+    const int numArgs = static_cast<int>(args.size());
+
+    // Presently, only hlsl does intrinsic promotions.
+    if (getSource() != EShSourceHlsl)
+        return true;
+
+    // set of opcodes that can be promoted in this manner.
+    switch (op) {
+    case EOpAtan:
+    case EOpClamp:
+    case EOpCross:
+    case EOpDistance:
+    case EOpDot:
+    case EOpDst:
+    case EOpFaceForward:
+    // case EOpFindMSB: TODO:
+    // case EOpFindLSB: TODO:
+    case EOpFma:
+    case EOpMod:
+    case EOpFrexp:
+    case EOpLdexp:
+    case EOpMix:
+    case EOpLit:
+    case EOpMax:
+    case EOpMin:
+    case EOpModf:
+    // case EOpGenMul: TODO:
+    case EOpPow:
+    case EOpReflect:
+    case EOpRefract:
+    // case EOpSinCos: TODO:
+    case EOpSmoothStep:
+    case EOpStep:
+        break;
+    default:
+        return true;
+    }
+
+    // TODO: array and struct behavior
+
+    // Try converting all nodes to the given node's type
+    TIntermSequence convertedArgs(numArgs, nullptr);
+
+    // Try to convert all types to the nonConvArg type.
+    for (int nonConvArg = 0; nonConvArg < numArgs; ++nonConvArg) {
+        // Try converting all args to this arg's type
+        for (int convArg = 0; convArg < numArgs; ++convArg) {
+            convertedArgs[convArg] = addConversion(op, args[nonConvArg]->getAsTyped()->getType(),
+                                                   args[convArg]->getAsTyped());
+        }
+
+        // If we successfully converted all the args, use the result.
+        if (std::all_of(convertedArgs.begin(), convertedArgs.end(),
+                        [](const TIntermNode* node) { return node != nullptr; })) {
+
+            std::swap(args, convertedArgs);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void TIntermBinary::updatePrecision()
+{
+#ifdef AMD_EXTENSIONS
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
+#else
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) {
+#endif
+        getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision);
+        if (getQualifier().precision != EpqNone) {
+            left->propagatePrecision(getQualifier().precision);
+            right->propagatePrecision(getQualifier().precision);
+        }
+    }
+}
+
+void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
+{
+#ifdef AMD_EXTENSIONS
+    if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
+#else
+    if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat))
+#endif
+        return;
+
+    getQualifier().precision = newPrecision;
+
+    TIntermBinary* binaryNode = getAsBinaryNode();
+    if (binaryNode) {
+        binaryNode->getLeft()->propagatePrecision(newPrecision);
+        binaryNode->getRight()->propagatePrecision(newPrecision);
+
+        return;
+    }
+
+    TIntermUnary* unaryNode = getAsUnaryNode();
+    if (unaryNode) {
+        unaryNode->getOperand()->propagatePrecision(newPrecision);
+
+        return;
+    }
+
+    TIntermAggregate* aggregateNode = getAsAggregate();
+    if (aggregateNode) {
+        TIntermSequence operands = aggregateNode->getSequence();
+        for (unsigned int i = 0; i < operands.size(); ++i) {
+            TIntermTyped* typedNode = operands[i]->getAsTyped();
+            if (! typedNode)
+                break;
+            typedNode->propagatePrecision(newPrecision);
+        }
+
+        return;
+    }
+
+    TIntermSelection* selectionNode = getAsSelectionNode();
+    if (selectionNode) {
+        TIntermTyped* typedNode = selectionNode->getTrueBlock()->getAsTyped();
+        if (typedNode) {
+            typedNode->propagatePrecision(newPrecision);
+            typedNode = selectionNode->getFalseBlock()->getAsTyped();
+            if (typedNode)
+                typedNode->propagatePrecision(newPrecision);
+        }
+
+        return;
+    }
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
+{
+    const TConstUnionArray& rightUnionArray = node->getConstArray();
+    int size = node->getType().computeNumComponents();
+
+    TConstUnionArray leftUnionArray(size);
+
+    for (int i=0; i < size; i++) {
+        switch (promoteTo) {
+        case EbtFloat:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtDouble:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+            case EbtFloat16:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+#endif
+        case EbtInt:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtUint:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtUint:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtBool:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
+                break;
+            case EbtUint:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getUConst() != 0);
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getI64Const() != 0);
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getU64Const() != 0);
+                break;
+            case EbtBool:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setBConst(rightUnionArray[i].getDConst() != 0.0);
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtInt64:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtUint64:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtBool:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        default:
+            return node;
+        }
+    }
+
+    const TType& t = node->getType();
+
+    return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier().storage, t.getVectorSize(), t.getMatrixCols(), t.getMatrixRows()),
+                            node->getLoc());
+}
+
+void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
+{
+    assert(!pragmaTable);
+    pragmaTable = new TPragmaTable();
+    *pragmaTable = pTable;
+}
+
+} // end namespace glslang

+ 136 - 0
src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h

@@ -0,0 +1,136 @@
+//
+// Copyright (C) 2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "reflection.h"
+#include "localintermediate.h"
+
+#include "gl_types.h"
+
+#include <list>
+#include <unordered_set>
+
+namespace glslang {
+
+//
+// The traverser: mostly pass through, except
+//  - processing function-call nodes to push live functions onto the stack of functions to process
+//  - processing selection nodes to trim semantically dead code
+//
+// This is in the glslang namespace directly so it can be a friend of TReflection.
+// This can be derived from to implement reflection database traversers or
+// binding mappers: anything that wants to traverse the live subset of the tree.
+//
+
+class TLiveTraverser : public TIntermTraverser {
+public:
+    TLiveTraverser(const TIntermediate& i, bool traverseAll = false,
+                   bool preVisit = true, bool inVisit = false, bool postVisit = false) :
+        TIntermTraverser(preVisit, inVisit, postVisit),
+        intermediate(i), traverseAll(traverseAll)
+    { }
+
+    //
+    // Given a function name, find its subroot in the tree, and push it onto the stack of
+    // functions left to process.
+    //
+    void pushFunction(const TString& name)
+    {
+        TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
+        for (unsigned int f = 0; f < globals.size(); ++f) {
+            TIntermAggregate* candidate = globals[f]->getAsAggregate();
+            if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
+                functions.push_back(candidate);
+                break;
+            }
+        }
+    }
+
+    typedef std::list<TIntermAggregate*> TFunctionStack;
+    TFunctionStack functions;
+
+protected:
+    // To catch which function calls are not dead, and hence which functions must be visited.
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node)
+    {
+        if (!traverseAll)
+            if (node->getOp() == EOpFunctionCall)
+                addFunctionCall(node);
+
+        return true; // traverse this subtree
+    }
+
+    // To prune semantically dead paths.
+    virtual bool visitSelection(TVisit /* visit */,  TIntermSelection* node)
+    {
+        if (traverseAll)
+            return true; // traverse all code
+
+        TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
+        if (constant) {
+            // cull the path that is dead
+            if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
+                node->getTrueBlock()->traverse(this);
+            if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
+                node->getFalseBlock()->traverse(this);
+
+            return false; // don't traverse any more, we did it all above
+        } else
+            return true; // traverse the whole subtree
+    }
+
+    // Track live functions as well as uniforms, so that we don't visit dead functions
+    // and only visit each function once.
+    void addFunctionCall(TIntermAggregate* call)
+    {
+        // // just use the map to ensure we process each function at most once
+        if (liveFunctions.find(call->getName()) == liveFunctions.end()) {
+            liveFunctions.insert(call->getName());
+            pushFunction(call->getName());
+        }
+    }
+
+    const TIntermediate& intermediate;
+    typedef std::unordered_set<TString> TLiveFunctions;
+    TLiveFunctions liveFunctions;
+    bool traverseAll;
+
+private:
+    // prevent copy & copy construct
+    TLiveTraverser(TLiveTraverser&);
+    TLiveTraverser& operator=(TLiveTraverser&);
+};
+
+} // namespace glslang

+ 604 - 0
src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp

@@ -0,0 +1,604 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+// Implement the TParseContextBase class.
+
+#include <cstdarg>
+
+#include "ParseHelper.h"
+
+extern int yyparse(glslang::TParseContext*);
+
+namespace glslang {
+
+//
+// Used to output syntax, parsing, and semantic errors.
+//
+
+void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason,
+                                      const char* szToken,
+                                      const char* szExtraInfoFormat,
+                                      TPrefixType prefix, va_list args)
+{
+    const int maxSize = MaxTokenLength + 200;
+    char szExtraInfo[maxSize];
+
+    safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args);
+
+    infoSink.info.prefix(prefix);
+    infoSink.info.location(loc);
+    infoSink.info << "'" << szToken <<  "' : " << szReason << " " << szExtraInfo << "\n";
+
+    if (prefix == EPrefixError) {
+        ++numErrors;
+    }
+}
+
+void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken,
+                                     const char* szExtraInfoFormat, ...)
+{
+    if (messages & EShMsgOnlyPreprocessor)
+        return;
+    va_list args;
+    va_start(args, szExtraInfoFormat);
+    outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
+    va_end(args);
+
+    if ((messages & EShMsgCascadingErrors) == 0)
+        currentScanner->setEndOfInput();
+}
+
+void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken,
+                                    const char* szExtraInfoFormat, ...)
+{
+    if (suppressWarnings())
+        return;
+    va_list args;
+    va_start(args, szExtraInfoFormat);
+    outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
+    va_end(args);
+}
+
+void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken,
+                                       const char* szExtraInfoFormat, ...)
+{
+    va_list args;
+    va_start(args, szExtraInfoFormat);
+    outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
+    va_end(args);
+
+    if ((messages & EShMsgCascadingErrors) == 0)
+        currentScanner->setEndOfInput();
+}
+
+void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken,
+                                      const char* szExtraInfoFormat, ...)
+{
+    va_list args;
+    va_start(args, szExtraInfoFormat);
+    outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
+    va_end(args);
+}
+
+//
+// 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 there was an error.
+//
+bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
+{
+    TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+    if (binaryNode) {
+        switch(binaryNode->getOp()) {
+        case EOpIndexDirect:
+        case EOpIndexIndirect:     // fall through
+        case EOpIndexDirectStruct: // fall through
+        case EOpVectorSwizzle:
+        case EOpMatrixSwizzle:
+            return lValueErrorCheck(loc, op, binaryNode->getLeft());
+        default:
+            break;
+        }
+        error(loc, " l-value required", op, "", "");
+
+        return true;
+    }
+
+    const char* symbol = nullptr;
+    TIntermSymbol* symNode = node->getAsSymbolNode();
+    if (symNode != nullptr)
+        symbol = symNode->getName().c_str();
+
+    const char* message = nullptr;
+    switch (node->getQualifier().storage) {
+    case EvqConst:          message = "can't modify a const";        break;
+    case EvqConstReadOnly:  message = "can't modify a const";        break;
+    case EvqUniform:        message = "can't modify a uniform";      break;
+    case EvqBuffer:
+        if (node->getQualifier().readonly)
+            message = "can't modify a readonly buffer";
+        break;
+
+    default:
+        //
+        // Type that can't be written to?
+        //
+        switch (node->getBasicType()) {
+        case EbtSampler:
+            message = "can't modify a sampler";
+            break;
+        case EbtAtomicUint:
+            message = "can't modify an atomic_uint";
+            break;
+        case EbtVoid:
+            message = "can't modify void";
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
+        error(loc, " l-value required", op, "", "");
+
+        return true;
+    }
+
+    //
+    // Everything else is okay, no error.
+    //
+    if (message == nullptr)
+        return false;
+
+    //
+    // If we get here, we have an error and a message.
+    //
+    if (symNode)
+        error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
+    else
+        error(loc, " l-value required", op, "(%s)", message);
+
+    return true;
+}
+
+// Test for and give an error if the node can't be read from.
+void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
+{
+    if (! node)
+        return;
+
+    TIntermBinary* binaryNode = node->getAsBinaryNode();
+    if (binaryNode) {
+        switch(binaryNode->getOp()) {
+        case EOpIndexDirect:
+        case EOpIndexIndirect:
+        case EOpIndexDirectStruct:
+        case EOpVectorSwizzle:
+        case EOpMatrixSwizzle:
+            rValueErrorCheck(loc, op, binaryNode->getLeft());
+        default:
+            break;
+        }
+
+        return;
+    }
+
+    TIntermSymbol* symNode = node->getAsSymbolNode();
+    if (symNode && symNode->getQualifier().writeonly)
+        error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
+}
+
+// Add a linkage symbol node for 'symbol', which
+// must have its type fully edited, as this will snapshot the type.
+// It is okay if symbol becomes invalid before finish().
+void TParseContextBase::trackLinkage(TSymbol& symbol)
+{
+    if (!parsingBuiltins)
+        intermediate.addSymbolLinkageNode(linkage, symbol);
+}
+
+// Add 'symbol' to the list of deferred linkage symbols, which
+// are later processed in finish(), at which point the symbol
+// must still be valid.
+// It is okay if the symbol's type will be subsequently edited.
+void TParseContextBase::trackLinkageDeferred(TSymbol& symbol)
+{
+    if (!parsingBuiltins)
+        linkageSymbols.push_back(&symbol);
+}
+
+// Make a shared symbol have a non-shared version that can be edited by the current
+// compile, such that editing its type will not change the shared version and will
+// effect all nodes already sharing it (non-shallow type),
+// or adopting its full type after being edited (shallow type).
+void TParseContextBase::makeEditable(TSymbol*& symbol)
+{
+    // copyUp() does a deep copy of the type.
+    symbol = symbolTable.copyUp(symbol);
+
+    // Save it (deferred, so it can be edited first) in the AST for linker use.
+    if (symbol)
+        trackLinkageDeferred(*symbol);
+}
+
+// Return a writable version of the variable 'name'.
+//
+// Return nullptr if 'name' is not found.  This should mean
+// something is seriously wrong (e.g., compiler asking self for
+// built-in that doesn't exist).
+TVariable* TParseContextBase::getEditableVariable(const char* name)
+{
+    bool builtIn;
+    TSymbol* symbol = symbolTable.find(name, &builtIn);
+
+    assert(symbol != nullptr);
+    if (symbol == nullptr)
+        return nullptr;
+
+    if (builtIn)
+        makeEditable(symbol);
+
+    return symbol->getAsVariable();
+}
+
+// Select the best matching function for 'call' from 'candidateList'.
+//
+// Assumptions
+//
+// There is no exact match, so a selection algorithm needs to run. That is, the
+// language-specific handler should check for exact match first, to
+// decide what to do, before calling this selector.
+//
+// Input
+//
+//  * list of candidate signatures to select from
+//  * the call
+//  * a predicate function convertible(from, to) that says whether or not type
+//    'from' can implicitly convert to type 'to' (it includes the case of what
+//    the calling language would consider a matching type with no conversion
+//    needed)
+//  * a predicate function better(from1, from2, to1, to2) that says whether or
+//    not a conversion from <-> to2 is considered better than a conversion
+//    from <-> to1 (both in and out directions need testing, as declared by the
+//    formal parameter)
+//
+// Output
+//
+//  * best matching candidate (or none, if no viable candidates found)
+//  * whether there was a tie for the best match (ambiguous overload selection,
+//    caller's choice for how to report)
+//
+const TFunction* TParseContextBase::selectFunction(
+    const TVector<const TFunction*> candidateList,
+    const TFunction& call,
+    std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible,
+    std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
+    /* output */ bool& tie)
+{
+//
+// Operation
+//
+// 1. Prune the input list of candidates down to a list of viable candidates,
+// where each viable candidate has
+//
+//  * at least as many parameters as there are calling arguments, with any
+//    remaining parameters being optional or having default values
+//  * each parameter is true under convertible(A, B), where A is the calling
+//    type for in and B is the formal type, and in addition, for out B is the
+//    calling type and A is the formal type
+//
+// 2. If there are no viable candidates, return with no match.
+//
+// 3. If there is only one viable candidate, it is the best match.
+//
+// 4. If there are multiple viable candidates, select the first viable candidate
+// as the incumbent. Compare the incumbent to the next viable candidate, and if
+// that candidate is better (bullets below), make it the incumbent. Repeat, with
+// a linear walk through the viable candidate list. The final incumbent will be
+// returned as the best match. A viable candidate is better than the incumbent if
+//
+//  * it has a function argument with a better(...) conversion than the incumbent,
+//    for all directions needed by in and out
+//  * the incumbent has no argument with a better(...) conversion then the
+//    candidate, for either in or out (as needed)
+//
+// 5. Check for ambiguity by comparing the best match against all other viable
+// candidates. If any other viable candidate has a function argument with a
+// better(...) conversion than the best candidate (for either in or out
+// directions), return that there was a tie for best.
+//
+
+    tie = false;
+
+    // 1. prune to viable...
+    TVector<const TFunction*> viableCandidates;
+    for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
+        const TFunction& candidate = *(*it);
+
+        // to even be a potential match, number of arguments must be >= the number of
+        // fixed (non-default) parameters, and <= the total (including parameter with defaults).
+        if (call.getParamCount() < candidate.getFixedParamCount() ||
+            call.getParamCount() > candidate.getParamCount())
+            continue;
+
+        // see if arguments are convertible
+        bool viable = true;
+
+        // The call can have fewer parameters than the candidate, if some have defaults.
+        const int paramCount = std::min(call.getParamCount(), candidate.getParamCount());
+        for (int param = 0; param < paramCount; ++param) {
+            if (candidate[param].type->getQualifier().isParamInput()) {
+                if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) {
+                    viable = false;
+                    break;
+                }
+            }
+            if (candidate[param].type->getQualifier().isParamOutput()) {
+                if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) {
+                    viable = false;
+                    break;
+                }
+            }
+        }
+
+        if (viable)
+            viableCandidates.push_back(&candidate);
+    }
+
+    // 2. none viable...
+    if (viableCandidates.size() == 0)
+        return nullptr;
+
+    // 3. only one viable...
+    if (viableCandidates.size() == 1)
+        return viableCandidates.front();
+
+    // 4. find best...
+    const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
+        // is call -> can2 better than call -> can1 for any parameter
+        bool hasBetterParam = false;
+        for (int param = 0; param < call.getParamCount(); ++param) {
+            if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
+                hasBetterParam = true;
+                break;
+            }
+        }
+        return hasBetterParam;
+    };
+
+    const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
+        // is call -> can2 equivalent to call -> can1 for all the call parameters?
+        for (int param = 0; param < call.getParamCount(); ++param) {
+            if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
+                better(*call[param].type, *can2[param].type, *can1[param].type))
+                return false;
+        }
+        return true;
+    };
+
+    const TFunction* incumbent = viableCandidates.front();
+    for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
+        const TFunction& candidate = *(*it);
+        if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent))
+            incumbent = &candidate;
+    }
+
+    // 5. ambiguity...
+    for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) {
+        if (incumbent == *it)
+            continue;
+        const TFunction& candidate = *(*it);
+
+        // In the case of default parameters, it may have an identical initial set, which is
+        // also ambiguous
+        if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate))
+            tie = true;
+    }
+
+    return incumbent;
+}
+
+//
+// Look at a '.' field selector string and change it into numerical selectors
+// for a vector or scalar.
+//
+// Always return some form of swizzle, so the result is always usable.
+//
+void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize,
+                                             TSwizzleSelectors<TVectorSelector>& selector)
+{
+    // Too long?
+    if (compString.size() > MaxSwizzleSelectors)
+        error(loc, "vector swizzle too long", compString.c_str(), "");
+
+    // Use this to test that all swizzle characters are from the same swizzle-namespace-set
+    enum {
+        exyzw,
+        ergba,
+        estpq,
+    } fieldSet[MaxSwizzleSelectors];
+
+    // Decode the swizzle string.
+    int size = std::min(MaxSwizzleSelectors, (int)compString.size());
+    for (int i = 0; i < size; ++i) {
+        switch (compString[i])  {
+        case 'x':
+            selector.push_back(0);
+            fieldSet[i] = exyzw;
+            break;
+        case 'r':
+            selector.push_back(0);
+            fieldSet[i] = ergba;
+            break;
+        case 's':
+            selector.push_back(0);
+            fieldSet[i] = estpq;
+            break;
+
+        case 'y':
+            selector.push_back(1);
+            fieldSet[i] = exyzw;
+            break;
+        case 'g':
+            selector.push_back(1);
+            fieldSet[i] = ergba;
+            break;
+        case 't':
+            selector.push_back(1);
+            fieldSet[i] = estpq;
+            break;
+
+        case 'z':
+            selector.push_back(2);
+            fieldSet[i] = exyzw;
+            break;
+        case 'b':
+            selector.push_back(2);
+            fieldSet[i] = ergba;
+            break;
+        case 'p':
+            selector.push_back(2);
+            fieldSet[i] = estpq;
+            break;
+
+        case 'w':
+            selector.push_back(3);
+            fieldSet[i] = exyzw;
+            break;
+        case 'a':
+            selector.push_back(3);
+            fieldSet[i] = ergba;
+            break;
+        case 'q':
+            selector.push_back(3);
+            fieldSet[i] = estpq;
+            break;
+
+        default:
+            error(loc, "unknown swizzle selection", compString.c_str(), "");
+            break;
+        }
+    }
+
+    // Additional error checking.
+    for (int i = 0; i < selector.size(); ++i) {
+        if (selector[i] >= vecSize) {
+            error(loc, "vector swizzle selection out of range",  compString.c_str(), "");
+            selector.resize(i);
+            break;
+        }
+
+        if (i > 0 && fieldSet[i] != fieldSet[i-1]) {
+            error(loc, "vector swizzle selectors not from the same set", compString.c_str(), "");
+            selector.resize(i);
+            break;
+        }
+    }
+
+    // Ensure it is valid.
+    if (selector.size() == 0)
+        selector.push_back(0);
+}
+
+//
+// Make the passed-in variable information become a member of the
+// global uniform block.  If this doesn't exist yet, make it.
+//
+void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName)
+{
+    // make the global block, if not yet made
+    if (globalUniformBlock == nullptr) {
+        TString& blockName = *NewPoolTString(getGlobalUniformBlockName());
+        TQualifier blockQualifier;
+        blockQualifier.clear();
+        blockQualifier.storage = EvqUniform;
+        TType blockType(new TTypeList, blockName, blockQualifier);
+        TString* instanceName = NewPoolTString("");
+        globalUniformBlock = new TVariable(instanceName, blockType, true);
+        firstNewMember = 0;
+    }
+
+    // add the requested member as a member to the block
+    TType* type = new TType;
+    type->shallowCopy(memberType);
+    type->setFieldName(memberName);
+    TTypeLoc typeLoc = {type, loc};
+    globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc);
+}
+
+//
+// Insert into the symbol table the global uniform block created in
+// growGlobalUniformBlock(). The variables added as members won't be
+// found unless this is done.
+//
+bool TParseContextBase::insertGlobalUniformBlock()
+{
+    if (globalUniformBlock == nullptr)
+        return true;
+
+    int numMembers = (int)globalUniformBlock->getType().getStruct()->size();
+    bool inserted = false;
+    if (firstNewMember == 0) {
+        // This is the first request; we need a normal symbol table insert
+        inserted = symbolTable.insert(*globalUniformBlock);
+        if (inserted)
+            trackLinkageDeferred(*globalUniformBlock);
+    } else if (firstNewMember <= numMembers) {
+        // This is a follow-on request; we need to amend the first insert
+        inserted = symbolTable.amend(*globalUniformBlock, firstNewMember);
+    }
+
+    if (inserted) {
+        finalizeGlobalUniformBlockLayout(*globalUniformBlock);
+        firstNewMember = numMembers;
+    }
+
+    return inserted;
+}
+
+void TParseContextBase::finish()
+{
+    if (!parsingBuiltins) {
+        // Transfer the linkage symbols to AST nodes
+        for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
+            intermediate.addSymbolLinkageNode(linkage, **i);
+        intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
+    }
+}
+
+} // end namespace glslang

+ 6269 - 0
src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp

@@ -0,0 +1,6269 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2015 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "ParseHelper.h"
+#include "Scan.h"
+
+#include "../OSDependent/osinclude.h"
+#include <algorithm>
+
+#include "preprocessor/PpContext.h"
+
+extern int yyparse(glslang::TParseContext*);
+
+namespace glslang {
+
+TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
+                             int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
+                             TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
+            TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
+            contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
+            inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr),
+            limits(resources.limits),
+            atomicUintOffsets(nullptr), anyIndexLimits(false)
+{
+    // decide whether precision qualifiers should be ignored or respected
+    if (profile == EEsProfile || spvVersion.vulkan > 0) {
+        precisionManager.respectPrecisionQualifiers();
+        if (! parsingBuiltins && language == EShLangFragment && profile != EEsProfile && spvVersion.vulkan > 0)
+            precisionManager.warnAboutDefaults();
+    }
+
+    setPrecisionDefaults();
+
+    globalUniformDefaults.clear();
+    globalUniformDefaults.layoutMatrix = ElmColumnMajor;
+    globalUniformDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd140 : ElpShared;
+
+    globalBufferDefaults.clear();
+    globalBufferDefaults.layoutMatrix = ElmColumnMajor;
+    globalBufferDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd430 : ElpShared;
+
+    globalInputDefaults.clear();
+    globalOutputDefaults.clear();
+
+    // "Shaders in the transform
+    // feedback capturing mode have an initial global default of
+    //     layout(xfb_buffer = 0) out;"
+    if (language == EShLangVertex ||
+        language == EShLangTessControl ||
+        language == EShLangTessEvaluation ||
+        language == EShLangGeometry)
+        globalOutputDefaults.layoutXfbBuffer = 0;
+
+    if (language == EShLangGeometry)
+        globalOutputDefaults.layoutStream = 0;
+}
+
+TParseContext::~TParseContext()
+{
+    delete [] atomicUintOffsets;
+}
+
+// Set up all default precisions as needed by the current environment.
+// Intended just as a TParseContext constructor helper.
+void TParseContext::setPrecisionDefaults()
+{
+    // Set all precision defaults to EpqNone, which is correct for all types
+    // when not obeying precision qualifiers, and correct for types that don't
+    // have defaults (thus getting an error on use) when obeying precision
+    // qualifiers.
+
+    for (int type = 0; type < EbtNumTypes; ++type)
+        defaultPrecision[type] = EpqNone;
+
+    for (int type = 0; type < maxSamplerIndex; ++type)
+        defaultSamplerPrecision[type] = EpqNone;
+
+    // replace with real precision defaults for those that have them
+    if (obeyPrecisionQualifiers()) {
+        if (profile == EEsProfile) {
+            // Most don't have defaults, a few default to lowp.
+            TSampler sampler;
+            sampler.set(EbtFloat, Esd2D);
+            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
+            sampler.set(EbtFloat, EsdCube);
+            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
+            sampler.set(EbtFloat, Esd2D);
+            sampler.external = true;
+            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
+        } else {
+            // Non-ES profile
+            // All default to highp.
+            for (int type = 0; type < maxSamplerIndex; ++type)
+                defaultSamplerPrecision[type] = EpqHigh;
+        }
+
+        // If we are parsing built-in computational variables/functions, it is meaningful to record
+        // whether the built-in has no precision qualifier, as that ambiguity
+        // is used to resolve the precision from the supplied arguments/operands instead.
+        // So, we don't actually want to replace EpqNone with a default precision for built-ins.
+        if (! parsingBuiltins) {
+            if (profile == EEsProfile && language == EShLangFragment) {
+                defaultPrecision[EbtInt] = EpqMedium;
+                defaultPrecision[EbtUint] = EpqMedium;
+            } else {
+                defaultPrecision[EbtInt] = EpqHigh;
+                defaultPrecision[EbtUint] = EpqHigh;
+                defaultPrecision[EbtFloat] = EpqHigh;
+            }
+        }
+
+        defaultPrecision[EbtSampler] = EpqLow;
+        defaultPrecision[EbtAtomicUint] = EpqHigh;
+    }
+}
+
+void TParseContext::setLimits(const TBuiltInResource& r)
+{
+    resources = r;
+
+    anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
+                     ! limits.generalConstantMatrixVectorIndexing ||
+                     ! limits.generalSamplerIndexing ||
+                     ! limits.generalUniformIndexing ||
+                     ! limits.generalVariableIndexing ||
+                     ! limits.generalVaryingIndexing;
+
+    intermediate.setLimits(resources);
+
+    // "Each binding point tracks its own current default offset for
+    // inheritance of subsequent variables using the same binding. The initial state of compilation is that all
+    // binding points have an offset of 0."
+    atomicUintOffsets = new int[resources.maxAtomicCounterBindings];
+    for (int b = 0; b < resources.maxAtomicCounterBindings; ++b)
+        atomicUintOffsets[b] = 0;
+}
+
+//
+// Parse an array of strings using yyparse, going through the
+// preprocessor to tokenize the shader strings, then through
+// the GLSL scanner.
+//
+// Returns true for successful acceptance of the shader, false if any errors.
+//
+bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& input, bool versionWillBeError)
+{
+    currentScanner = &input;
+    ppContext.setInput(input, versionWillBeError);
+    yyparse(this);
+
+    finish();
+
+    return numErrors == 0;
+}
+
+// This is called from bison when it has a parse (syntax) error
+// Note though that to stop cascading errors, we set EOF, which
+// will usually cause a syntax error, so be more accurate that
+// compilation is terminating.
+void TParseContext::parserError(const char* s)
+{
+    if (! getScanner()->atEndOfInput() || numErrors == 0)
+        error(getCurrentLoc(), "", "", s, "");
+    else
+        error(getCurrentLoc(), "compilation terminated", "", "");
+}
+
+void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
+{
+    if (pragmaCallback)
+        pragmaCallback(loc.line, tokens);
+
+    if (tokens.size() == 0)
+        return;
+
+    if (tokens[0].compare("optimize") == 0) {
+        if (tokens.size() != 4) {
+            error(loc, "optimize pragma syntax is incorrect", "#pragma", "");
+            return;
+        }
+
+        if (tokens[1].compare("(") != 0) {
+            error(loc, "\"(\" expected after 'optimize' keyword", "#pragma", "");
+            return;
+        }
+
+        if (tokens[2].compare("on") == 0)
+            contextPragma.optimize = true;
+        else if (tokens[2].compare("off") == 0)
+            contextPragma.optimize = false;
+        else {
+            error(loc, "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", "");
+            return;
+        }
+
+        if (tokens[3].compare(")") != 0) {
+            error(loc, "\")\" expected to end 'optimize' pragma", "#pragma", "");
+            return;
+        }
+    } else if (tokens[0].compare("debug") == 0) {
+        if (tokens.size() != 4) {
+            error(loc, "debug pragma syntax is incorrect", "#pragma", "");
+            return;
+        }
+
+        if (tokens[1].compare("(") != 0) {
+            error(loc, "\"(\" expected after 'debug' keyword", "#pragma", "");
+            return;
+        }
+
+        if (tokens[2].compare("on") == 0)
+            contextPragma.debug = true;
+        else if (tokens[2].compare("off") == 0)
+            contextPragma.debug = false;
+        else {
+            error(loc, "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", "");
+            return;
+        }
+
+        if (tokens[3].compare(")") != 0) {
+            error(loc, "\")\" expected to end 'debug' pragma", "#pragma", "");
+            return;
+        }
+    }
+}
+
+//
+// Handle seeing a variable identifier in the grammar.
+//
+TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string)
+{
+    TIntermTyped* node = nullptr;
+
+    // Error check for requiring specific extensions present.
+    if (symbol && symbol->getNumExtensions())
+        requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
+
+    if (symbol && symbol->isReadOnly()) {
+        // All shared things containing an implicitly sized array must be copied up
+        // on first use, so that all future references will share its array structure,
+        // so that editing the implicit size will effect all nodes consuming it,
+        // and so that editing the implicit size won't change the shared one.
+        //
+        // If this is a variable or a block, check it and all it contains, but if this
+        // is a member of an anonymous block, check the whole block, as the whole block
+        // will need to be copied up if it contains an implicitly-sized array.
+        if (symbol->getType().containsImplicitlySizedArray() ||
+            (symbol->getAsAnonMember() &&
+             symbol->getAsAnonMember()->getAnonContainer().getType().containsImplicitlySizedArray()))
+            makeEditable(symbol);
+    }
+
+    const TVariable* variable;
+    const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr;
+    if (anon) {
+        // It was a member of an anonymous container.
+
+        // The "getNumExtensions()" mechanism above doesn't yet work for block members
+        blockMemberExtensionCheck(loc, nullptr, *string);
+
+        // Create a subtree for its dereference.
+        variable = anon->getAnonContainer().getAsVariable();
+        TIntermTyped* container = intermediate.addSymbol(*variable, loc);
+        TIntermTyped* constNode = intermediate.addConstantUnion(anon->getMemberNumber(), loc);
+        node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc);
+
+        node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
+        if (node->getType().hiddenMember())
+            error(loc, "member of nameless block was not redeclared", string->c_str(), "");
+    } else {
+        // Not a member of an anonymous container.
+
+        // The symbol table search was done in the lexical phase.
+        // See if it was a variable.
+        variable = symbol ? symbol->getAsVariable() : nullptr;
+        if (variable) {
+            if ((variable->getType().getBasicType() == EbtBlock ||
+                 variable->getType().getBasicType() == EbtStruct) && variable->getType().getStruct() == nullptr) {
+                error(loc, "cannot be used (maybe an instance name is needed)", string->c_str(), "");
+                variable = nullptr;
+            }
+        } else {
+            if (symbol)
+                error(loc, "variable name expected", string->c_str(), "");
+        }
+
+        // Recovery, if it wasn't found or was not a variable.
+        if (! variable)
+            variable = new TVariable(string, TType(EbtVoid));
+
+        if (variable->getType().getQualifier().isFrontEndConstant())
+            node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
+        else
+            node = intermediate.addSymbol(*variable, loc);
+    }
+
+    if (variable->getType().getQualifier().isIo())
+        intermediate.addIoAccessed(*string);
+
+    return node;
+}
+
+//
+// Handle seeing a base[index] dereference in the grammar.
+//
+TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index)
+{
+    TIntermTyped* result = nullptr;
+
+    int indexValue = 0;
+    if (index->getQualifier().isFrontEndConstant()) {
+        indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
+        checkIndex(loc, base->getType(), indexValue);
+    }
+
+    variableCheck(base);
+    if (! base->isArray() && ! base->isMatrix() && ! base->isVector()) {
+        if (base->getAsSymbolNode())
+            error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
+        else
+            error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
+    } else if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant())
+        return intermediate.foldDereference(base, indexValue, loc);
+    else {
+        // at least one of base and index is variable...
+
+        if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
+            handleIoResizeArrayAccess(loc, base);
+
+        if (index->getQualifier().isFrontEndConstant()) {
+            if (base->getType().isImplicitlySizedArray())
+                updateImplicitArraySize(loc, base, indexValue);
+            result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
+        } else {
+            if (base->getType().isImplicitlySizedArray()) {
+                if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
+                    error(loc, "", "[", "array must be sized by a redeclaration or layout qualifier before being indexed with a variable");
+                else
+                    error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
+            }
+            if (base->getBasicType() == EbtBlock) {
+                if (base->getQualifier().storage == EvqBuffer)
+                    requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array");
+                else if (base->getQualifier().storage == EvqUniform)
+                    profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "variable indexing uniform block array");
+                else {
+                    // input/output blocks either don't exist or can be variable indexed
+                }
+            } else if (language == EShLangFragment && base->getQualifier().isPipeOutput())
+                requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader output array");
+            else if (base->getBasicType() == EbtSampler && version >= 130) {
+                const char* explanation = "variable indexing sampler array";
+                requireProfile(base->getLoc(), EEsProfile | ECoreProfile | ECompatibilityProfile, explanation);
+                profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation);
+                profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, nullptr, explanation);
+            }
+
+            result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
+        }
+    }
+
+    if (result == nullptr) {
+        // Insert dummy error-recovery result
+        result = intermediate.addConstantUnion(0.0, EbtFloat, loc);
+    } else {
+        // Insert valid dereferenced result
+        TType newType(base->getType(), 0);  // dereferenced type
+        if (base->getType().getQualifier().isConstant() && index->getQualifier().isConstant()) {
+            newType.getQualifier().storage = EvqConst;
+            // If base or index is a specialization constant, the result should also be a specialization constant.
+            if (base->getType().getQualifier().isSpecConstant() || index->getQualifier().isSpecConstant()) {
+                newType.getQualifier().makeSpecConstant();
+            }
+        } else {
+            newType.getQualifier().makePartialTemporary();
+        }
+        result->setType(newType);
+
+        if (anyIndexLimits)
+            handleIndexLimits(loc, base, index);
+    }
+
+    return result;
+}
+
+void TParseContext::checkIndex(const TSourceLoc& loc, const TType& type, int& index)
+{
+    if (index < 0) {
+        error(loc, "", "[", "index out of range '%d'", index);
+        index = 0;
+    } else if (type.isArray()) {
+        if (type.isExplicitlySizedArray() && index >= type.getOuterArraySize()) {
+            error(loc, "", "[", "array index out of range '%d'", index);
+            index = type.getOuterArraySize() - 1;
+        }
+    } else if (type.isVector()) {
+        if (index >= type.getVectorSize()) {
+            error(loc, "", "[", "vector index out of range '%d'", index);
+            index = type.getVectorSize() - 1;
+        }
+    } else if (type.isMatrix()) {
+        if (index >= type.getMatrixCols()) {
+            error(loc, "", "[", "matrix index out of range '%d'", index);
+            index = type.getMatrixCols() - 1;
+        }
+    }
+}
+
+// for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
+void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* base, TIntermTyped* index)
+{
+    if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
+        (! limits.generalUniformIndexing && base->getQualifier().isUniformOrBuffer() && language != EShLangVertex) ||
+        (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
+        (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
+        (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
+                                             ! base->getType().getQualifier().isPipeInput() &&
+                                             ! base->getType().getQualifier().isPipeOutput() &&
+                                             ! base->getType().getQualifier().isConstant()) ||
+        (! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
+                                                base->getType().getQualifier().isPipeOutput()))) {
+        // it's too early to know what the inductive variables are, save it for post processing
+        needsIndexLimitationChecking.push_back(index);
+    }
+}
+
+// Make a shared symbol have a non-shared version that can be edited by the current
+// compile, such that editing its type will not change the shared version and will
+// effect all nodes sharing it.
+void TParseContext::makeEditable(TSymbol*& symbol)
+{
+    TParseContextBase::makeEditable(symbol);
+
+    // See if it's tied to IO resizing
+    if (isIoResizeArray(symbol->getType()))
+        ioArraySymbolResizeList.push_back(symbol);
+}
+
+// Return true if this is a geometry shader input array or tessellation control output array.
+bool TParseContext::isIoResizeArray(const TType& type) const
+{
+    return type.isArray() &&
+           ((language == EShLangGeometry    && type.getQualifier().storage == EvqVaryingIn) ||
+            (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && ! type.getQualifier().patch));
+}
+
+// If an array is not isIoResizeArray() but is an io array, make sure it has the right size
+void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type)
+{
+    if (! type.isArray() || type.getQualifier().patch || symbolTable.atBuiltInLevel())
+        return;
+
+    assert(! isIoResizeArray(type));
+
+    if (type.getQualifier().storage != EvqVaryingIn || type.getQualifier().patch)
+        return;
+
+    if (language == EShLangTessControl || language == EShLangTessEvaluation) {
+        if (type.getOuterArraySize() != resources.maxPatchVertices) {
+            if (type.isExplicitlySizedArray())
+                error(loc, "tessellation input array size must be gl_MaxPatchVertices or implicitly sized", "[]", "");
+            type.changeOuterArraySize(resources.maxPatchVertices);
+        }
+    }
+}
+
+// Issue any errors if the non-array object is missing arrayness WRT
+// shader I/O that has array requirements.
+// All arrayness checking is handled in array paths, this is for
+void TParseContext::ioArrayCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
+{
+    if (! type.isArray() && ! symbolTable.atBuiltInLevel()) {
+        if (type.getQualifier().isArrayedIo(language)
+#ifdef NV_EXTENSIONS
+            && !type.getQualifier().layoutPassthrough
+#endif
+           )
+            error(loc, "type must be an array:", type.getStorageQualifierString(), identifier.c_str());
+    }
+}
+
+// Handle a dereference of a geometry shader input array or tessellation control output array.
+// See ioArraySymbolResizeList comment in ParseHelper.h.
+//
+void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TIntermTyped* base)
+{
+    TIntermSymbol* symbolNode = base->getAsSymbolNode();
+    assert(symbolNode);
+    if (! symbolNode)
+        return;
+
+    // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing)
+    if (symbolNode->getType().isImplicitlySizedArray()) {
+        int newSize = getIoArrayImplicitSize();
+        if (newSize > 0)
+            symbolNode->getWritableType().changeOuterArraySize(newSize);
+    }
+}
+
+// If there has been an input primitive declaration (geometry shader) or an output
+// number of vertices declaration(tessellation shader), make sure all input array types
+// match it in size.  Types come either from nodes in the AST or symbols in the
+// symbol table.
+//
+// Types without an array size will be given one.
+// Types already having a size that is wrong will get an error.
+//
+void TParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnly)
+{
+    int requiredSize = getIoArrayImplicitSize();
+    if (requiredSize == 0)
+        return;
+
+    const char* feature;
+    if (language == EShLangGeometry)
+        feature = TQualifier::getGeometryString(intermediate.getInputPrimitive());
+    else if (language == EShLangTessControl)
+        feature = "vertices";
+    else
+        feature = "unknown";
+
+    if (tailOnly) {
+        checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList.back()->getWritableType(), ioArraySymbolResizeList.back()->getName());
+        return;
+    }
+
+    for (size_t i = 0; i < ioArraySymbolResizeList.size(); ++i)
+        checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList[i]->getWritableType(), ioArraySymbolResizeList[i]->getName());
+}
+
+int TParseContext::getIoArrayImplicitSize() const
+{
+    if (language == EShLangGeometry)
+        return TQualifier::mapGeometryToSize(intermediate.getInputPrimitive());
+    else if (language == EShLangTessControl)
+        return intermediate.getVertices() != TQualifier::layoutNotSet ? intermediate.getVertices() : 0;
+    else
+        return 0;
+}
+
+void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredSize, const char* feature, TType& type, const TString& name)
+{
+    if (type.isImplicitlySizedArray())
+        type.changeOuterArraySize(requiredSize);
+    else if (type.getOuterArraySize() != requiredSize) {
+        if (language == EShLangGeometry)
+            error(loc, "inconsistent input primitive for array size of", feature, name.c_str());
+        else if (language == EShLangTessControl)
+            error(loc, "inconsistent output number of vertices for array size of", feature, name.c_str());
+        else
+            assert(0);
+    }
+}
+
+// Handle seeing a binary node with a math operation.
+// Returns nullptr if not semantically allowed.
+TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right)
+{
+    rValueErrorCheck(loc, str, left->getAsTyped());
+    rValueErrorCheck(loc, str, right->getAsTyped());
+
+    bool allowed = true;
+    switch (op) {
+    // TODO: Bring more source language-specific checks up from intermediate.cpp
+    // to the specific parse helpers for that source language.
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        if (! left->isScalar() || ! right->isScalar())
+            allowed = false;
+        break;
+    default:
+        break;
+    }
+
+    TIntermTyped* result = nullptr;
+    if (allowed)
+        result = intermediate.addBinaryMath(op, left, right, loc);
+
+    if (result == nullptr)
+        binaryOpError(loc, str, left->getCompleteString(), right->getCompleteString());
+
+    return result;
+}
+
+// Handle seeing a unary node with a math operation.
+TIntermTyped* TParseContext::handleUnaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* childNode)
+{
+    rValueErrorCheck(loc, str, childNode);
+
+    TIntermTyped* result = intermediate.addUnaryMath(op, childNode, loc);
+
+    if (result)
+        return result;
+    else
+        unaryOpError(loc, str, childNode->getCompleteString());
+
+    return childNode;
+}
+
+//
+// Handle seeing a base.field dereference in the grammar.
+//
+TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TIntermTyped* base, const TString& field)
+{
+    variableCheck(base);
+
+    //
+    // .length() can't be resolved until we later see the function-calling syntax.
+    // Save away the name in the AST for now.  Processing is completed in
+    // handleLengthMethod().
+    //
+    if (field == "length") {
+        if (base->isArray()) {
+            profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, ".length");
+            profileRequires(loc, EEsProfile, 300, nullptr, ".length");
+        } else if (base->isVector() || base->isMatrix()) {
+            const char* feature = ".length() on vectors and matrices";
+            requireProfile(loc, ~EEsProfile, feature);
+            profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, feature);
+        } else {
+            error(loc, "does not operate on this type:", field.c_str(), base->getType().getCompleteString().c_str());
+
+            return base;
+        }
+
+        return intermediate.addMethod(base, TType(EbtInt), &field, loc);
+    }
+
+    // It's not .length() if we get to here.
+
+    if (base->isArray()) {
+        error(loc, "cannot apply to an array:", ".", field.c_str());
+
+        return base;
+    }
+
+    // It's neither an array nor .length() if we get here,
+    // leaving swizzles and struct/block dereferences.
+
+    TIntermTyped* result = base;
+    if (base->isVector() || base->isScalar()) {
+        if (base->isScalar()) {
+            const char* dotFeature = "scalar swizzle";
+            requireProfile(loc, ~EEsProfile, dotFeature);
+            profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature);
+        }
+
+        TSwizzleSelectors<TVectorSelector> selectors;
+        parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
+
+        if (base->isScalar()) {
+            if (selectors.size() == 1)
+                return result;
+            else {
+                TType type(base->getBasicType(), EvqTemporary, selectors.size());
+                // Swizzle operations propagate specialization-constantness
+                if (base->getQualifier().isSpecConstant())
+                    type.getQualifier().makeSpecConstant();
+                return addConstructor(loc, base, type);
+            }
+        }
+
+        if (base->getType().getQualifier().isFrontEndConstant())
+            result = intermediate.foldSwizzle(base, selectors, loc);
+        else {
+            if (selectors.size() == 1) {
+                TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc);
+                result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
+                result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision));
+            } else {
+                TIntermTyped* index = intermediate.addSwizzle(selectors, loc);
+                result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
+                result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size()));
+            }
+            // Swizzle operations propagate specialization-constantness
+            if (base->getType().getQualifier().isSpecConstant())
+                result->getWritableType().getQualifier().makeSpecConstant();
+        }
+    } else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
+        const TTypeList* fields = base->getType().getStruct();
+        bool fieldFound = false;
+        int member;
+        for (member = 0; member < (int)fields->size(); ++member) {
+            if ((*fields)[member].type->getFieldName() == field) {
+                fieldFound = true;
+                break;
+            }
+        }
+        if (fieldFound) {
+            if (base->getType().getQualifier().isFrontEndConstant())
+                result = intermediate.foldDereference(base, member, loc);
+            else {
+                blockMemberExtensionCheck(loc, base, field);
+                TIntermTyped* index = intermediate.addConstantUnion(member, loc);
+                result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
+                result->setType(*(*fields)[member].type);
+            }
+        } else
+            error(loc, "no such field in structure", field.c_str(), "");
+    } else
+        error(loc, "does not apply to this type:", field.c_str(), base->getType().getCompleteString().c_str());
+
+    // Propagate noContraction up the dereference chain
+    if (base->getQualifier().noContraction)
+        result->getWritableType().getQualifier().noContraction = true;
+
+    return result;
+}
+
+void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* /*base*/, const TString& field)
+{
+    if (profile == EEsProfile && field == "gl_PointSize") {
+        if (language == EShLangGeometry)
+            requireExtensions(loc, Num_AEP_geometry_point_size, AEP_geometry_point_size, "gl_PointSize");
+        else if (language == EShLangTessControl || language == EShLangTessEvaluation)
+            requireExtensions(loc, Num_AEP_tessellation_point_size, AEP_tessellation_point_size, "gl_PointSize");
+    }
+}
+
+//
+// Handle seeing a function declarator in the grammar.  This is the precursor
+// to recognizing a function prototype or function definition.
+//
+TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunction& function, bool prototype)
+{
+    // ES can't declare prototypes inside functions
+    if (! symbolTable.atGlobalLevel())
+        requireProfile(loc, ~EEsProfile, "local function declaration");
+
+    //
+    // Multiple declarations of the same function name 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 (full signature match) are allowed.  But, return types and parameter qualifiers must also match.
+    //  - except ES 100, which only allows a single prototype
+    //
+    // ES 100 does not allow redefining, but does allow overloading of built-in functions.
+    // ES 300 does not allow redefining or overloading of built-in functions.
+    //
+    bool builtIn;
+    TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn);
+    if (symbol && symbol->getAsFunction() && builtIn)
+        requireProfile(loc, ~EEsProfile, "redefinition of built-in function");
+    const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
+    if (prevDec) {
+        if (prevDec->isPrototyped() && prototype)
+            profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function");
+        if (prevDec->getType() != function.getType())
+            error(loc, "overloaded functions must have the same return type", function.getType().getBasicTypeString().c_str(), "");
+        for (int i = 0; i < prevDec->getParamCount(); ++i) {
+            if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
+                error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1);
+
+            if ((*prevDec)[i].type->getQualifier().precision != function[i].type->getQualifier().precision)
+                error(loc, "overloaded functions must have the same parameter precision qualifiers for argument", function[i].type->getPrecisionQualifierString(), "%d", i+1);
+        }
+    }
+
+    arrayObjectCheck(loc, function.getType(), "array in function return type");
+
+    if (prototype) {
+        // All built-in functions are defined, even though they don't have a body.
+        // Count their prototype as a definition instead.
+        if (symbolTable.atBuiltInLevel())
+            function.setDefined();
+        else {
+            if (prevDec && ! builtIn)
+                symbol->getAsFunction()->setPrototyped();  // need a writable one, but like having prevDec as a const
+            function.setPrototyped();
+        }
+    }
+
+    // This insert won't actually insert it if it's a duplicate signature, but it will still check for
+    // other forms of name collisions.
+    if (! symbolTable.insert(function))
+        error(loc, "function name is redeclaration of existing name", function.getName().c_str(), "");
+
+    //
+    // If this is a redeclaration, it could also be a definition,
+    // in which case, we need to use the parameter names from this one, and not the one that's
+    // being redeclared.  So, pass back this declaration, not the one in the symbol table.
+    //
+    return &function;
+}
+
+//
+// Handle seeing the function prototype in front of a function definition in the grammar.
+// The body is handled after this function returns.
+//
+TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function)
+{
+    currentCaller = function.getMangledName();
+    TSymbol* symbol = symbolTable.find(function.getMangledName());
+    TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr;
+
+    if (! prevDec)
+        error(loc, "can't find function", function.getName().c_str(), "");
+    // 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 occurrence.
+
+    if (prevDec && prevDec->isDefined()) {
+        // Then this function already has a body.
+        error(loc, "function already has a body", function.getName().c_str(), "");
+    }
+    if (prevDec && ! prevDec->isDefined()) {
+        prevDec->setDefined();
+
+        // Remember the return type for later checking for RETURN statements.
+        currentFunctionType = &(prevDec->getType());
+    } else
+        currentFunctionType = new TType(EbtVoid);
+    functionReturnsValue = false;
+
+    // Check for entry point
+    if (function.getName().compare(intermediate.getEntryPointName().c_str()) == 0) {
+        intermediate.setEntryPointMangledName(function.getMangledName().c_str());
+        intermediate.incrementEntryPointCount();
+        inMain = true;
+    } else
+        inMain = false;
+
+    //
+    // Raise error message if main function takes any parameters or returns anything other than void
+    //
+    if (inMain) {
+        if (function.getParamCount() > 0)
+            error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
+        if (function.getType().getBasicType() != EbtVoid)
+            error(loc, "", function.getType().getBasicTypeString().c_str(), "entry point cannot return a value");
+    }
+
+    //
+    // New symbol table scope for body of function plus its arguments
+    //
+    symbolTable.push();
+
+    //
+    // 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 (int i = 0; i < function.getParamCount(); i++) {
+        TParameter& param = function[i];
+        if (param.name != nullptr) {
+            TVariable *variable = new TVariable(param.name, *param.type);
+
+            // Insert the parameters with name in the symbol table.
+            if (! symbolTable.insert(*variable))
+                error(loc, "redefinition", variable->getName().c_str(), "");
+            else {
+                // Transfer ownership of name pointer to symbol table.
+                param.name = nullptr;
+
+                // Add the parameter to the HIL
+                paramNodes = intermediate.growAggregate(paramNodes,
+                                                        intermediate.addSymbol(*variable, loc),
+                                                        loc);
+            }
+        } else
+            paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc);
+    }
+    intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
+    loopNestingLevel = 0;
+    statementNestingLevel = 0;
+    controlFlowNestingLevel = 0;
+    postMainReturn = false;
+
+    return paramNodes;
+}
+
+//
+// Handle seeing function call syntax in the grammar, which could be any of
+//  - .length() method
+//  - constructor
+//  - a call to a built-in function mapped to an operator
+//  - a call to a built-in function that will remain a function call (e.g., texturing)
+//  - user function
+//  - subroutine call (not implemented yet)
+//
+TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments)
+{
+    TIntermTyped* result = nullptr;
+
+    if (function->getBuiltInOp() == EOpArrayLength)
+        result = handleLengthMethod(loc, function, arguments);
+    else if (function->getBuiltInOp() != 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);  // use this to get the type back
+        if (! constructorError(loc, arguments, *function, function->getBuiltInOp(), type)) {
+            //
+            // It's a constructor, of type 'type'.
+            //
+            result = addConstructor(loc, arguments, type);
+            if (result == nullptr)
+                error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), "");
+        }
+    } else {
+        //
+        // Find it in the symbol table.
+        //
+        const TFunction* fnCandidate;
+        bool builtIn;
+        fnCandidate = findFunction(loc, *function, builtIn);
+        if (fnCandidate) {
+            // This is a declared function that might map to
+            //  - a built-in operator,
+            //  - a built-in function not mapped to an operator, or
+            //  - a user function.
+
+            // Error check for a function requiring specific extensions present.
+            if (builtIn && fnCandidate->getNumExtensions())
+                requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
+
+            if (arguments) {
+                // Make sure qualifications work for these arguments.
+                TIntermAggregate* aggregate = arguments->getAsAggregate();
+                for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
+                    // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
+                    // is the single argument itself or its children are the arguments.  Only one argument
+                    // means take 'arguments' itself as the one argument.
+                    TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
+                    TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier();
+                    if (formalQualifier.isParamOutput()) {
+                        if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
+                            error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
+                    }
+                    TQualifier& argQualifier = arg->getAsTyped()->getQualifier();
+                    if (argQualifier.isMemory()) {
+                        const char* message = "argument cannot drop memory qualifier when passed to formal parameter";
+                        if (argQualifier.volatil && ! formalQualifier.volatil)
+                            error(arguments->getLoc(), message, "volatile", "");
+                        if (argQualifier.coherent && ! formalQualifier.coherent)
+                            error(arguments->getLoc(), message, "coherent", "");
+                        if (argQualifier.readonly && ! formalQualifier.readonly)
+                            error(arguments->getLoc(), message, "readonly", "");
+                        if (argQualifier.writeonly && ! formalQualifier.writeonly)
+                            error(arguments->getLoc(), message, "writeonly", "");
+                    }
+                    // TODO 4.5 functionality:  A shader will fail to compile
+                    // if the value passed to the memargument of an atomic memory function does not correspond to a buffer or
+                    // shared variable. It is acceptable to pass an element of an array or a single component of a vector to the
+                    // memargument of an atomic memory function, as long as the underlying array or vector is a buffer or
+                    // shared variable.
+                }
+
+                // Convert 'in' arguments
+                addInputArgumentConversions(*fnCandidate, arguments);  // arguments may be modified if it's just a single argument node
+            }
+
+            if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) {
+                // A function call mapped to a built-in operation.
+                result = handleBuiltInFunctionCall(loc, *arguments, *fnCandidate);
+            } else {
+                // This is a function call not mapped to built-in operator.
+                // It could still be a built-in function, but only if PureOperatorBuiltins == false.
+                result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc);
+                TIntermAggregate* call = result->getAsAggregate();
+                call->setName(fnCandidate->getMangledName());
+
+                // this is how we know whether the given function is a built-in function or a user-defined function
+                // if builtIn == false, it's a userDefined -> could be an overloaded built-in function also
+                // if builtIn == true, it's definitely a built-in function with EOpNull
+                if (! builtIn) {
+                    call->setUserDefined();
+                    if (symbolTable.atGlobalLevel()) {
+                        requireProfile(loc, ~EEsProfile, "calling user function from global scope");
+                        intermediate.addToCallGraph(infoSink, "main(", fnCandidate->getMangledName());
+                    } else
+                        intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
+                }
+
+                if (builtIn)
+                    nonOpBuiltInCheck(loc, *fnCandidate, *call);
+                else
+                    userFunctionCallCheck(loc, *call);
+            }
+
+            // Convert 'out' arguments.  If it was a constant folded built-in, it won't be an aggregate anymore.
+            // Built-ins with a single argument aren't called with an aggregate, but they also don't have an output.
+            // Also, build the qualifier list for user function calls, which are always called with an aggregate.
+            if (result->getAsAggregate()) {
+                TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
+                for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
+                    TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage;
+                    qualifierList.push_back(qual);
+                }
+                result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
+            }
+        }
+    }
+
+    // generic error recovery
+    // TODO: simplification: localize all the error recoveries that look like this, and taking type into account to reduce cascades
+    if (result == nullptr)
+        result = intermediate.addConstantUnion(0.0, EbtFloat, loc);
+
+    return result;
+}
+
+TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNode& arguments,
+                                                       const TFunction& function)
+{
+    checkLocation(loc, function.getBuiltInOp());
+    TIntermTyped *result = intermediate.addBuiltInFunctionCall(loc, function.getBuiltInOp(),
+                                                               function.getParamCount() == 1,
+                                                               &arguments, function.getType());
+    if (obeyPrecisionQualifiers())
+        computeBuiltinPrecisions(*result, function);
+
+    if (result == nullptr)  {
+        error(arguments.getLoc(), " wrong operand type", "Internal Error",
+                                  "built in unary operator function.  Type: %s",
+                                  static_cast<TIntermTyped*>(&arguments)->getCompleteString().c_str());
+    } else if (result->getAsOperator())
+        builtInOpCheck(loc, function, *result->getAsOperator());
+
+    return result;
+}
+
+// "The operation of a built-in function can have a different precision
+// qualification than the precision qualification of the resulting value.
+// These two precision qualifications are established as follows.
+//
+// The precision qualification of the operation of a built-in function is
+// based on the precision qualification of its input arguments and formal
+// parameters:  When a formal parameter specifies a precision qualifier,
+// that is used, otherwise, the precision qualification of the calling
+// argument is used.  The highest precision of these will be the precision
+// qualification of the operation of the built-in function. Generally,
+// this is applied across all arguments to a built-in function, with the
+// exceptions being:
+//   - bitfieldExtract and bitfieldInsert ignore the 'offset' and 'bits'
+//     arguments.
+//   - interpolateAt* functions only look at the 'interpolant' argument.
+//
+// The precision qualification of the result of a built-in function is
+// determined in one of the following ways:
+//
+//   - For the texture sampling, image load, and image store functions,
+//     the precision of the return type matches the precision of the
+//     sampler type
+//
+//   Otherwise:
+//
+//   - For prototypes that do not specify a resulting precision qualifier,
+//     the precision will be the same as the precision of the operation.
+//
+//   - For prototypes that do specify a resulting precision qualifier,
+//     the specified precision qualifier is the precision qualification of
+//     the result."
+//
+void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction& function)
+{
+    TPrecisionQualifier operationPrecision = EpqNone;
+    TPrecisionQualifier resultPrecision = EpqNone;
+
+    TIntermOperator* opNode = node.getAsOperator();
+    if (opNode == nullptr)
+        return;
+
+    if (TIntermUnary* unaryNode = node.getAsUnaryNode()) {
+        operationPrecision = std::max(function[0].type->getQualifier().precision,
+                                      unaryNode->getOperand()->getType().getQualifier().precision);
+        if (function.getType().getBasicType() != EbtBool)
+            resultPrecision = function.getType().getQualifier().precision == EpqNone ?
+                                        operationPrecision :
+                                        function.getType().getQualifier().precision;
+    } else if (TIntermAggregate* agg = node.getAsAggregate()) {
+        TIntermSequence& sequence = agg->getSequence();
+        unsigned int numArgs = (unsigned int)sequence.size();
+        switch (agg->getOp()) {
+        case EOpBitfieldExtract:
+            numArgs = 1;
+            break;
+        case EOpBitfieldInsert:
+            numArgs = 2;
+            break;
+        case EOpInterpolateAtCentroid:
+        case EOpInterpolateAtOffset:
+        case EOpInterpolateAtSample:
+            numArgs = 1;
+            break;
+        default:
+            break;
+        }
+        // find the maximum precision from the arguments and parameters
+        for (unsigned int arg = 0; arg < numArgs; ++arg) {
+            operationPrecision = std::max(operationPrecision, sequence[arg]->getAsTyped()->getQualifier().precision);
+            operationPrecision = std::max(operationPrecision, function[arg].type->getQualifier().precision);
+        }
+        // compute the result precision
+        if (agg->isSampling() || agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore)
+            resultPrecision = sequence[0]->getAsTyped()->getQualifier().precision;
+        else if (function.getType().getBasicType() != EbtBool)
+            resultPrecision = function.getType().getQualifier().precision == EpqNone ?
+                                        operationPrecision :
+                                        function.getType().getQualifier().precision;
+    }
+
+    // Propagate precision through this node and its children. That algorithm stops
+    // when a precision is found, so start by clearing this subroot precision
+    opNode->getQualifier().precision = EpqNone;
+    if (operationPrecision != EpqNone) {
+        opNode->propagatePrecision(operationPrecision);
+        opNode->setOperationPrecision(operationPrecision);
+    }
+    // Now, set the result precision, which might not match
+    opNode->getQualifier().precision = resultPrecision;
+}
+
+TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value)
+{
+    functionReturnsValue = true;
+    if (currentFunctionType->getBasicType() == EbtVoid) {
+        error(loc, "void function cannot return a value", "return", "");
+        return intermediate.addBranch(EOpReturn, loc);
+    } else if (*currentFunctionType != value->getType()) {
+        TIntermTyped* converted = intermediate.addConversion(EOpReturn, *currentFunctionType, value);
+        if (converted) {
+            if (*currentFunctionType != converted->getType())
+                error(loc, "cannot convert return value to function return type", "return", "");
+            if (version < 420)
+                warn(loc, "type conversion on return values was not explicitly allowed until version 420", "return", "");
+            return intermediate.addBranch(EOpReturn, converted, loc);
+        } else {
+            error(loc, "type does not match, or is not convertible to, the function's return type", "return", "");
+            return intermediate.addBranch(EOpReturn, value, loc);
+        }
+    } else
+        return intermediate.addBranch(EOpReturn, value, loc);
+}
+
+// See if the operation is being done in an illegal location.
+void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op)
+{
+    switch (op) {
+    case EOpBarrier:
+        if (language == EShLangTessControl) {
+            if (controlFlowNestingLevel > 0)
+                error(loc, "tessellation control barrier() cannot be placed within flow control", "", "");
+            if (! inMain)
+                error(loc, "tessellation control barrier() must be in main()", "", "");
+            else if (postMainReturn)
+                error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", "");
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+// Finish processing object.length(). This started earlier in handleDotDereference(), where
+// the ".length" part was recognized and semantically checked, and finished here where the
+// function syntax "()" is recognized.
+//
+// Return resulting tree node.
+TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction* function, TIntermNode* intermNode)
+{
+    int length = 0;
+
+    if (function->getParamCount() > 0)
+        error(loc, "method does not accept any arguments", function->getName().c_str(), "");
+    else {
+        const TType& type = intermNode->getAsTyped()->getType();
+        if (type.isArray()) {
+            if (type.isRuntimeSizedArray()) {
+                // Create a unary op and let the back end handle it
+                return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
+            } else if (type.isImplicitlySizedArray()) {
+                if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) {
+                    // We could be between a layout declaration that gives a built-in io array implicit size and
+                    // a user redeclaration of that array, meaning we have to substitute its implicit size here
+                    // without actually redeclaring the array.  (It is an error to use a member before the
+                    // redeclaration, but not an error to use the array name itself.)
+                    const TString& name = intermNode->getAsSymbolNode()->getName();
+                    if (name == "gl_in" || name == "gl_out")
+                        length = getIoArrayImplicitSize();
+                }
+                if (length == 0) {
+                    if (intermNode->getAsSymbolNode() && isIoResizeArray(type))
+                        error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
+                    else
+                        error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
+                }
+            } else if (type.getOuterArrayNode()) {
+                // If the array's outer size is specified by an intermediate node, it means the array's length
+                // was specified by a specialization constant. In such a case, we should return the node of the
+                // specialization constants to represent the length.
+                return type.getOuterArrayNode();
+            } else
+                length = type.getOuterArraySize();
+        } else if (type.isMatrix())
+            length = type.getMatrixCols();
+        else if (type.isVector())
+            length = type.getVectorSize();
+        else {
+            // we should not get here, because earlier semantic checking should have prevented this path
+            error(loc, ".length()", "unexpected use of .length()", "");
+        }
+    }
+
+    if (length == 0)
+        length = 1;
+
+    return intermediate.addConstantUnion(length, loc);
+}
+
+//
+// Add any needed implicit conversions for function-call arguments to input parameters.
+//
+void TParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const
+{
+    TIntermAggregate* aggregate = arguments->getAsAggregate();
+
+    // Process each argument's conversion
+    for (int i = 0; i < function.getParamCount(); ++i) {
+        // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
+        // is the single argument itself or its children are the arguments.  Only one argument
+        // means take 'arguments' itself as the one argument.
+        TIntermTyped* arg = function.getParamCount() == 1 ? arguments->getAsTyped() : (aggregate ? aggregate->getSequence()[i]->getAsTyped() : arguments->getAsTyped());
+        if (*function[i].type != arg->getType()) {
+            if (function[i].type->getQualifier().isParamInput()) {
+                // In-qualified arguments just need an extra node added above the argument to
+                // convert to the correct type.
+                arg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg);
+                if (arg) {
+                    if (function.getParamCount() == 1)
+                        arguments = arg;
+                    else {
+                        if (aggregate)
+                            aggregate->getSequence()[i] = arg;
+                        else
+                            arguments = arg;
+                    }
+                }
+            }
+        }
+    }
+}
+
+//
+// Add any needed implicit output conversions for function-call arguments.  This
+// can require a new tree topology, complicated further by whether the function
+// has a return value.
+//
+// Returns a node of a subtree that evaluates to the return value of the function.
+//
+TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const
+{
+    TIntermSequence& arguments = intermNode.getSequence();
+
+    // Will there be any output conversions?
+    bool outputConversions = false;
+    for (int i = 0; i < function.getParamCount(); ++i) {
+        if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().isParamOutput()) {
+            outputConversions = true;
+            break;
+        }
+    }
+
+    if (! outputConversions)
+        return &intermNode;
+
+    // Setup for the new tree, if needed:
+    //
+    // Output conversions need a different tree topology.
+    // Out-qualified arguments need a temporary of the correct type, with the call
+    // followed by an assignment of the temporary to the original argument:
+    //     void: function(arg, ...)  ->        (          function(tempArg, ...), arg = tempArg, ...)
+    //     ret = function(arg, ...)  ->  ret = (tempRet = function(tempArg, ...), arg = tempArg, ..., tempRet)
+    // Where the "tempArg" type needs no conversion as an argument, but will convert on assignment.
+    TIntermTyped* conversionTree = nullptr;
+    TVariable* tempRet = nullptr;
+    if (intermNode.getBasicType() != EbtVoid) {
+        // do the "tempRet = function(...), " bit from above
+        tempRet = makeInternalVariable("tempReturn", intermNode.getType());
+        TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+        conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, intermNode.getLoc());
+    } else
+        conversionTree = &intermNode;
+
+    conversionTree = intermediate.makeAggregate(conversionTree);
+
+    // Process each argument's conversion
+    for (int i = 0; i < function.getParamCount(); ++i) {
+        if (*function[i].type != arguments[i]->getAsTyped()->getType()) {
+            if (function[i].type->getQualifier().isParamOutput()) {
+                // Out-qualified arguments need to use the topology set up above.
+                // do the " ...(tempArg, ...), arg = tempArg" bit from above
+                TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type);
+                tempArg->getWritableType().getQualifier().makeTemporary();
+                TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+                TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc());
+                conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc());
+                // replace the argument with another node for the same tempArg variable
+                arguments[i] = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+            }
+        }
+    }
+
+    // Finalize the tree topology (see bigger comment above).
+    if (tempRet) {
+        // do the "..., tempRet" bit from above
+        TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+        conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, intermNode.getLoc());
+    }
+    conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc());
+
+    return conversionTree;
+}
+
+//
+// Do additional checking of built-in function calls that is not caught
+// by normal semantic checks on argument type, extension tagging, etc.
+//
+// Assumes there has been a semantically correct match to a built-in function prototype.
+//
+void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermOperator& callNode)
+{
+    // Set up convenience accessors to the argument(s).  There is almost always
+    // multiple arguments for the cases below, but when there might be one,
+    // check the unaryArg first.
+    const TIntermSequence* argp = nullptr;   // confusing to use [] syntax on a pointer, so this is to help get a reference
+    const TIntermTyped* unaryArg = nullptr;
+    const TIntermTyped* arg0 = nullptr;
+    if (callNode.getAsAggregate()) {
+        argp = &callNode.getAsAggregate()->getSequence();
+        if (argp->size() > 0)
+            arg0 = (*argp)[0]->getAsTyped();
+    } else {
+        assert(callNode.getAsUnaryNode());
+        unaryArg = callNode.getAsUnaryNode()->getOperand();
+        arg0 = unaryArg;
+    }
+    const TIntermSequence& aggArgs = *argp;  // only valid when unaryArg is nullptr
+
+    switch (callNode.getOp()) {
+    case EOpTextureGather:
+    case EOpTextureGatherOffset:
+    case EOpTextureGatherOffsets:
+    {
+        // Figure out which variants are allowed by what extensions,
+        // and what arguments must be constant for which situations.
+
+        TString featureString = fnCandidate.getName() + "(...)";
+        const char* feature = featureString.c_str();
+        profileRequires(loc, EEsProfile, 310, nullptr, feature);
+        int compArg = -1;  // track which argument, if any, is the constant component argument
+        switch (callNode.getOp()) {
+        case EOpTextureGather:
+            // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5,
+            // otherwise, need GL_ARB_texture_gather.
+            if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) {
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+                if (! fnCandidate[0].type->getSampler().shadow)
+                    compArg = 2;
+            } else
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+            break;
+        case EOpTextureGatherOffset:
+            // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument
+            if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3)
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+            else
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+                profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
+            if (! fnCandidate[0].type->getSampler().shadow)
+                compArg = 3;
+            break;
+        case EOpTextureGatherOffsets:
+            profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+            if (! fnCandidate[0].type->getSampler().shadow)
+                compArg = 3;
+            // check for constant offsets
+            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+                error(loc, "must be a compile-time constant:", feature, "offsets argument");
+            break;
+        default:
+            break;
+        }
+
+        if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
+            if (aggArgs[compArg]->getAsConstantUnion()) {
+                int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
+                if (value < 0 || value > 3)
+                    error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
+            } else
+                error(loc, "must be a compile-time constant:", feature, "component argument");
+        }
+
+        break;
+    }
+
+    case EOpTextureOffset:
+    case EOpTextureFetchOffset:
+    case EOpTextureProjOffset:
+    case EOpTextureLodOffset:
+    case EOpTextureProjLodOffset:
+    case EOpTextureGradOffset:
+    case EOpTextureProjGradOffset:
+    {
+        // Handle texture-offset limits checking
+        // Pick which argument has to hold constant offsets
+        int arg = -1;
+        switch (callNode.getOp()) {
+        case EOpTextureOffset:          arg = 2;  break;
+        case EOpTextureFetchOffset:     arg = (arg0->getType().getSampler().dim != EsdRect) ? 3 : 2; break;
+        case EOpTextureProjOffset:      arg = 2;  break;
+        case EOpTextureLodOffset:       arg = 3;  break;
+        case EOpTextureProjLodOffset:   arg = 3;  break;
+        case EOpTextureGradOffset:      arg = 4;  break;
+        case EOpTextureProjGradOffset:  arg = 4;  break;
+        default:
+            assert(0);
+            break;
+        }
+
+        if (arg > 0) {
+            if (! aggArgs[arg]->getAsConstantUnion())
+                error(loc, "argument must be compile-time constant", "texel offset", "");
+            else {
+                const TType& type = aggArgs[arg]->getAsTyped()->getType();
+                for (int c = 0; c < type.getVectorSize(); ++c) {
+                    int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
+                    if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
+                        error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
+                }
+            }
+        }
+
+        break;
+    }
+
+    case EOpTextureQuerySamples:
+    case EOpImageQuerySamples:
+        // GL_ARB_shader_texture_image_samples
+        profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples");
+        break;
+
+    case EOpImageAtomicAdd:
+    case EOpImageAtomicMin:
+    case EOpImageAtomicMax:
+    case EOpImageAtomicAnd:
+    case EOpImageAtomicOr:
+    case EOpImageAtomicXor:
+    case EOpImageAtomicExchange:
+    case EOpImageAtomicCompSwap:
+    {
+        // Make sure the image types have the correct layout() format and correct argument types
+        const TType& imageType = arg0->getType();
+        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
+            if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
+        } else {
+            if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0)
+                error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
+            else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile)
+                error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
+        }
+
+        break;
+    }
+
+    case EOpInterpolateAtCentroid:
+    case EOpInterpolateAtSample:
+    case EOpInterpolateAtOffset:
+        // Make sure the first argument is an interpolant, or an array element of an interpolant
+        if (arg0->getType().getQualifier().storage != EvqVaryingIn) {
+            // It might still be an array element.
+            //
+            // We could check more, but the semantics of the first argument are already met; the
+            // only way to turn an array into a float/vec* is array dereference and swizzle.
+            //
+            // ES and desktop 4.3 and earlier:  swizzles may not be used
+            // desktop 4.4 and later: swizzles may be used
+            bool swizzleOkay = (profile != EEsProfile) && (version >= 440);
+            const TIntermTyped* base = TIntermediate::findLValueBase(arg0, swizzleOkay);
+            if (base == nullptr || base->getType().getQualifier().storage != EvqVaryingIn)
+                error(loc, "first argument must be an interpolant, or interpolant-array element", fnCandidate.getName().c_str(), "");
+        }
+        break;
+
+    case EOpEmitStreamVertex:
+    case EOpEndStreamPrimitive:
+        intermediate.setMultiStream();
+        break;
+
+    default:
+        break;
+    }
+}
+
+extern bool PureOperatorBuiltins;
+
+// Deprecated!  Use PureOperatorBuiltins == true instead, in which case this
+// functionality is handled in builtInOpCheck() instead of here.
+//
+// Do additional checking of built-in function calls that were not mapped
+// to built-in operations (e.g., texturing functions).
+//
+// Assumes there has been a semantically correct match to a built-in function.
+//
+void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermAggregate& callNode)
+{
+    // Further maintenance of this function is deprecated, because the "correct"
+    // future-oriented design is to not have to do string compares on function names.
+
+    // If PureOperatorBuiltins == true, then all built-ins should be mapped
+    // to a TOperator, and this function would then never get called.
+
+    assert(PureOperatorBuiltins == false);
+
+    // built-in texturing functions get their return value precision from the precision of the sampler
+    if (fnCandidate.getType().getQualifier().precision == EpqNone &&
+        fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler)
+        callNode.getQualifier().precision = callNode.getSequence()[0]->getAsTyped()->getQualifier().precision;
+
+    if (fnCandidate.getName().compare(0, 7, "texture") == 0) {
+        if (fnCandidate.getName().compare(0, 13, "textureGather") == 0) {
+            TString featureString = fnCandidate.getName() + "(...)";
+            const char* feature = featureString.c_str();
+            profileRequires(loc, EEsProfile, 310, nullptr, feature);
+
+            int compArg = -1;  // track which argument, if any, is the constant component argument
+            if (fnCandidate.getName().compare("textureGatherOffset") == 0) {
+                // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument
+                if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3)
+                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+                else
+                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+                int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2;
+                if (! callNode.getSequence()[offsetArg]->getAsConstantUnion())
+                    profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
+                if (! fnCandidate[0].type->getSampler().shadow)
+                    compArg = 3;
+            } else if (fnCandidate.getName().compare("textureGatherOffsets") == 0) {
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+                if (! fnCandidate[0].type->getSampler().shadow)
+                    compArg = 3;
+                // check for constant offsets
+                int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2;
+                if (! callNode.getSequence()[offsetArg]->getAsConstantUnion())
+                    error(loc, "must be a compile-time constant:", feature, "offsets argument");
+            } else if (fnCandidate.getName().compare("textureGather") == 0) {
+                // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5,
+                // otherwise, need GL_ARB_texture_gather.
+                if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) {
+                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+                    if (! fnCandidate[0].type->getSampler().shadow)
+                        compArg = 2;
+                } else
+                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+            }
+
+            if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
+                if (callNode.getSequence()[compArg]->getAsConstantUnion()) {
+                    int value = callNode.getSequence()[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
+                    if (value < 0 || value > 3)
+                        error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
+                } else
+                    error(loc, "must be a compile-time constant:", feature, "component argument");
+            }
+        } else {
+            // this is only for functions not starting "textureGather"...
+            if (fnCandidate.getName().find("Offset") != TString::npos) {
+
+                // Handle texture-offset limits checking
+                int arg = -1;
+                if (fnCandidate.getName().compare("textureOffset") == 0)
+                    arg = 2;
+                else if (fnCandidate.getName().compare("texelFetchOffset") == 0)
+                    arg = 3;
+                else if (fnCandidate.getName().compare("textureProjOffset") == 0)
+                    arg = 2;
+                else if (fnCandidate.getName().compare("textureLodOffset") == 0)
+                    arg = 3;
+                else if (fnCandidate.getName().compare("textureProjLodOffset") == 0)
+                    arg = 3;
+                else if (fnCandidate.getName().compare("textureGradOffset") == 0)
+                    arg = 4;
+                else if (fnCandidate.getName().compare("textureProjGradOffset") == 0)
+                    arg = 4;
+
+                if (arg > 0) {
+                    if (! callNode.getSequence()[arg]->getAsConstantUnion())
+                        error(loc, "argument must be compile-time constant", "texel offset", "");
+                    else {
+                        const TType& type = callNode.getSequence()[arg]->getAsTyped()->getType();
+                        for (int c = 0; c < type.getVectorSize(); ++c) {
+                            int offset = callNode.getSequence()[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
+                            if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
+                                error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // GL_ARB_shader_texture_image_samples
+    if (fnCandidate.getName().compare(0, 14, "textureSamples") == 0 || fnCandidate.getName().compare(0, 12, "imageSamples") == 0)
+        profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples");
+
+    if (fnCandidate.getName().compare(0, 11, "imageAtomic") == 0) {
+        const TType& imageType = callNode.getSequence()[0]->getAsTyped()->getType();
+        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
+            if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
+        } else {
+            if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0)
+                error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
+            else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile)
+                error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
+        }
+    }
+}
+
+//
+// Do any extra checking for a user function call.
+//
+void TParseContext::userFunctionCallCheck(const TSourceLoc& loc, TIntermAggregate& callNode)
+{
+    TIntermSequence& arguments = callNode.getSequence();
+
+    for (int i = 0; i < (int)arguments.size(); ++i)
+        samplerConstructorLocationCheck(loc, "call argument", arguments[i]);
+}
+
+//
+// Emit an error if this is a sampler constructor
+//
+void TParseContext::samplerConstructorLocationCheck(const TSourceLoc& loc, const char* token, TIntermNode* node)
+{
+    if (node->getAsOperator() && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
+        error(loc, "sampler constructor must appear at point of use", token, "");
+}
+
+//
+// Handle seeing a built-in constructor in a grammar production.
+//
+TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPublicType& publicType)
+{
+    TType type(publicType);
+    type.getQualifier().precision = EpqNone;
+
+    if (type.isArray()) {
+        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed constructor");
+        profileRequires(loc, EEsProfile, 300, nullptr, "arrayed constructor");
+    }
+
+    TOperator op = intermediate.mapTypeToConstructorOp(type);
+
+    if (op == EOpNull) {
+        error(loc, "cannot construct this type", type.getBasicString(), "");
+        op = EOpConstructFloat;
+        TType errorType(EbtFloat);
+        type.shallowCopy(errorType);
+    }
+
+    TString empty("");
+
+    return new TFunction(&empty, type, op);
+}
+
+// Handle seeing a precision qualifier in the grammar.
+void TParseContext::handlePrecisionQualifier(const TSourceLoc& /*loc*/, TQualifier& qualifier, TPrecisionQualifier precision)
+{
+    if (obeyPrecisionQualifiers())
+        qualifier.precision = precision;
+}
+
+// Check for messages to give on seeing a precision qualifier used in a
+// declaration in the grammar.
+void TParseContext::checkPrecisionQualifier(const TSourceLoc& loc, TPrecisionQualifier)
+{
+    if (precisionManager.shouldWarnAboutDefaults()) {
+        warn(loc, "all default precisions are highp; use precision statements to quiet warning, e.g.:\n"
+                  "         \"precision mediump int; precision highp float;\"", "", "");
+        precisionManager.defaultWarningGiven();
+    }
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(const TSourceLoc& loc, const char* op, TString left, TString right)
+{
+    error(loc, "", op, "cannot convert from '%s' to '%s'",
+          right.c_str(), left.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(const TSourceLoc& loc, const char* op, TString operand)
+{
+   error(loc, " wrong operand type", op,
+          "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)",
+          op, operand.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(const TSourceLoc& loc, const char* op, TString left, TString right)
+{
+    error(loc, " wrong operand types:", op,
+            "no operation '%s' exists that takes a left-hand operand of type '%s' and "
+            "a right operand of type '%s' (or there is no acceptable conversion)",
+            op, left.c_str(), right.c_str());
+}
+
+//
+// A basic type of EbtVoid is a key that the name string was seen in the source, but
+// it was not found as a variable in the symbol table.  If so, give the error
+// message and insert a dummy variable in the symbol table to prevent future errors.
+//
+void TParseContext::variableCheck(TIntermTyped*& nodePtr)
+{
+    TIntermSymbol* symbol = nodePtr->getAsSymbolNode();
+    if (! symbol)
+        return;
+
+    if (symbol->getType().getBasicType() == EbtVoid) {
+        const char *extraInfoFormat = "";
+        if (spvVersion.vulkan != 0 && symbol->getName() == "gl_VertexID") {
+          extraInfoFormat = "(Did you mean gl_VertexIndex?)";
+        } else if (spvVersion.vulkan != 0 && symbol->getName() == "gl_InstanceID") {
+          extraInfoFormat = "(Did you mean gl_InstanceIndex?)";
+        }
+        error(symbol->getLoc(), "undeclared identifier", symbol->getName().c_str(), extraInfoFormat);
+
+        // Add to symbol table to prevent future error messages on the same name
+        if (symbol->getName().size() > 0) {
+            TVariable* fakeVariable = new TVariable(&symbol->getName(), TType(EbtFloat));
+            symbolTable.insert(*fakeVariable);
+
+            // substitute a symbol node for this new variable
+            nodePtr = intermediate.addSymbol(*fakeVariable, symbol->getLoc());
+        }
+    } else {
+        switch (symbol->getQualifier().storage) {
+        case EvqPointCoord:
+            profileRequires(symbol->getLoc(), ENoProfile, 120, nullptr, "gl_PointCoord");
+            break;
+        default: break; // some compilers want this
+        }
+    }
+}
+
+//
+// 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 there was an error.
+//
+bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
+{
+    TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+    if (binaryNode) {
+        bool errorReturn = false;
+
+        switch(binaryNode->getOp()) {
+        case EOpIndexDirect:
+        case EOpIndexIndirect:
+            // ...  tessellation control shader ...
+            // If a per-vertex output variable is used as an l-value, it is a
+            // compile-time or link-time error if the expression indicating the
+            // vertex index is not the identifier gl_InvocationID.
+            if (language == EShLangTessControl) {
+                const TType& leftType = binaryNode->getLeft()->getType();
+                if (leftType.getQualifier().storage == EvqVaryingOut && ! leftType.getQualifier().patch && binaryNode->getLeft()->getAsSymbolNode()) {
+                    // we have a per-vertex output
+                    const TIntermSymbol* rightSymbol = binaryNode->getRight()->getAsSymbolNode();
+                    if (! rightSymbol || rightSymbol->getQualifier().builtIn != EbvInvocationId)
+                        error(loc, "tessellation-control per-vertex output l-value must be indexed with gl_InvocationID", "[]", "");
+                }
+            }
+
+            break; // left node is checked by base class
+        case EOpIndexDirectStruct:
+            break; // left node is checked by base class
+        case EOpVectorSwizzle:
+            errorReturn = lValueErrorCheck(loc, 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()->getConstArray()[0].getIConst();
+                    offset[value]++;
+                    if (offset[value] > 1) {
+                        error(loc, " l-value of swizzle cannot have duplicate components", op, "", "");
+
+                        return true;
+                    }
+                }
+            }
+
+            return errorReturn;
+        default:
+            break;
+        }
+
+        if (errorReturn) {
+            error(loc, " l-value required", op, "", "");
+            return true;
+        }
+    }
+
+    // Let the base class check errors
+    if (TParseContextBase::lValueErrorCheck(loc, op, node))
+        return true;
+
+    const char* symbol = nullptr;
+    TIntermSymbol* symNode = node->getAsSymbolNode();
+    if (symNode != nullptr)
+        symbol = symNode->getName().c_str();
+
+    const char* message = nullptr;
+    switch (node->getQualifier().storage) {
+    case EvqVaryingIn:      message = "can't modify shader input";   break;
+    case EvqInstanceId:     message = "can't modify gl_InstanceID";  break;
+    case EvqVertexId:       message = "can't modify gl_VertexID";    break;
+    case EvqFace:           message = "can't modify gl_FrontFace";   break;
+    case EvqFragCoord:      message = "can't modify gl_FragCoord";   break;
+    case EvqPointCoord:     message = "can't modify gl_PointCoord";  break;
+    case EvqFragDepth:
+        intermediate.setDepthReplacing();
+        // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
+        if (profile == EEsProfile && intermediate.getEarlyFragmentTests())
+            message = "can't modify gl_FragDepth if using early_fragment_tests";
+        break;
+
+    default:
+        break;
+    }
+
+    if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
+        error(loc, " l-value required", op, "", "");
+
+        return true;
+    }
+
+    //
+    // Everything else is okay, no error.
+    //
+    if (message == nullptr)
+        return false;
+
+    //
+    // If we get here, we have an error and a message.
+    //
+    if (symNode)
+        error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
+    else
+        error(loc, " l-value required", op, "(%s)", message);
+
+    return true;
+}
+
+// Test for and give an error if the node can't be read from.
+void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
+{
+    // Let the base class check errors
+    TParseContextBase::rValueErrorCheck(loc, op, node);
+
+#ifdef AMD_EXTENSIONS
+    TIntermSymbol* symNode = node->getAsSymbolNode();
+    if (!(symNode && symNode->getQualifier().writeonly)) // base class checks
+        if (symNode && symNode->getQualifier().explicitInterp)
+            error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str());
+#endif
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+//
+void TParseContext::constantValueCheck(TIntermTyped* node, const char* token)
+{
+    if (! node->getQualifier().isConstant())
+        error(node->getLoc(), "constant expression required", token, "");
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+//
+void TParseContext::integerCheck(const TIntermTyped* node, const char* token)
+{
+    if ((node->getBasicType() == EbtInt || node->getBasicType() == EbtUint) && node->isScalar())
+        return;
+
+    error(node->getLoc(), "scalar integer expression required", token, "");
+}
+
+//
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+//
+void TParseContext::globalCheck(const TSourceLoc& loc, const char* token)
+{
+    if (! symbolTable.atGlobalLevel())
+        error(loc, "not allowed in nested scope", token, "");
+}
+
+//
+// Reserved errors for GLSL.
+//
+void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& identifier)
+{
+    // "Identifiers starting with "gl_" are reserved for use by OpenGL, and may not be
+    // declared in a shader; this results in a compile-time error."
+    if (! symbolTable.atBuiltInLevel()) {
+        if (builtInName(identifier))
+            error(loc, "identifiers starting with \"gl_\" are reserved", identifier.c_str(), "");
+
+        // "__" are not supposed to be an error.  ES 310 (and desktop) added the clarification:
+        // "In addition, all identifiers containing two consecutive underscores (__) are
+        // reserved; using such a name does not itself result in an error, but may result
+        // in undefined behavior."
+        // however, before that, ES tests required an error.
+        if (identifier.find("__") != TString::npos) {
+            if (profile == EEsProfile && version <= 300)
+                error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version <= 300", identifier.c_str(), "");
+            else
+                warn(loc, "identifiers containing consecutive underscores (\"__\") are reserved", identifier.c_str(), "");
+        }
+    }
+}
+
+//
+// Reserved errors for the preprocessor.
+//
+void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* identifier, const char* op)
+{
+    // "__" are not supposed to be an error.  ES 310 (and desktop) added the clarification:
+    // "All macro names containing two consecutive underscores ( __ ) are reserved;
+    // defining such a name does not itself result in an error, but may result in
+    // undefined behavior.  All macro names prefixed with "GL_" ("GL" followed by a
+    // single underscore) are also reserved, and defining such a name results in a
+    // compile-time error."
+    // however, before that, ES tests required an error.
+    if (strncmp(identifier, "GL_", 3) == 0)
+        ppError(loc, "names beginning with \"GL_\" can't be (un)defined:", op,  identifier);
+    else if (strncmp(identifier, "defined", 8) == 0)
+        ppError(loc, "\"defined\" can't be (un)defined:", op,  identifier);
+    else if (strstr(identifier, "__") != 0) {
+        if (profile == EEsProfile && version >= 300 &&
+            (strcmp(identifier, "__LINE__") == 0 ||
+             strcmp(identifier, "__FILE__") == 0 ||
+             strcmp(identifier, "__VERSION__") == 0))
+            ppError(loc, "predefined names can't be (un)defined:", op,  identifier);
+        else {
+            if (profile == EEsProfile && version <= 300)
+                ppError(loc, "names containing consecutive underscores are reserved, and an error if version <= 300:", op, identifier);
+            else
+                ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier);
+        }
+    }
+}
+
+//
+// See if this version/profile allows use of the line-continuation character '\'.
+//
+// Returns true if a line continuation should be done.
+//
+bool TParseContext::lineContinuationCheck(const TSourceLoc& loc, bool endOfComment)
+{
+    const char* message = "line continuation";
+
+    bool lineContinuationAllowed = (profile == EEsProfile && version >= 300) ||
+                                   (profile != EEsProfile && (version >= 420 || extensionTurnedOn(E_GL_ARB_shading_language_420pack)));
+
+    if (endOfComment) {
+        if (lineContinuationAllowed)
+            warn(loc, "used at end of comment; the following line is still part of the comment", message, "");
+        else
+            warn(loc, "used at end of comment, but this version does not provide line continuation", message, "");
+
+        return lineContinuationAllowed;
+    }
+
+    if (relaxedErrors()) {
+        if (! lineContinuationAllowed)
+            warn(loc, "not allowed in this version", message, "");
+        return true;
+    } else {
+        profileRequires(loc, EEsProfile, 300, nullptr, message);
+        profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, message);
+    }
+
+    return lineContinuationAllowed;
+}
+
+bool TParseContext::builtInName(const TString& identifier)
+{
+    return identifier.compare(0, 3, "gl_") == 0;
+}
+
+//
+// Make sure there is enough data and not too many arguments provided to the
+// constructor to build something of the type of the constructor.  Also returns
+// the type of the constructor.
+//
+// Part of establishing type is establishing specialization-constness.
+// We don't yet know "top down" whether type is a specialization constant,
+// but a const constructor can becomes a specialization constant if any of
+// its children are, subject to KHR_vulkan_glsl rules:
+//
+//     - int(), uint(), and bool() constructors for type conversions
+//       from any of the following types to any of the following types:
+//         * int
+//         * uint
+//         * bool
+//     - vector versions of the above conversion constructors
+//
+// Returns true if there was an error in construction.
+//
+bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
+{
+    type.shallowCopy(function.getType());
+
+    bool constructingMatrix = false;
+    switch(op) {
+    case EOpConstructTextureSampler:
+        return constructorTextureSamplerError(loc, function);
+    case EOpConstructMat2x2:
+    case EOpConstructMat2x3:
+    case EOpConstructMat2x4:
+    case EOpConstructMat3x2:
+    case EOpConstructMat3x3:
+    case EOpConstructMat3x4:
+    case EOpConstructMat4x2:
+    case EOpConstructMat4x3:
+    case EOpConstructMat4x4:
+    case EOpConstructDMat2x2:
+    case EOpConstructDMat2x3:
+    case EOpConstructDMat2x4:
+    case EOpConstructDMat3x2:
+    case EOpConstructDMat3x3:
+    case EOpConstructDMat3x4:
+    case EOpConstructDMat4x2:
+    case EOpConstructDMat4x3:
+    case EOpConstructDMat4x4:
+        constructingMatrix = true;
+        break;
+    default:
+        break;
+    }
+
+    //
+    // Walk the arguments for first-pass checks and collection of information.
+    //
+
+    int size = 0;
+    bool constType = true;
+    bool specConstType = false;   // value is only valid if constType is true
+    bool full = false;
+    bool overFull = false;
+    bool matrixInMatrix = false;
+    bool arrayArg = false;
+    bool floatArgument = false;
+    for (int arg = 0; arg < function.getParamCount(); ++arg) {
+        if (function[arg].type->isArray()) {
+            if (! function[arg].type->isExplicitlySizedArray()) {
+                // Can't construct from an unsized array.
+                error(loc, "array argument must be sized", "constructor", "");
+                return true;
+            }
+            arrayArg = true;
+        }
+        if (constructingMatrix && function[arg].type->isMatrix())
+            matrixInMatrix = true;
+
+        // 'full' will go to true when enough args have been seen.  If we loop
+        // again, there is an extra argument.
+        if (full) {
+            // For vectors and matrices, it's okay to have too many components
+            // available, but not okay to have unused arguments.
+            overFull = true;
+        }
+
+        size += function[arg].type->computeNumComponents();
+        if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
+            full = true;
+
+        if (! function[arg].type->getQualifier().isConstant())
+            constType = false;
+        if (function[arg].type->getQualifier().isSpecConstant())
+            specConstType = true;
+        if (function[arg].type->isFloatingDomain())
+            floatArgument = true;
+    }
+
+    // inherit constness from children
+    if (constType) {
+        bool makeSpecConst;
+        // Finish pinning down spec-const semantics
+        if (specConstType) {
+            switch (op) {
+            case EOpConstructInt:
+            case EOpConstructUint:
+            case EOpConstructInt64:
+            case EOpConstructUint64:
+            case EOpConstructBool:
+            case EOpConstructBVec2:
+            case EOpConstructBVec3:
+            case EOpConstructBVec4:
+            case EOpConstructIVec2:
+            case EOpConstructIVec3:
+            case EOpConstructIVec4:
+            case EOpConstructUVec2:
+            case EOpConstructUVec3:
+            case EOpConstructUVec4:
+            case EOpConstructI64Vec2:
+            case EOpConstructI64Vec3:
+            case EOpConstructI64Vec4:
+            case EOpConstructU64Vec2:
+            case EOpConstructU64Vec3:
+            case EOpConstructU64Vec4:
+                // This was the list of valid ones, if they aren't converting from float
+                // and aren't making an array.
+                makeSpecConst = ! floatArgument && ! type.isArray();
+                break;
+            default:
+                // anything else wasn't white-listed in the spec as a conversion
+                makeSpecConst = false;
+                break;
+            }
+        } else
+            makeSpecConst = false;
+
+        if (makeSpecConst)
+            type.getQualifier().makeSpecConstant();
+        else if (specConstType)
+            type.getQualifier().makeTemporary();
+        else
+            type.getQualifier().storage = EvqConst;
+    }
+
+    if (type.isArray()) {
+        if (function.getParamCount() == 0) {
+            error(loc, "array constructor must have at least one argument", "constructor", "");
+            return true;
+        }
+
+        if (type.isImplicitlySizedArray()) {
+            // auto adapt the constructor type to the number of arguments
+            type.changeOuterArraySize(function.getParamCount());
+        } else if (type.getOuterArraySize() != function.getParamCount()) {
+            error(loc, "array constructor needs one argument per array element", "constructor", "");
+            return true;
+        }
+
+        if (type.isArrayOfArrays()) {
+            // Types have to match, but we're still making the type.
+            // Finish making the type, and the comparison is done later
+            // when checking for conversion.
+            TArraySizes& arraySizes = type.getArraySizes();
+
+            // At least the dimensionalities have to match.
+            if (! function[0].type->isArray() || arraySizes.getNumDims() != function[0].type->getArraySizes().getNumDims() + 1) {
+                error(loc, "array constructor argument not correct type to construct array element", "constructor", "");
+                return true;
+            }
+
+            if (arraySizes.isInnerImplicit()) {
+                // "Arrays of arrays ..., and the size for any dimension is optional"
+                // That means we need to adopt (from the first argument) the other array sizes into the type.
+                for (int d = 1; d < arraySizes.getNumDims(); ++d) {
+                    if (arraySizes.getDimSize(d) == UnsizedArraySize) {
+                        arraySizes.setDimSize(d, function[0].type->getArraySizes().getDimSize(d - 1));
+                    }
+                }
+            }
+        }
+    }
+
+    if (arrayArg && op != EOpConstructStruct && ! type.isArrayOfArrays()) {
+        error(loc, "constructing non-array constituent from array argument", "constructor", "");
+        return true;
+    }
+
+    if (matrixInMatrix && ! type.isArray()) {
+        profileRequires(loc, ENoProfile, 120, nullptr, "constructing matrix from matrix");
+
+        // "If a matrix argument is given to a matrix constructor,
+        // it is a compile-time error to have any other arguments."
+        if (function.getParamCount() != 1)
+            error(loc, "matrix constructed from matrix can only have one argument", "constructor", "");
+        return false;
+    }
+
+    if (overFull) {
+        error(loc, "too many arguments", "constructor", "");
+        return true;
+    }
+
+    if (op == EOpConstructStruct && ! type.isArray() && (int)type.getStruct()->size() != function.getParamCount()) {
+        error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", "");
+        return true;
+    }
+
+    if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) ||
+        (op == EOpConstructStruct && size < type.computeNumComponents())) {
+        error(loc, "not enough data provided for construction", "constructor", "");
+        return true;
+    }
+
+    TIntermTyped* typed = node->getAsTyped();
+    if (typed == nullptr) {
+        error(loc, "constructor argument does not have a type", "constructor", "");
+        return true;
+    }
+    if (op != EOpConstructStruct && typed->getBasicType() == EbtSampler) {
+        error(loc, "cannot convert a sampler", "constructor", "");
+        return true;
+    }
+    if (op != EOpConstructStruct && typed->getBasicType() == EbtAtomicUint) {
+        error(loc, "cannot convert an atomic_uint", "constructor", "");
+        return true;
+    }
+    if (typed->getBasicType() == EbtVoid) {
+        error(loc, "cannot convert a void", "constructor", "");
+        return true;
+    }
+
+    return false;
+}
+
+// Verify all the correct semantics for constructing a combined texture/sampler.
+// Return true if the semantics are incorrect.
+bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const TFunction& function)
+{
+    TString constructorName = function.getType().getBasicTypeString();  // TODO: performance: should not be making copy; interface needs to change
+    const char* token = constructorName.c_str();
+
+    // exactly two arguments needed
+    if (function.getParamCount() != 2) {
+        error(loc, "sampler-constructor requires two arguments", token, "");
+        return true;
+    }
+
+    // For now, not allowing arrayed constructors, the rest of this function
+    // is set up to allow them, if this test is removed:
+    if (function.getType().isArray()) {
+        error(loc, "sampler-constructor cannot make an array of samplers", token, "");
+        return true;
+    }
+
+    // first argument
+    //  * the constructor's first argument must be a texture type
+    //  * the dimensionality (1D, 2D, 3D, Cube, Rect, Buffer, MS, and Array)
+    //    of the texture type must match that of the constructed sampler type
+    //    (that is, the suffixes of the type of the first argument and the
+    //    type of the constructor will be spelled the same way)
+    if (function[0].type->getBasicType() != EbtSampler ||
+        ! function[0].type->getSampler().isTexture() ||
+        function[0].type->isArray()) {
+        error(loc, "sampler-constructor first argument must be a scalar textureXXX type", token, "");
+        return true;
+    }
+    // simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=()
+    TSampler texture = function.getType().getSampler();
+    texture.combined = false;
+    texture.shadow = false;
+    if (texture != function[0].type->getSampler()) {
+        error(loc, "sampler-constructor first argument must match type and dimensionality of constructor type", token, "");
+        return true;
+    }
+
+    // second argument
+    //   * the constructor's second argument must be a scalar of type
+    //     *sampler* or *samplerShadow*
+    //   * the presence or absence of depth comparison (Shadow) must match
+    //     between the constructed sampler type and the type of the second argument
+    if (  function[1].type->getBasicType() != EbtSampler ||
+        ! function[1].type->getSampler().isPureSampler() ||
+          function[1].type->isArray()) {
+        error(loc, "sampler-constructor second argument must be a scalar type 'sampler'", token, "");
+        return true;
+    }
+    if (function.getType().getSampler().shadow != function[1].type->getSampler().shadow) {
+        error(loc, "sampler-constructor second argument presence of shadow must match constructor presence of shadow", token, "");
+        return true;
+    }
+
+    return false;
+}
+
+// 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& loc, const TString& identifier, const TBasicType basicType)
+{
+    if (basicType == EbtVoid) {
+        error(loc, "illegal use of type 'void'", identifier.c_str(), "");
+        return true;
+    }
+
+    return false;
+}
+
+// Checks to see if the node (for the expression) contains a scalar boolean expression or not
+void TParseContext::boolCheck(const TSourceLoc& loc, const TIntermTyped* type)
+{
+    if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
+        error(loc, "boolean expression expected", "", "");
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
+{
+    if (pType.basicType != EbtBool || pType.arraySizes || pType.matrixCols > 1 || (pType.vectorSize > 1))
+        error(loc, "boolean expression expected", "", "");
+}
+
+void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/)
+{
+    if (type.getQualifier().storage == EvqUniform)
+        return;
+
+    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler))
+        error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str());
+    else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) {
+        // non-uniform sampler
+        // not yet:  okay if it has an initializer
+        // if (! initializer)
+        error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
+    }
+}
+
+void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
+{
+    if (type.getQualifier().storage == EvqUniform)
+        return;
+
+    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAtomicUint))
+        error(loc, "non-uniform struct contains an atomic_uint:", type.getBasicTypeString().c_str(), identifier.c_str());
+    else if (type.getBasicType() == EbtAtomicUint && type.getQualifier().storage != EvqUniform)
+        error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
+}
+
+void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, const TString& /*identifier*/)
+{
+    if (parsingBuiltins)
+        return;
+
+    // Vulkan doesn't allow transparent uniforms outside of blocks
+    if (spvVersion.vulkan == 0 || type.getQualifier().storage != EvqUniform)
+        return;
+    if (type.containsNonOpaque())
+        vulkanRemoved(loc, "non-opaque uniforms outside a block");
+}
+
+//
+// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
+//
+void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier)
+{
+    // move from parameter/unknown qualifiers to pipeline in/out qualifiers
+    switch (qualifier.storage) {
+    case EvqIn:
+        profileRequires(loc, ENoProfile, 130, nullptr, "in for stage inputs");
+        profileRequires(loc, EEsProfile, 300, nullptr, "in for stage inputs");
+        qualifier.storage = EvqVaryingIn;
+        break;
+    case EvqOut:
+        profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs");
+        profileRequires(loc, EEsProfile, 300, nullptr, "out for stage outputs");
+        qualifier.storage = EvqVaryingOut;
+        break;
+    case EvqInOut:
+        qualifier.storage = EvqVaryingIn;
+        error(loc, "cannot use 'inout' at global scope", "", "");
+        break;
+    default:
+        break;
+    }
+
+    invariantCheck(loc, qualifier);
+}
+
+//
+// Check a full qualifier and type (no variable yet) at global level.
+//
+void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TPublicType& publicType)
+{
+    if (! symbolTable.atGlobalLevel())
+        return;
+
+    if (qualifier.isMemory() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer)
+        error(loc, "memory qualifiers cannot be used on this type", "", "");
+
+    if (qualifier.storage == EvqBuffer && publicType.basicType != EbtBlock)
+        error(loc, "buffers can be declared only as blocks", "buffer", "");
+
+    if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
+        return;
+
+    if (publicType.shaderQualifiers.blendEquation)
+        error(loc, "can only be applied to a standalone 'out'", "blend equation", "");
+
+    // now, knowing it is a shader in/out, do all the in/out semantic checks
+
+    if (publicType.basicType == EbtBool) {
+        error(loc, "cannot be bool", GetStorageQualifierString(qualifier.storage), "");
+        return;
+    }
+
+    if (publicType.basicType == EbtInt   || publicType.basicType == EbtUint   ||
+        publicType.basicType == EbtInt64 || publicType.basicType == EbtUint64 ||
+        publicType.basicType == EbtDouble)
+        profileRequires(loc, EEsProfile, 300, nullptr, "shader input/output");
+
+#ifdef AMD_EXTENSIONS
+    if (! qualifier.flat && ! qualifier.explicitInterp) {
+#else
+    if (!qualifier.flat) {
+#endif
+        if (publicType.basicType == EbtInt    || publicType.basicType == EbtUint   ||
+            publicType.basicType == EbtInt64  || publicType.basicType == EbtUint64 ||
+            publicType.basicType == EbtDouble ||
+            (publicType.userDef && (publicType.userDef->containsBasicType(EbtInt)    ||
+                                    publicType.userDef->containsBasicType(EbtUint)   ||
+                                    publicType.userDef->containsBasicType(EbtInt64)  ||
+                                    publicType.userDef->containsBasicType(EbtUint64) ||
+                                    publicType.userDef->containsBasicType(EbtDouble)))) {
+            if (qualifier.storage == EvqVaryingIn && language == EShLangFragment)
+                error(loc, "must be qualified as flat", TType::getBasicString(publicType.basicType), GetStorageQualifierString(qualifier.storage));
+            else if (qualifier.storage == EvqVaryingOut && language == EShLangVertex && version == 300)
+                error(loc, "must be qualified as flat", TType::getBasicString(publicType.basicType), GetStorageQualifierString(qualifier.storage));
+        }
+    }
+
+    if (qualifier.patch && qualifier.isInterpolation())
+        error(loc, "cannot use interpolation qualifiers with patch", "patch", "");
+
+    if (qualifier.storage == EvqVaryingIn) {
+        switch (language) {
+        case EShLangVertex:
+            if (publicType.basicType == EbtStruct) {
+                error(loc, "cannot be a structure or array", GetStorageQualifierString(qualifier.storage), "");
+                return;
+            }
+            if (publicType.arraySizes) {
+                requireProfile(loc, ~EEsProfile, "vertex input arrays");
+                profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
+            }
+            if (publicType.basicType == EbtDouble)
+                profileRequires(loc, ~EEsProfile, 410, nullptr, "vertex-shader `double` type input");
+            if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)
+                error(loc, "vertex input cannot be further qualified", "", "");
+            break;
+
+        case EShLangTessControl:
+            if (qualifier.patch)
+                error(loc, "can only use on output in tessellation-control shader", "patch", "");
+            break;
+
+        case EShLangTessEvaluation:
+            break;
+
+        case EShLangGeometry:
+            break;
+
+        case EShLangFragment:
+            if (publicType.userDef) {
+                profileRequires(loc, EEsProfile, 300, nullptr, "fragment-shader struct input");
+                profileRequires(loc, ~EEsProfile, 150, nullptr, "fragment-shader struct input");
+                if (publicType.userDef->containsStructure())
+                    requireProfile(loc, ~EEsProfile, "fragment-shader struct input containing structure");
+                if (publicType.userDef->containsArray())
+                    requireProfile(loc, ~EEsProfile, "fragment-shader struct input containing an array");
+            }
+            break;
+
+        case EShLangCompute:
+            if (! symbolTable.atBuiltInLevel())
+                error(loc, "global storage input qualifier cannot be used in a compute shader", "in", "");
+            break;
+
+        default:
+            break;
+        }
+    } else {
+        // qualifier.storage == EvqVaryingOut
+        switch (language) {
+        case EShLangVertex:
+            if (publicType.userDef) {
+                profileRequires(loc, EEsProfile, 300, nullptr, "vertex-shader struct output");
+                profileRequires(loc, ~EEsProfile, 150, nullptr, "vertex-shader struct output");
+                if (publicType.userDef->containsStructure())
+                    requireProfile(loc, ~EEsProfile, "vertex-shader struct output containing structure");
+                if (publicType.userDef->containsArray())
+                    requireProfile(loc, ~EEsProfile, "vertex-shader struct output containing an array");
+            }
+
+            break;
+
+        case EShLangTessControl:
+            break;
+
+        case EShLangTessEvaluation:
+            if (qualifier.patch)
+                error(loc, "can only use on input in tessellation-evaluation shader", "patch", "");
+            break;
+
+        case EShLangGeometry:
+            break;
+
+        case EShLangFragment:
+            profileRequires(loc, EEsProfile, 300, nullptr, "fragment shader output");
+            if (publicType.basicType == EbtStruct) {
+                error(loc, "cannot be a structure", GetStorageQualifierString(qualifier.storage), "");
+                return;
+            }
+            if (publicType.matrixRows > 0) {
+                error(loc, "cannot be a matrix", GetStorageQualifierString(qualifier.storage), "");
+                return;
+            }
+            if (qualifier.isAuxiliary())
+                error(loc, "can't use auxiliary qualifier on a fragment output", "centroid/sample/patch", "");
+            if (qualifier.isInterpolation())
+                error(loc, "can't use interpolation qualifier on a fragment output", "flat/smooth/noperspective", "");
+            if (publicType.basicType == EbtDouble)
+                error(loc, "cannot contain a double", GetStorageQualifierString(qualifier.storage), "");
+        break;
+
+        case EShLangCompute:
+            error(loc, "global storage output qualifier cannot be used in a compute shader", "out", "");
+            break;
+
+        default:
+            break;
+        }
+    }
+}
+
+//
+// Merge characteristics of the 'src' qualifier into the 'dst'.
+// If there is duplication, issue error messages, unless 'force'
+// is specified, which means to just override default settings.
+//
+// Also, when force is false, it will be assumed that 'src' follows
+// 'dst', for the purpose of error checking order for versions
+// that require specific orderings of qualifiers.
+//
+void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, const TQualifier& src, bool force)
+{
+    // Multiple auxiliary qualifiers (mostly done later by 'individual qualifiers')
+    if (src.isAuxiliary() && dst.isAuxiliary())
+        error(loc, "can only have one auxiliary qualifier (centroid, patch, and sample)", "", "");
+
+    // Multiple interpolation qualifiers (mostly done later by 'individual qualifiers')
+    if (src.isInterpolation() && dst.isInterpolation())
+#ifdef AMD_EXTENSIONS
+        error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective, __explicitInterpAMD)", "", "");
+#else
+        error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective)", "", "");
+#endif
+
+    // Ordering
+    if (! force && ((profile != EEsProfile && version < 420) ||
+                    (profile == EEsProfile && version < 310))
+                && ! extensionTurnedOn(E_GL_ARB_shading_language_420pack)) {
+        // non-function parameters
+        if (src.noContraction && (dst.invariant || dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
+            error(loc, "precise qualifier must appear first", "", "");
+        if (src.invariant && (dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
+            error(loc, "invariant qualifier must appear before interpolation, storage, and precision qualifiers ", "", "");
+        else if (src.isInterpolation() && (dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
+            error(loc, "interpolation qualifiers must appear before storage and precision qualifiers", "", "");
+        else if (src.isAuxiliary() && (dst.storage != EvqTemporary || dst.precision != EpqNone))
+            error(loc, "Auxiliary qualifiers (centroid, patch, and sample) must appear before storage and precision qualifiers", "", "");
+        else if (src.storage != EvqTemporary && (dst.precision != EpqNone))
+            error(loc, "precision qualifier must appear as last qualifier", "", "");
+
+        // function parameters
+        if (src.noContraction && (dst.storage == EvqConst || dst.storage == EvqIn || dst.storage == EvqOut))
+            error(loc, "precise qualifier must appear first", "", "");
+        if (src.storage == EvqConst && (dst.storage == EvqIn || dst.storage == EvqOut))
+            error(loc, "in/out must appear before const", "", "");
+    }
+
+    // Storage qualification
+    if (dst.storage == EvqTemporary || dst.storage == EvqGlobal)
+        dst.storage = src.storage;
+    else if ((dst.storage == EvqIn  && src.storage == EvqOut) ||
+             (dst.storage == EvqOut && src.storage == EvqIn))
+        dst.storage = EvqInOut;
+    else if ((dst.storage == EvqIn    && src.storage == EvqConst) ||
+             (dst.storage == EvqConst && src.storage == EvqIn))
+        dst.storage = EvqConstReadOnly;
+    else if (src.storage != EvqTemporary &&
+             src.storage != EvqGlobal)
+        error(loc, "too many storage qualifiers", GetStorageQualifierString(src.storage), "");
+
+    // Precision qualifiers
+    if (! force && src.precision != EpqNone && dst.precision != EpqNone)
+        error(loc, "only one precision qualifier allowed", GetPrecisionQualifierString(src.precision), "");
+    if (dst.precision == EpqNone || (force && src.precision != EpqNone))
+        dst.precision = src.precision;
+
+    // Layout qualifiers
+    mergeObjectLayoutQualifiers(dst, src, false);
+
+    // individual qualifiers
+    bool repeated = false;
+    #define MERGE_SINGLETON(field) repeated |= dst.field && src.field; dst.field |= src.field;
+    MERGE_SINGLETON(invariant);
+    MERGE_SINGLETON(noContraction);
+    MERGE_SINGLETON(centroid);
+    MERGE_SINGLETON(smooth);
+    MERGE_SINGLETON(flat);
+    MERGE_SINGLETON(nopersp);
+#ifdef AMD_EXTENSIONS
+    MERGE_SINGLETON(explicitInterp);
+#endif
+    MERGE_SINGLETON(patch);
+    MERGE_SINGLETON(sample);
+    MERGE_SINGLETON(coherent);
+    MERGE_SINGLETON(volatil);
+    MERGE_SINGLETON(restrict);
+    MERGE_SINGLETON(readonly);
+    MERGE_SINGLETON(writeonly);
+    MERGE_SINGLETON(specConstant);
+
+    if (repeated)
+        error(loc, "replicated qualifiers", "", "");
+}
+
+void TParseContext::setDefaultPrecision(const TSourceLoc& loc, TPublicType& publicType, TPrecisionQualifier qualifier)
+{
+    TBasicType basicType = publicType.basicType;
+
+    if (basicType == EbtSampler) {
+        defaultSamplerPrecision[computeSamplerTypeIndex(publicType.sampler)] = qualifier;
+
+        return;  // all is well
+    }
+
+    if (basicType == EbtInt || basicType == EbtFloat) {
+        if (publicType.isScalar()) {
+            defaultPrecision[basicType] = qualifier;
+            if (basicType == EbtInt) {
+                defaultPrecision[EbtUint] = qualifier;
+                precisionManager.explicitIntDefaultSeen();
+            } else
+                precisionManager.explicitFloatDefaultSeen();
+
+            return;  // all is well
+        }
+    }
+
+    if (basicType == EbtAtomicUint) {
+        if (qualifier != EpqHigh)
+            error(loc, "can only apply highp to atomic_uint", "precision", "");
+
+        return;
+    }
+
+    error(loc, "cannot apply precision statement to this type; use 'float', 'int' or a sampler type", TType::getBasicString(basicType), "");
+}
+
+// used to flatten the sampler type space into a single dimension
+// correlates with the declaration of defaultSamplerPrecision[]
+int TParseContext::computeSamplerTypeIndex(TSampler& sampler)
+{
+    int arrayIndex    = sampler.arrayed ? 1 : 0;
+    int shadowIndex   = sampler.shadow  ? 1 : 0;
+    int externalIndex = sampler.external? 1 : 0;
+    int imageIndex    = sampler.image   ? 1 : 0;
+    int msIndex       = sampler.ms      ? 1 : 0;
+
+    int flattened = EsdNumDims * (EbtNumTypes * (2 * (2 * (2 * (2 * arrayIndex + msIndex) + imageIndex) + shadowIndex) +
+                                                 externalIndex) + sampler.type) + sampler.dim;
+    assert(flattened < maxSamplerIndex);
+
+    return flattened;
+}
+
+TPrecisionQualifier TParseContext::getDefaultPrecision(TPublicType& publicType)
+{
+    if (publicType.basicType == EbtSampler)
+        return defaultSamplerPrecision[computeSamplerTypeIndex(publicType.sampler)];
+    else
+        return defaultPrecision[publicType.basicType];
+}
+
+void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType baseType, TQualifier& qualifier)
+{
+    // Built-in symbols are allowed some ambiguous precisions, to be pinned down
+    // later by context.
+    if (! obeyPrecisionQualifiers() || parsingBuiltins)
+        return;
+
+    if (baseType == EbtAtomicUint && qualifier.precision != EpqNone && qualifier.precision != EpqHigh)
+        error(loc, "atomic counters can only be highp", "atomic_uint", "");
+
+    if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) {
+        if (qualifier.precision == EpqNone) {
+            if (relaxedErrors())
+                warn(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "substituting 'mediump'");
+            else
+                error(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "");
+            qualifier.precision = EpqMedium;
+            defaultPrecision[baseType] = EpqMedium;
+        }
+    } else if (qualifier.precision != EpqNone)
+        error(loc, "type cannot have precision qualifier", TType::getBasicString(baseType), "");
+}
+
+void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier qualifier, const TType& type)
+{
+    if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque())
+        error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), "");
+}
+
+bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType basicType)
+{
+    if (type.getBasicType() == basicType)
+        return true;
+
+    if (type.getBasicType() == EbtStruct) {
+        const TTypeList& structure = *type.getStruct();
+        for (unsigned int i = 0; i < structure.size(); ++i) {
+            if (containsFieldWithBasicType(*structure[i].type, basicType))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+//
+// Do size checking for an array type's size.
+//
+void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair)
+{
+    bool isConst = false;
+    sizePair.node = nullptr;
+
+    int size = 1;
+
+    TIntermConstantUnion* constant = expr->getAsConstantUnion();
+    if (constant) {
+        // handle true (non-specialization) constant
+        size = constant->getConstArray()[0].getIConst();
+        isConst = true;
+    } else {
+        // see if it's a specialization constant instead
+        if (expr->getQualifier().isSpecConstant()) {
+            isConst = true;
+            sizePair.node = expr;
+            TIntermSymbol* symbol = expr->getAsSymbolNode();
+            if (symbol && symbol->getConstArray().size() > 0)
+                size = symbol->getConstArray()[0].getIConst();
+        }
+    }
+
+    sizePair.size = size;
+
+    if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
+        error(loc, "array size must be a constant integer expression", "", "");
+        return;
+    }
+
+    if (size <= 0) {
+        error(loc, "array size must be a positive integer", "", "");
+        return;
+    }
+}
+
+//
+// See if this qualifier can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayQualifierError(const TSourceLoc& loc, const TQualifier& qualifier)
+{
+    if (qualifier.storage == EvqConst) {
+        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "const array");
+        profileRequires(loc, EEsProfile, 300, nullptr, "const array");
+    }
+
+    if (qualifier.storage == EvqVaryingIn && language == EShLangVertex) {
+        requireProfile(loc, ~EEsProfile, "vertex input arrays");
+        profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
+    }
+
+    return false;
+}
+
+//
+// See if this qualifier and type combination can be an array.
+// Assumes arrayQualifierError() was also called to catch the type-invariant tests.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayError(const TSourceLoc& loc, const TType& type)
+{
+    if (type.getQualifier().storage == EvqVaryingOut && language == EShLangVertex) {
+        if (type.isArrayOfArrays())
+            requireProfile(loc, ~EEsProfile, "vertex-shader array-of-array output");
+        else if (type.isStruct())
+            requireProfile(loc, ~EEsProfile, "vertex-shader array-of-struct output");
+    }
+    if (type.getQualifier().storage == EvqVaryingIn && language == EShLangFragment) {
+        if (type.isArrayOfArrays())
+            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-array input");
+        else if (type.isStruct())
+            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-struct input");
+    }
+    if (type.getQualifier().storage == EvqVaryingOut && language == EShLangFragment) {
+        if (type.isArrayOfArrays())
+            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-array output");
+    }
+
+    return false;
+}
+
+//
+// Require array to be completely sized
+//
+void TParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes)
+{
+    if (arraySizes.isImplicit())
+        error(loc, "array size required", "", "");
+}
+
+void TParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& type)
+{
+    const TTypeList& structure = *type.getStruct();
+    for (int m = 0; m < (int)structure.size(); ++m) {
+        const TType& member = *structure[m].type;
+        if (member.isArray())
+            arraySizeRequiredCheck(structure[m].loc, *member.getArraySizes());
+    }
+}
+
+void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TArraySizes* arraySizes, bool initializer, bool lastMember)
+{
+    assert(arraySizes);
+
+    // always allow special built-in ins/outs sized to topologies
+    if (parsingBuiltins)
+        return;
+
+    // always allow an initializer to set any unknown array sizes
+    if (initializer)
+        return;
+
+    // No environment lets any non-outer-dimension that's to be implicitly sized
+    if (arraySizes->isInnerImplicit())
+        error(loc, "only outermost dimension of an array of arrays can be implicitly sized", "[]", "");
+
+    // desktop always allows outer-dimension-unsized variable arrays,
+    if (profile != EEsProfile)
+        return;
+
+    // for ES, if size isn't coming from an initializer, it has to be explicitly declared now,
+    // with very few exceptions
+
+    // last member of ssbo block exception:
+    if (qualifier.storage == EvqBuffer && lastMember)
+        return;
+
+    // implicitly-sized io exceptions:
+    switch (language) {
+    case EShLangGeometry:
+        if (qualifier.storage == EvqVaryingIn)
+            if (extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader))
+                return;
+        break;
+    case EShLangTessControl:
+        if ( qualifier.storage == EvqVaryingIn ||
+            (qualifier.storage == EvqVaryingOut && ! qualifier.patch))
+            if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
+                return;
+        break;
+    case EShLangTessEvaluation:
+        if ((qualifier.storage == EvqVaryingIn && ! qualifier.patch) ||
+             qualifier.storage == EvqVaryingOut)
+            if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
+                return;
+        break;
+    default:
+        break;
+    }
+
+    arraySizeRequiredCheck(loc, *arraySizes);
+}
+
+void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc)
+{
+    const char* feature = "arrays of arrays";
+
+    requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
+    profileRequires(loc, EEsProfile, 310, nullptr, feature);
+    profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature);
+}
+
+void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TArraySizes* sizes1, const TArraySizes* sizes2)
+{
+    if ((sizes1 && sizes2) ||
+        (sizes1 && sizes1->getNumDims() > 1) ||
+        (sizes2 && sizes2->getNumDims() > 1))
+        arrayOfArrayVersionCheck(loc);
+}
+
+void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TType* type, const TArraySizes* sizes2)
+{
+    // skip checking for multiple dimensions on the type; it was caught earlier
+    if ((type && type->isArray() && sizes2) ||
+        (sizes2 && sizes2->getNumDims() > 1))
+        arrayOfArrayVersionCheck(loc);
+}
+
+// Merge array dimensions listed in 'sizes' onto the type's array dimensions.
+//
+// From the spec: "vec4[2] a[3]; // size-3 array of size-2 array of vec4"
+//
+// That means, the 'sizes' go in front of the 'type' as outermost sizes.
+// 'type' is the type part of the declaration (to the left)
+// 'sizes' is the arrayness tagged on the identifier (to the right)
+//
+void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes)
+{
+    if (sizes)
+        type.addArrayOuterSizes(*sizes);
+}
+
+//
+// Do all the semantic checking for declaring or redeclaring an array, with and
+// without a size, and make the right changes to the symbol table.
+//
+void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol)
+{
+    if (symbol == nullptr) {
+        bool currentScope;
+        symbol = symbolTable.find(identifier, nullptr, &currentScope);
+
+        if (symbol && builtInName(identifier) && ! symbolTable.atBuiltInLevel()) {
+            // bad shader (errors already reported) trying to redeclare a built-in name as an array
+            symbol = nullptr;
+            return;
+        }
+        if (symbol == nullptr || ! currentScope) {
+            //
+            // Successfully process a new definition.
+            // (Redeclarations have to take place at the same scope; otherwise they are hiding declarations)
+            //
+            symbol = new TVariable(&identifier, type);
+            symbolTable.insert(*symbol);
+            if (symbolTable.atGlobalLevel())
+                trackLinkageDeferred(*symbol);
+
+            if (! symbolTable.atBuiltInLevel()) {
+                if (isIoResizeArray(type)) {
+                    ioArraySymbolResizeList.push_back(symbol);
+                    checkIoArraysConsistency(loc, true);
+                } else
+                    fixIoArraySize(loc, symbol->getWritableType());
+            }
+
+            return;
+        }
+        if (symbol->getAsAnonMember()) {
+            error(loc, "cannot redeclare a user-block member array", identifier.c_str(), "");
+            symbol = nullptr;
+            return;
+        }
+    }
+
+    //
+    // Process a redeclaration.
+    //
+
+    if (symbol == nullptr) {
+        error(loc, "array variable name expected", identifier.c_str(), "");
+        return;
+    }
+
+    // redeclareBuiltinVariable() should have already done the copyUp()
+    TType& existingType = symbol->getWritableType();
+
+    if (! existingType.isArray()) {
+        error(loc, "redeclaring non-array as array", identifier.c_str(), "");
+        return;
+    }
+
+    if (! existingType.sameElementType(type)) {
+        error(loc, "redeclaration of array with a different element type", identifier.c_str(), "");
+        return;
+    }
+
+    if (! existingType.sameInnerArrayness(type)) {
+        error(loc, "redeclaration of array with a different array dimensions or sizes", identifier.c_str(), "");
+        return;
+    }
+
+    if (existingType.isExplicitlySizedArray()) {
+        // be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
+        if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize()))
+            error(loc, "redeclaration of array with size", identifier.c_str(), "");
+        return;
+    }
+
+    arrayLimitCheck(loc, identifier, type.getOuterArraySize());
+
+    existingType.updateArraySizes(type);
+
+    if (isIoResizeArray(type))
+        checkIoArraysConsistency(loc);
+}
+
+void TParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode *node, int index)
+{
+    // maybe there is nothing to do...
+    TIntermTyped* typedNode = node->getAsTyped();
+    if (typedNode->getType().getImplicitArraySize() > index)
+        return;
+
+    // something to do...
+
+    // Figure out what symbol to lookup, as we will use its type to edit for the size change,
+    // as that type will be shared through shallow copies for future references.
+    TSymbol* symbol = nullptr;
+    int blockIndex = -1;
+    const TString* lookupName = nullptr;
+    if (node->getAsSymbolNode())
+        lookupName = &node->getAsSymbolNode()->getName();
+    else if (node->getAsBinaryNode()) {
+        const TIntermBinary* deref = node->getAsBinaryNode();
+        // This has to be the result of a block dereference, unless it's bad shader code
+        // If it's a uniform block, then an error will be issued elsewhere, but
+        // return early now to avoid crashing later in this function.
+        if (deref->getLeft()->getBasicType() != EbtBlock ||
+            deref->getLeft()->getType().getQualifier().storage == EvqUniform ||
+            deref->getRight()->getAsConstantUnion() == nullptr)
+            return;
+
+        const TIntermTyped* left  = deref->getLeft();
+        const TIntermTyped* right = deref->getRight();
+
+        if (left->getAsBinaryNode()) {
+            left = left->getAsBinaryNode()->getLeft(); // Block array access
+            assert(left->isArray());
+        }
+
+        if (! left->getAsSymbolNode())
+            return;
+
+        blockIndex = right->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+        lookupName = &left->getAsSymbolNode()->getName();
+        if (IsAnonymous(*lookupName))
+            lookupName = &(*left->getType().getStruct())[blockIndex].type->getFieldName();
+    }
+
+    // Lookup the symbol, should only fail if shader code is incorrect
+    symbol = symbolTable.find(*lookupName);
+    if (symbol == nullptr)
+        return;
+
+    if (symbol->getAsFunction()) {
+        error(loc, "array variable name expected", symbol->getName().c_str(), "");
+        return;
+    }
+
+    if (symbol->getType().isStruct() && blockIndex != -1)
+        (*symbol->getWritableType().getStruct())[blockIndex].type->setImplicitArraySize(index + 1);
+    else
+        symbol->getWritableType().setImplicitArraySize(index + 1);
+}
+
+// Returns true if the first argument to the #line directive is the line number for the next line.
+//
+// Desktop, pre-version 3.30:  "After processing this directive
+// (including its new-line), the implementation will behave as if it is compiling at line number line+1 and
+// source string number source-string-number."
+//
+// Desktop, version 3.30 and later, and ES:  "After processing this directive
+// (including its new-line), the implementation will behave as if it is compiling at line number line and
+// source string number source-string-number.
+bool TParseContext::lineDirectiveShouldSetNextLine() const
+{
+    return profile == EEsProfile || version >= 330;
+}
+
+//
+// Enforce non-initializer type/qualifier rules.
+//
+void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier, TType& type)
+{
+    //
+    // Make the qualifier make sense, given that there is not an initializer.
+    //
+    if (type.getQualifier().storage == EvqConst ||
+        type.getQualifier().storage == EvqConstReadOnly) {
+        type.getQualifier().makeTemporary();
+        error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
+    }
+}
+
+//
+// See if the identifier is a built-in symbol that can be redeclared, and if so,
+// copy the symbol table's read-only built-in variable to the current
+// global level, where it can be modified based on the passed in type.
+//
+// Returns nullptr if no redeclaration took place; meaning a normal declaration still
+// needs to occur for it, not necessarily an error.
+//
+// Returns a redeclared and type-modified variable if a redeclarated occurred.
+//
+TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier,
+                                                 const TQualifier& qualifier, const TShaderQualifiers& publicType)
+{
+    if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel())
+        return nullptr;
+
+    bool nonEsRedecls = (profile != EEsProfile && (version >= 130 || identifier == "gl_TexCoord"));
+    bool    esRedecls = (profile == EEsProfile && extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks));
+    if (! esRedecls && ! nonEsRedecls)
+        return nullptr;
+
+    // Special case when using GL_ARB_separate_shader_objects
+    bool ssoPre150 = false;  // means the only reason this variable is redeclared is due to this combination
+    if (profile != EEsProfile && version <= 140 && extensionTurnedOn(E_GL_ARB_separate_shader_objects)) {
+        if (identifier == "gl_Position"     ||
+            identifier == "gl_PointSize"    ||
+            identifier == "gl_ClipVertex"   ||
+            identifier == "gl_FogFragCoord")
+            ssoPre150 = true;
+    }
+
+    // Potentially redeclaring a built-in variable...
+
+    if (ssoPre150 ||
+        (identifier == "gl_FragDepth"           && ((nonEsRedecls && version >= 420) || esRedecls)) ||
+        (identifier == "gl_FragCoord"           && ((nonEsRedecls && version >= 150) || esRedecls)) ||
+         identifier == "gl_ClipDistance"                                                            ||
+         identifier == "gl_CullDistance"                                                            ||
+         identifier == "gl_FrontColor"                                                              ||
+         identifier == "gl_BackColor"                                                               ||
+         identifier == "gl_FrontSecondaryColor"                                                     ||
+         identifier == "gl_BackSecondaryColor"                                                      ||
+         identifier == "gl_SecondaryColor"                                                          ||
+        (identifier == "gl_Color"               && language == EShLangFragment)                     ||
+#ifdef NV_EXTENSIONS
+         identifier == "gl_SampleMask"                                                              ||
+         identifier == "gl_Layer"                                                                   ||
+#endif
+         identifier == "gl_TexCoord") {
+
+        // Find the existing symbol, if any.
+        bool builtIn;
+        TSymbol* symbol = symbolTable.find(identifier, &builtIn);
+
+        // If the symbol was not found, this must be a version/profile/stage
+        // that doesn't have it.
+        if (! symbol)
+            return nullptr;
+
+        // If it wasn't at a built-in level, then it's already been redeclared;
+        // that is, this is a redeclaration of a redeclaration; reuse that initial
+        // redeclaration.  Otherwise, make the new one.
+        if (builtIn)
+            makeEditable(symbol);
+
+        // Now, modify the type of the copy, as per the type of the current redeclaration.
+
+        TQualifier& symbolQualifier = symbol->getWritableType().getQualifier();
+        if (ssoPre150) {
+            if (intermediate.inIoAccessed(identifier))
+                error(loc, "cannot redeclare after use", identifier.c_str(), "");
+            if (qualifier.hasLayout())
+                error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
+            if (qualifier.isMemory() || qualifier.isAuxiliary() || (language == EShLangVertex   && qualifier.storage != EvqVaryingOut) ||
+                                                                   (language == EShLangFragment && qualifier.storage != EvqVaryingIn))
+                error(loc, "cannot change storage, memory, or auxiliary qualification of", "redeclaration", symbol->getName().c_str());
+            if (! qualifier.smooth)
+                error(loc, "cannot change interpolation qualification of", "redeclaration", symbol->getName().c_str());
+        } else if (identifier == "gl_FrontColor"          ||
+                   identifier == "gl_BackColor"           ||
+                   identifier == "gl_FrontSecondaryColor" ||
+                   identifier == "gl_BackSecondaryColor"  ||
+                   identifier == "gl_SecondaryColor"      ||
+                   identifier == "gl_Color") {
+            symbolQualifier.flat = qualifier.flat;
+            symbolQualifier.smooth = qualifier.smooth;
+            symbolQualifier.nopersp = qualifier.nopersp;
+            if (qualifier.hasLayout())
+                error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
+            if (qualifier.isMemory() || qualifier.isAuxiliary() || symbol->getType().getQualifier().storage != qualifier.storage)
+                error(loc, "cannot change storage, memory, or auxiliary qualification of", "redeclaration", symbol->getName().c_str());
+        } else if (identifier == "gl_TexCoord"     ||
+                   identifier == "gl_ClipDistance" ||
+                   identifier == "gl_CullDistance") {
+            if (qualifier.hasLayout() || qualifier.isMemory() || qualifier.isAuxiliary() ||
+                qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
+                symbolQualifier.storage != qualifier.storage)
+                error(loc, "cannot change qualification of", "redeclaration", symbol->getName().c_str());
+        } else if (identifier == "gl_FragCoord") {
+            if (intermediate.inIoAccessed("gl_FragCoord"))
+                error(loc, "cannot redeclare after use", "gl_FragCoord", "");
+            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
+                qualifier.isMemory() || qualifier.isAuxiliary())
+                error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
+            if (qualifier.storage != EvqVaryingIn)
+                error(loc, "cannot change input storage qualification of", "redeclaration", symbol->getName().c_str());
+            if (! builtIn && (publicType.pixelCenterInteger != intermediate.getPixelCenterInteger() ||
+                              publicType.originUpperLeft != intermediate.getOriginUpperLeft()))
+                error(loc, "cannot redeclare with different qualification:", "redeclaration", symbol->getName().c_str());
+            if (publicType.pixelCenterInteger)
+                intermediate.setPixelCenterInteger();
+            if (publicType.originUpperLeft)
+                intermediate.setOriginUpperLeft();
+        } else if (identifier == "gl_FragDepth") {
+            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
+                qualifier.isMemory() || qualifier.isAuxiliary())
+                error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
+            if (qualifier.storage != EvqVaryingOut)
+                error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
+            if (publicType.layoutDepth != EldNone) {
+                if (intermediate.inIoAccessed("gl_FragDepth"))
+                    error(loc, "cannot redeclare after use", "gl_FragDepth", "");
+                if (! intermediate.setDepth(publicType.layoutDepth))
+                    error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str());
+            }
+        }
+#ifdef NV_EXTENSIONS
+        else if (identifier == "gl_SampleMask") {
+            if (!publicType.layoutOverrideCoverage) {
+                error(loc, "redeclaration only allowed for override_coverage layout", "redeclaration", symbol->getName().c_str());
+            }
+            intermediate.setLayoutOverrideCoverage();
+        }
+        else if (identifier == "gl_Layer") {
+            if (!qualifier.layoutViewportRelative && qualifier.layoutSecondaryViewportRelativeOffset == -2048)
+                error(loc, "redeclaration only allowed for viewport_relative or secondary_view_offset layout", "redeclaration", symbol->getName().c_str());
+            symbolQualifier.layoutViewportRelative = qualifier.layoutViewportRelative;
+            symbolQualifier.layoutSecondaryViewportRelativeOffset = qualifier.layoutSecondaryViewportRelativeOffset;
+        }
+#endif
+
+        // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
+
+        return symbol;
+    }
+
+    return nullptr;
+}
+
+//
+// Either redeclare the requested block, or give an error message why it can't be done.
+//
+// TODO: functionality: explicitly sizing members of redeclared blocks is not giving them an explicit size
+void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes)
+{
+    const char* feature = "built-in block redeclaration";
+    profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
+    profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
+
+    if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment") {
+        error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str());
+        return;
+    }
+
+    // Redeclaring a built-in block...
+
+    if (instanceName && ! builtInName(*instanceName)) {
+        error(loc, "cannot redeclare a built-in block with a user name", instanceName->c_str(), "");
+        return;
+    }
+
+    // Blocks with instance names are easy to find, lookup the instance name,
+    // Anonymous blocks need to be found via a member.
+    bool builtIn;
+    TSymbol* block;
+    if (instanceName)
+        block = symbolTable.find(*instanceName, &builtIn);
+    else
+        block = symbolTable.find(newTypeList.front().type->getFieldName(), &builtIn);
+
+    // If the block was not found, this must be a version/profile/stage
+    // that doesn't have it, or the instance name is wrong.
+    const char* errorName = instanceName ? instanceName->c_str() : newTypeList.front().type->getFieldName().c_str();
+    if (! block) {
+        error(loc, "no declaration found for redeclaration", errorName, "");
+        return;
+    }
+    // Built-in blocks cannot be redeclared more than once, which if happened,
+    // we'd be finding the already redeclared one here, rather than the built in.
+    if (! builtIn) {
+        error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), "");
+        return;
+    }
+
+    // Copy the block to make a writable version, to insert into the block table after editing.
+    block = symbolTable.copyUpDeferredInsert(block);
+
+    if (block->getType().getBasicType() != EbtBlock) {
+        error(loc, "cannot redeclare a non block as a block", errorName, "");
+        return;
+    }
+
+    // Edit and error check the container against the redeclaration
+    //  - remove unused members
+    //  - ensure remaining qualifiers/types match
+    TType& type = block->getWritableType();
+
+#ifdef NV_EXTENSIONS
+    // if gl_PerVertex is redeclared for the purpose of passing through "gl_Position"
+    // for passthrough purpose, the redclared block should have the same qualifers as
+    // the current one
+    if (currentBlockQualifier.layoutPassthrough)
+    {
+        type.getQualifier().layoutPassthrough = currentBlockQualifier.layoutPassthrough;
+        type.getQualifier().storage = currentBlockQualifier.storage;
+        type.getQualifier().layoutStream = currentBlockQualifier.layoutStream;
+        type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
+    }
+#endif
+
+    TTypeList::iterator member = type.getWritableStruct()->begin();
+    size_t numOriginalMembersFound = 0;
+    while (member != type.getStruct()->end()) {
+        // look for match
+        bool found = false;
+        TTypeList::const_iterator newMember;
+        TSourceLoc memberLoc;
+        memberLoc.init();
+        for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) {
+            if (member->type->getFieldName() == newMember->type->getFieldName()) {
+                found = true;
+                memberLoc = newMember->loc;
+                break;
+            }
+        }
+
+        if (found) {
+            ++numOriginalMembersFound;
+            // - ensure match between redeclared members' types
+            // - check for things that can't be changed
+            // - update things that can be changed
+            TType& oldType = *member->type;
+            const TType& newType = *newMember->type;
+            if (! newType.sameElementType(oldType))
+                error(memberLoc, "cannot redeclare block member with a different type", member->type->getFieldName().c_str(), "");
+            if (oldType.isArray() != newType.isArray())
+                error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), "");
+            else if (! oldType.sameArrayness(newType) && oldType.isExplicitlySizedArray())
+                error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), "");
+            else if (newType.isArray())
+                arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize());
+            if (newType.getQualifier().isMemory())
+                error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
+            if (newType.getQualifier().hasLayout())
+                error(memberLoc, "cannot add layout to redeclared block member", member->type->getFieldName().c_str(), "");
+            if (newType.getQualifier().patch)
+                error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), "");
+            oldType.getQualifier().centroid = newType.getQualifier().centroid;
+            oldType.getQualifier().sample = newType.getQualifier().sample;
+            oldType.getQualifier().invariant = newType.getQualifier().invariant;
+            oldType.getQualifier().noContraction = newType.getQualifier().noContraction;
+            oldType.getQualifier().smooth = newType.getQualifier().smooth;
+            oldType.getQualifier().flat = newType.getQualifier().flat;
+            oldType.getQualifier().nopersp = newType.getQualifier().nopersp;
+
+#ifdef NV_EXTENSIONS
+            if (member->type->getFieldName() == "gl_Layer") {
+                if (!newType.getQualifier().layoutViewportRelative && newType.getQualifier().layoutSecondaryViewportRelativeOffset == -2048)
+                    error(loc, "redeclaration only allowed for viewport_relative or secondary_view_offset layout", "redeclaration", member->type->getFieldName().c_str());
+                oldType.getQualifier().layoutViewportRelative = newType.getQualifier().layoutViewportRelative;
+                oldType.getQualifier().layoutSecondaryViewportRelativeOffset = newType.getQualifier().layoutSecondaryViewportRelativeOffset;
+            }
+            if (oldType.isImplicitlySizedArray() && newType.isExplicitlySizedArray())
+                oldType.changeOuterArraySize(newType.getOuterArraySize());
+#endif
+
+            // go to next member
+            ++member;
+        } else {
+            // For missing members of anonymous blocks that have been redeclared,
+            // hide the original (shared) declaration.
+            // Instance-named blocks can just have the member removed.
+            if (instanceName)
+                member = type.getWritableStruct()->erase(member);
+            else {
+                member->type->hideMember();
+                ++member;
+            }
+        }
+    }
+
+    if (numOriginalMembersFound < newTypeList.size())
+        error(loc, "block redeclaration has extra members", blockName.c_str(), "");
+    if (type.isArray() != (arraySizes != nullptr))
+        error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), "");
+    else if (type.isArray()) {
+        if (type.isExplicitlySizedArray() && arraySizes->getOuterSize() == UnsizedArraySize)
+            error(loc, "block already declared with size, can't redeclare as implicitly-sized", blockName.c_str(), "");
+        else if (type.isExplicitlySizedArray() && type.getArraySizes() != *arraySizes)
+            error(loc, "cannot change array size of redeclared block", blockName.c_str(), "");
+        else if (type.isImplicitlySizedArray() && arraySizes->getOuterSize() != UnsizedArraySize)
+            type.changeOuterArraySize(arraySizes->getOuterSize());
+    }
+
+    symbolTable.insert(*block);
+
+    // Check for general layout qualifier errors
+    layoutObjectCheck(loc, *block);
+
+    // Tracking for implicit sizing of array
+    if (isIoResizeArray(block->getType())) {
+        ioArraySymbolResizeList.push_back(block);
+        checkIoArraysConsistency(loc, true);
+    } else if (block->getType().isArray())
+        fixIoArraySize(loc, block->getWritableType());
+
+    // Save it in the AST for linker use.
+    trackLinkageDeferred(*block);
+}
+
+void TParseContext::paramCheckFix(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
+{
+    switch (qualifier) {
+    case EvqConst:
+    case EvqConstReadOnly:
+        type.getQualifier().storage = EvqConstReadOnly;
+        break;
+    case EvqIn:
+    case EvqOut:
+    case EvqInOut:
+        type.getQualifier().storage = qualifier;
+        break;
+    case EvqGlobal:
+    case EvqTemporary:
+        type.getQualifier().storage = EvqIn;
+        break;
+    default:
+        type.getQualifier().storage = EvqIn;
+        error(loc, "storage qualifier not allowed on function parameter", GetStorageQualifierString(qualifier), "");
+        break;
+    }
+}
+
+void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& qualifier, TType& type)
+{
+    if (qualifier.isMemory()) {
+        type.getQualifier().volatil   = qualifier.volatil;
+        type.getQualifier().coherent  = qualifier.coherent;
+        type.getQualifier().readonly  = qualifier.readonly;
+        type.getQualifier().writeonly = qualifier.writeonly;
+        type.getQualifier().restrict  = qualifier.restrict;
+    }
+
+    if (qualifier.isAuxiliary() ||
+        qualifier.isInterpolation())
+        error(loc, "cannot use auxiliary or interpolation qualifiers on a function parameter", "", "");
+    if (qualifier.hasLayout())
+        error(loc, "cannot use layout qualifiers on a function parameter", "", "");
+    if (qualifier.invariant)
+        error(loc, "cannot use invariant qualifier on a function parameter", "", "");
+    if (qualifier.noContraction) {
+        if (qualifier.isParamOutput())
+            type.getQualifier().noContraction = true;
+        else
+            warn(loc, "qualifier has no effect on non-output parameters", "precise", "");
+    }
+
+    paramCheckFix(loc, qualifier.storage, type);
+}
+
+void TParseContext::nestedBlockCheck(const TSourceLoc& loc)
+{
+    if (structNestingLevel > 0)
+        error(loc, "cannot nest a block definition inside a structure or block", "", "");
+    ++structNestingLevel;
+}
+
+void TParseContext::nestedStructCheck(const TSourceLoc& loc)
+{
+    if (structNestingLevel > 0)
+        error(loc, "cannot nest a structure definition inside a structure or block", "", "");
+    ++structNestingLevel;
+}
+
+void TParseContext::arrayObjectCheck(const TSourceLoc& loc, const TType& type, const char* op)
+{
+    // Some versions don't allow comparing arrays or structures containing arrays
+    if (type.containsArray()) {
+        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, op);
+        profileRequires(loc, EEsProfile, 300, nullptr, op);
+    }
+}
+
+void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const char* op)
+{
+    if (containsFieldWithBasicType(type, EbtSampler))
+        error(loc, "can't use with samplers or structs containing samplers", op, "");
+}
+
+void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
+{
+    if (type.containsSpecializationSize())
+        error(loc, "can't use with types containing arrays sized with a specialization constant", op, "");
+}
+
+void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publicType)
+{
+    const TTypeList& typeList = *publicType.userDef->getStruct();
+
+    // fix and check for member storage qualifiers and types that don't belong within a structure
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        const TSourceLoc& memberLoc = typeList[member].loc;
+        if (memberQualifier.isAuxiliary() ||
+            memberQualifier.isInterpolation() ||
+            (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal))
+            error(memberLoc, "cannot use storage or interpolation qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
+        if (memberQualifier.isMemory())
+            error(memberLoc, "cannot use memory qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
+        if (memberQualifier.hasLayout()) {
+            error(memberLoc, "cannot use layout qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
+            memberQualifier.clearLayout();
+        }
+        if (memberQualifier.invariant)
+            error(memberLoc, "cannot use invariant qualifier on structure members", typeList[member].type->getFieldName().c_str(), "");
+    }
+}
+
+//
+// See if this loop satisfies the limitations for ES 2.0 (version 100) for loops in Appendex A:
+//
+// "The loop index has type int or float.
+//
+// "The for statement has the form:
+//     for ( init-declaration ; condition ; expression )
+//     init-declaration has the form: type-specifier identifier = constant-expression
+//     condition has the form:  loop-index relational_operator constant-expression
+//         where relational_operator is one of: > >= < <= == or !=
+//     expression [sic] has one of the following forms:
+//         loop-index++
+//         loop-index--
+//         loop-index += constant-expression
+//         loop-index -= constant-expression
+//
+// The body is handled in an AST traversal.
+//
+void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, TIntermLoop* loop)
+{
+    // loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration
+    bool badInit = false;
+    if (! init || ! init->getAsAggregate() || init->getAsAggregate()->getSequence().size() != 1)
+        badInit = true;
+    TIntermBinary* binaryInit = 0;
+    if (! badInit) {
+        // get the declaration assignment
+        binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode();
+        if (! binaryInit)
+            badInit = true;
+    }
+    if (badInit) {
+        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // loop index must be type int or float
+    if (! binaryInit->getType().isScalar() || (binaryInit->getBasicType() != EbtInt && binaryInit->getBasicType() != EbtFloat)) {
+        error(loc, "inductive loop requires a scalar 'int' or 'float' loop index", "limitations", "");
+        return;
+    }
+
+    // init is the form "loop-index = constant"
+    if (binaryInit->getOp() != EOpAssign || ! binaryInit->getLeft()->getAsSymbolNode() || ! binaryInit->getRight()->getAsConstantUnion()) {
+        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // get the unique id of the loop index
+    int loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId();
+    inductiveLoopIds.insert(loopIndex);
+
+    // condition's form must be "loop-index relational-operator constant-expression"
+    bool badCond = ! loop->getTest();
+    if (! badCond) {
+        TIntermBinary* binaryCond = loop->getTest()->getAsBinaryNode();
+        badCond = ! binaryCond;
+        if (! badCond) {
+            switch (binaryCond->getOp()) {
+            case EOpGreaterThan:
+            case EOpGreaterThanEqual:
+            case EOpLessThan:
+            case EOpLessThanEqual:
+            case EOpEqual:
+            case EOpNotEqual:
+                break;
+            default:
+                badCond = true;
+            }
+        }
+        if (binaryCond && (! binaryCond->getLeft()->getAsSymbolNode() ||
+                           binaryCond->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
+                           ! binaryCond->getRight()->getAsConstantUnion()))
+            badCond = true;
+    }
+    if (badCond) {
+        error(loc, "inductive-loop condition requires the form \"loop-index <comparison-op> constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // loop-index++
+    // loop-index--
+    // loop-index += constant-expression
+    // loop-index -= constant-expression
+    bool badTerminal = ! loop->getTerminal();
+    if (! badTerminal) {
+        TIntermUnary* unaryTerminal = loop->getTerminal()->getAsUnaryNode();
+        TIntermBinary* binaryTerminal = loop->getTerminal()->getAsBinaryNode();
+        if (unaryTerminal || binaryTerminal) {
+            switch(loop->getTerminal()->getAsOperator()->getOp()) {
+            case EOpPostDecrement:
+            case EOpPostIncrement:
+            case EOpAddAssign:
+            case EOpSubAssign:
+                break;
+            default:
+                badTerminal = true;
+            }
+        } else
+            badTerminal = true;
+        if (binaryTerminal && (! binaryTerminal->getLeft()->getAsSymbolNode() ||
+                               binaryTerminal->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
+                               ! binaryTerminal->getRight()->getAsConstantUnion()))
+            badTerminal = true;
+        if (unaryTerminal && (! unaryTerminal->getOperand()->getAsSymbolNode() ||
+                              unaryTerminal->getOperand()->getAsSymbolNode()->getId() != loopIndex))
+            badTerminal = true;
+    }
+    if (badTerminal) {
+        error(loc, "inductive-loop termination requires the form \"loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // the body
+    inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
+}
+
+// Do limit checks for built-in arrays.
+void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identifier, int size)
+{
+    if (identifier.compare("gl_TexCoord") == 0)
+        limitCheck(loc, size, "gl_MaxTextureCoords", "gl_TexCoord array size");
+    else if (identifier.compare("gl_ClipDistance") == 0)
+        limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistance array size");
+    else if (identifier.compare("gl_CullDistance") == 0)
+        limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistance array size");
+}
+
+// See if the provided value is less than or equal to the symbol indicated by limit,
+// which should be a constant in the symbol table.
+void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* limit, const char* feature)
+{
+    TSymbol* symbol = symbolTable.find(limit);
+    assert(symbol->getAsVariable());
+    const TConstUnionArray& constArray = symbol->getAsVariable()->getConstArray();
+    assert(! constArray.empty());
+    if (value > constArray[0].getIConst())
+        error(loc, "must be less than or equal to", feature, "%s (%d)", limit, constArray[0].getIConst());
+}
+
+//
+// Do any additional error checking, etc., once we know the parsing is done.
+//
+void TParseContext::finish()
+{
+    TParseContextBase::finish();
+
+    if (parsingBuiltins)
+        return;
+
+    // Check on array indexes for ES 2.0 (version 100) limitations.
+    for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
+        constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
+
+    // Check for stages that are enabled by extension.
+    // Can't do this at the beginning, it is chicken and egg to add a stage by
+    // extension.
+    // Stage-specific features were correctly tested for already, this is just
+    // about the stage itself.
+    switch (language) {
+    case EShLangGeometry:
+        if (profile == EEsProfile && version == 310)
+            requireExtensions(getCurrentLoc(), Num_AEP_geometry_shader, AEP_geometry_shader, "geometry shaders");
+        break;
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        if (profile == EEsProfile && version == 310)
+            requireExtensions(getCurrentLoc(), Num_AEP_tessellation_shader, AEP_tessellation_shader, "tessellation shaders");
+        else if (profile != EEsProfile && version < 400)
+            requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_tessellation_shader, "tessellation shaders");
+        break;
+    case EShLangCompute:
+        if (profile != EEsProfile && version < 430)
+            requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_compute_shader, "compute shaders");
+        break;
+    default:
+        break;
+    }
+}
+
+//
+// Layout qualifier stuff.
+//
+
+// Put the id's layout qualification into the public type, for qualifiers not having a number set.
+// This is before we know any type information for error checking.
+void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id)
+{
+    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
+
+    if (id == TQualifier::getLayoutMatrixString(ElmColumnMajor)) {
+        publicType.qualifier.layoutMatrix = ElmColumnMajor;
+        return;
+    }
+    if (id == TQualifier::getLayoutMatrixString(ElmRowMajor)) {
+        publicType.qualifier.layoutMatrix = ElmRowMajor;
+        return;
+    }
+    if (id == TQualifier::getLayoutPackingString(ElpPacked)) {
+        if (spvVersion.spv != 0)
+            spvRemoved(loc, "packed");
+        publicType.qualifier.layoutPacking = ElpPacked;
+        return;
+    }
+    if (id == TQualifier::getLayoutPackingString(ElpShared)) {
+        if (spvVersion.spv != 0)
+            spvRemoved(loc, "shared");
+        publicType.qualifier.layoutPacking = ElpShared;
+        return;
+    }
+    if (id == TQualifier::getLayoutPackingString(ElpStd140)) {
+        publicType.qualifier.layoutPacking = ElpStd140;
+        return;
+    }
+    if (id == TQualifier::getLayoutPackingString(ElpStd430)) {
+        requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "std430");
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, "std430");
+        profileRequires(loc, EEsProfile, 310, nullptr, "std430");
+        publicType.qualifier.layoutPacking = ElpStd430;
+        return;
+    }
+    // TODO: compile-time performance: may need to stop doing linear searches
+    for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) {
+        if (id == TQualifier::getLayoutFormatString(format)) {
+            if ((format > ElfEsFloatGuard && format < ElfFloatGuard) ||
+                (format > ElfEsIntGuard && format < ElfIntGuard) ||
+                (format > ElfEsUintGuard && format < ElfCount))
+                requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "image load-store format");
+            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_ARB_shader_image_load_store, "image load store");
+            profileRequires(loc, EEsProfile, 310, E_GL_ARB_shader_image_load_store, "image load store");
+            publicType.qualifier.layoutFormat = format;
+            return;
+        }
+    }
+    if (id == "push_constant") {
+        requireVulkan(loc, "push_constant");
+        publicType.qualifier.layoutPushConstant = true;
+        return;
+    }
+    if (language == EShLangGeometry || language == EShLangTessEvaluation) {
+        if (id == TQualifier::getGeometryString(ElgTriangles)) {
+            publicType.shaderQualifiers.geometry = ElgTriangles;
+            return;
+        }
+        if (language == EShLangGeometry) {
+            if (id == TQualifier::getGeometryString(ElgPoints)) {
+                publicType.shaderQualifiers.geometry = ElgPoints;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgLineStrip)) {
+                publicType.shaderQualifiers.geometry = ElgLineStrip;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgLines)) {
+                publicType.shaderQualifiers.geometry = ElgLines;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) {
+                publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) {
+                publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgTriangleStrip)) {
+                publicType.shaderQualifiers.geometry = ElgTriangleStrip;
+                return;
+            }
+#ifdef NV_EXTENSIONS
+            if (id == "passthrough") {
+               requireExtensions(loc, 1, &E_SPV_NV_geometry_shader_passthrough, "geometry shader passthrough");
+               publicType.qualifier.layoutPassthrough = true;
+               intermediate.setGeoPassthroughEXT();
+               return;
+            }
+#endif
+        } else {
+            assert(language == EShLangTessEvaluation);
+
+            // input primitive
+            if (id == TQualifier::getGeometryString(ElgTriangles)) {
+                publicType.shaderQualifiers.geometry = ElgTriangles;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgQuads)) {
+                publicType.shaderQualifiers.geometry = ElgQuads;
+                return;
+            }
+            if (id == TQualifier::getGeometryString(ElgIsolines)) {
+                publicType.shaderQualifiers.geometry = ElgIsolines;
+                return;
+            }
+
+            // vertex spacing
+            if (id == TQualifier::getVertexSpacingString(EvsEqual)) {
+                publicType.shaderQualifiers.spacing = EvsEqual;
+                return;
+            }
+            if (id == TQualifier::getVertexSpacingString(EvsFractionalEven)) {
+                publicType.shaderQualifiers.spacing = EvsFractionalEven;
+                return;
+            }
+            if (id == TQualifier::getVertexSpacingString(EvsFractionalOdd)) {
+                publicType.shaderQualifiers.spacing = EvsFractionalOdd;
+                return;
+            }
+
+            // triangle order
+            if (id == TQualifier::getVertexOrderString(EvoCw)) {
+                publicType.shaderQualifiers.order = EvoCw;
+                return;
+            }
+            if (id == TQualifier::getVertexOrderString(EvoCcw)) {
+                publicType.shaderQualifiers.order = EvoCcw;
+                return;
+            }
+
+            // point mode
+            if (id == "point_mode") {
+                publicType.shaderQualifiers.pointMode = true;
+                return;
+            }
+        }
+    }
+    if (language == EShLangFragment) {
+        if (id == "origin_upper_left") {
+            requireProfile(loc, ECoreProfile | ECompatibilityProfile, "origin_upper_left");
+            publicType.shaderQualifiers.originUpperLeft = true;
+            return;
+        }
+        if (id == "pixel_center_integer") {
+            requireProfile(loc, ECoreProfile | ECompatibilityProfile, "pixel_center_integer");
+            publicType.shaderQualifiers.pixelCenterInteger = true;
+            return;
+        }
+        if (id == "early_fragment_tests") {
+            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_ARB_shader_image_load_store, "early_fragment_tests");
+            profileRequires(loc, EEsProfile, 310, nullptr, "early_fragment_tests");
+            publicType.shaderQualifiers.earlyFragmentTests = true;
+            return;
+        }
+        for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) {
+            if (id == TQualifier::getLayoutDepthString(depth)) {
+                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier");
+                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, nullptr, "depth layout qualifier");
+                publicType.shaderQualifiers.layoutDepth = depth;
+                return;
+            }
+        }
+        if (id.compare(0, 13, "blend_support") == 0) {
+            bool found = false;
+            for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
+                if (id == TQualifier::getBlendEquationString(be)) {
+                    requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation");
+                    intermediate.addBlendEquation(be);
+                    publicType.shaderQualifiers.blendEquation = true;
+                    found = true;
+                    break;
+                }
+            }
+            if (! found)
+                error(loc, "unknown blend equation", "blend_support", "");
+            return;
+        }
+#ifdef NV_EXTENSIONS
+        if (id == "override_coverage") {
+            requireExtensions(loc, 1, &E_GL_NV_sample_mask_override_coverage, "sample mask override coverage");
+            publicType.shaderQualifiers.layoutOverrideCoverage = true;
+            return;
+        }
+#endif
+    }
+#ifdef NV_EXTENSIONS
+    if (language == EShLangVertex ||
+        language == EShLangTessControl ||
+        language == EShLangTessEvaluation ||
+        language == EShLangGeometry ) {
+        if (id == "viewport_relative") {
+            requireExtensions(loc, 1, &E_GL_NV_viewport_array2, "view port array2");
+            publicType.qualifier.layoutViewportRelative = true;
+            return;
+        }
+    }
+#endif
+    error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
+}
+
+// Put the id's layout qualifier value into the public type, for qualifiers having a number set.
+// This is before we know any type information for error checking.
+void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id, const TIntermTyped* node)
+{
+    const char* feature = "layout-id value";
+    const char* nonLiteralFeature = "non-literal layout-id value";
+
+    integerCheck(node, feature);
+    const TIntermConstantUnion* constUnion = node->getAsConstantUnion();
+    int value;
+    if (constUnion) {
+        value = constUnion->getConstArray()[0].getIConst();
+        if (! constUnion->isLiteral()) {
+            requireProfile(loc, ECoreProfile | ECompatibilityProfile, nonLiteralFeature);
+            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, nonLiteralFeature);
+        }
+    } else {
+        // grammar should have give out the error message
+        value = 0;
+    }
+
+    if (value < 0) {
+        error(loc, "cannot be negative", feature, "");
+        return;
+    }
+
+    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
+
+    if (id == "offset") {
+        // "offset" can be for either
+        //  - uniform offsets
+        //  - atomic_uint offsets
+        const char* feature = "offset";
+        requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
+        const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters };
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature);
+        profileRequires(loc, EEsProfile, 310, nullptr, feature);
+        publicType.qualifier.layoutOffset = value;
+        return;
+    } else if (id == "align") {
+        const char* feature = "uniform buffer-member align";
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
+        // "The specified alignment must be a power of 2, or a compile-time error results."
+        if (! IsPow2(value))
+            error(loc, "must be a power of 2", "align", "");
+        else
+            publicType.qualifier.layoutAlign = value;
+        return;
+    } else if (id == "location") {
+        profileRequires(loc, EEsProfile, 300, nullptr, "location");
+        const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+        profileRequires(loc, ~EEsProfile, 330, 2, exts, "location");
+        if ((unsigned int)value >= TQualifier::layoutLocationEnd)
+            error(loc, "location is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutLocation = value;
+        return;
+    } else if (id == "set") {
+        if ((unsigned int)value >= TQualifier::layoutSetEnd)
+            error(loc, "set is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutSet = value;
+        if (value != 0)
+            requireVulkan(loc, "descriptor set");
+        return;
+    } else if (id == "binding") {
+        profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, "binding");
+        profileRequires(loc, EEsProfile, 310, nullptr, "binding");
+        if ((unsigned int)value >= TQualifier::layoutBindingEnd)
+            error(loc, "binding is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutBinding = value;
+        return;
+    } else if (id == "component") {
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, "component");
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "component");
+        if ((unsigned)value >= TQualifier::layoutComponentEnd)
+            error(loc, "component is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutComponent = value;
+        return;
+    } else if (id.compare(0, 4, "xfb_") == 0) {
+        // "Any shader making any static use (after preprocessing) of any of these
+        // *xfb_* qualifiers will cause the shader to be in a transform feedback
+        // capturing mode and hence responsible for describing the transform feedback
+        // setup."
+        intermediate.setXfbMode();
+        const char* feature = "transform feedback qualifier";
+        requireStage(loc, (EShLanguageMask)(EShLangVertexMask | EShLangGeometryMask | EShLangTessControlMask | EShLangTessEvaluationMask), feature);
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
+        if (id == "xfb_buffer") {
+            // "It is a compile-time error to specify an *xfb_buffer* that is greater than
+            // the implementation-dependent constant gl_MaxTransformFeedbackBuffers."
+            if (value >= resources.maxTransformFeedbackBuffers)
+                error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", resources.maxTransformFeedbackBuffers);
+            if (value >= (int)TQualifier::layoutXfbBufferEnd)
+                error(loc, "buffer is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbBufferEnd-1);
+            else
+                publicType.qualifier.layoutXfbBuffer = value;
+            return;
+        } else if (id == "xfb_offset") {
+            if (value >= (int)TQualifier::layoutXfbOffsetEnd)
+                error(loc, "offset is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbOffsetEnd-1);
+            else
+                publicType.qualifier.layoutXfbOffset = value;
+            return;
+        } else if (id == "xfb_stride") {
+            // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
+            // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
+            if (value > 4 * resources.maxTransformFeedbackInterleavedComponents)
+                error(loc, "1/4 stride is too large:", id.c_str(), "gl_MaxTransformFeedbackInterleavedComponents is %d", resources.maxTransformFeedbackInterleavedComponents);
+            else if (value >= (int)TQualifier::layoutXfbStrideEnd)
+                error(loc, "stride is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbStrideEnd-1);
+            if (value < (int)TQualifier::layoutXfbStrideEnd)
+                publicType.qualifier.layoutXfbStride = value;
+            return;
+        }
+    }
+
+    if (id == "input_attachment_index") {
+        requireVulkan(loc, "input_attachment_index");
+        if (value >= (int)TQualifier::layoutAttachmentEnd)
+            error(loc, "attachment index is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutAttachment = value;
+        return;
+    }
+    if (id == "constant_id") {
+        requireSpv(loc, "constant_id");
+        if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
+            error(loc, "specialization-constant id is too large", id.c_str(), "");
+        } else {
+            publicType.qualifier.layoutSpecConstantId = value;
+            publicType.qualifier.specConstant = true;
+            if (! intermediate.addUsedConstantId(value))
+                error(loc, "specialization-constant id already used", id.c_str(), "");
+        }
+        return;
+    }
+
+#if NV_EXTENSIONS
+    if (language == EShLangVertex ||
+        language == EShLangTessControl ||
+        language == EShLangTessEvaluation ||
+        language == EShLangGeometry) {
+        if (id == "secondary_view_offset") {
+            requireExtensions(loc, 1, &E_GL_NV_stereo_view_rendering, "stereo view rendering");
+            publicType.qualifier.layoutSecondaryViewportRelativeOffset = value;
+            return;
+        }
+    }
+#endif
+
+    switch (language) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+        if (id == "vertices") {
+            if (value == 0)
+                error(loc, "must be greater than 0", "vertices", "");
+            else
+                publicType.shaderQualifiers.vertices = value;
+            return;
+        }
+        break;
+
+    case EShLangTessEvaluation:
+        break;
+
+    case EShLangGeometry:
+        if (id == "invocations") {
+            profileRequires(loc, ECompatibilityProfile | ECoreProfile, 400, nullptr, "invocations");
+            if (value == 0)
+                error(loc, "must be at least 1", "invocations", "");
+            else
+                publicType.shaderQualifiers.invocations = value;
+            return;
+        }
+        if (id == "max_vertices") {
+            publicType.shaderQualifiers.vertices = value;
+            if (value > resources.maxGeometryOutputVertices)
+                error(loc, "too large, must be less than gl_MaxGeometryOutputVertices", "max_vertices", "");
+            return;
+        }
+        if (id == "stream") {
+            requireProfile(loc, ~EEsProfile, "selecting output stream");
+            publicType.qualifier.layoutStream = value;
+            if (value > 0)
+                intermediate.setMultiStream();
+            return;
+        }
+        break;
+
+    case EShLangFragment:
+        if (id == "index") {
+            requireProfile(loc, ECompatibilityProfile | ECoreProfile, "index layout qualifier on fragment output");
+            const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+            profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output");
+
+            // "It is also a compile-time error if a fragment shader sets a layout index to less than 0 or greater than 1."
+            if (value < 0 || value > 1) {
+                value = 0;
+                error(loc, "value must be 0 or 1", "index", "");
+            }
+
+            publicType.qualifier.layoutIndex = value;
+            return;
+        }
+        break;
+
+    case EShLangCompute:
+        if (id.compare(0, 11, "local_size_") == 0) {
+            profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize");
+            profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize");
+            if (id == "local_size_x") {
+                publicType.shaderQualifiers.localSize[0] = value;
+                return;
+            }
+            if (id == "local_size_y") {
+                publicType.shaderQualifiers.localSize[1] = value;
+                return;
+            }
+            if (id == "local_size_z") {
+                publicType.shaderQualifiers.localSize[2] = value;
+                return;
+            }
+            if (spvVersion.spv != 0) {
+                if (id == "local_size_x_id") {
+                    publicType.shaderQualifiers.localSizeSpecId[0] = value;
+                    return;
+                }
+                if (id == "local_size_y_id") {
+                    publicType.shaderQualifiers.localSizeSpecId[1] = value;
+                    return;
+                }
+                if (id == "local_size_z_id") {
+                    publicType.shaderQualifiers.localSizeSpecId[2] = value;
+                    return;
+                }
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    error(loc, "there is no such layout identifier for this stage taking an assigned value", id.c_str(), "");
+}
+
+// Merge any layout qualifier information from src into dst, leaving everything else in dst alone
+//
+// "More than one layout qualifier may appear in a single declaration.
+// Additionally, the same layout-qualifier-name can occur multiple times
+// within a layout qualifier or across multiple layout qualifiers in the
+// same declaration. When the same layout-qualifier-name occurs
+// multiple times, in a single declaration, the last occurrence overrides
+// the former occurrence(s).  Further, if such a layout-qualifier-name
+// will effect subsequent declarations or other observable behavior, it
+// is only the last occurrence that will have any effect, behaving as if
+// the earlier occurrence(s) within the declaration are not present.
+// This is also true for overriding layout-qualifier-names, where one
+// overrides the other (e.g., row_major vs. column_major); only the last
+// occurrence has any effect."
+//
+void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifier& src, bool inheritOnly)
+{
+    if (src.hasMatrix())
+        dst.layoutMatrix = src.layoutMatrix;
+    if (src.hasPacking())
+        dst.layoutPacking = src.layoutPacking;
+
+    if (src.hasStream())
+        dst.layoutStream = src.layoutStream;
+
+    if (src.hasFormat())
+        dst.layoutFormat = src.layoutFormat;
+
+    if (src.hasXfbBuffer())
+        dst.layoutXfbBuffer = src.layoutXfbBuffer;
+
+    if (src.hasAlign())
+        dst.layoutAlign = src.layoutAlign;
+
+    if (! inheritOnly) {
+        if (src.hasLocation())
+            dst.layoutLocation = src.layoutLocation;
+        if (src.hasComponent())
+            dst.layoutComponent = src.layoutComponent;
+        if (src.hasIndex())
+            dst.layoutIndex = src.layoutIndex;
+
+        if (src.hasOffset())
+            dst.layoutOffset = src.layoutOffset;
+
+        if (src.hasSet())
+            dst.layoutSet = src.layoutSet;
+        if (src.layoutBinding != TQualifier::layoutBindingEnd)
+            dst.layoutBinding = src.layoutBinding;
+
+        if (src.hasXfbStride())
+            dst.layoutXfbStride = src.layoutXfbStride;
+        if (src.hasXfbOffset())
+            dst.layoutXfbOffset = src.layoutXfbOffset;
+        if (src.hasAttachment())
+            dst.layoutAttachment = src.layoutAttachment;
+        if (src.hasSpecConstantId())
+            dst.layoutSpecConstantId = src.layoutSpecConstantId;
+
+        if (src.layoutPushConstant)
+            dst.layoutPushConstant = true;
+
+#ifdef NV_EXTENSIONS
+        if (src.layoutPassthrough)
+            dst.layoutPassthrough = true;
+        if (src.layoutViewportRelative)
+            dst.layoutViewportRelative = true;
+        if (src.layoutSecondaryViewportRelativeOffset != -2048)
+            dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset;
+#endif
+    }
+}
+
+// Do error layout error checking given a full variable/block declaration.
+void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symbol)
+{
+    const TType& type = symbol.getType();
+    const TQualifier& qualifier = type.getQualifier();
+
+    // first, cross check WRT to just the type
+    layoutTypeCheck(loc, type);
+
+    // now, any remaining error checking based on the object itself
+
+    if (qualifier.hasAnyLocation()) {
+        switch (qualifier.storage) {
+        case EvqUniform:
+        case EvqBuffer:
+            if (symbol.getAsVariable() == nullptr)
+                error(loc, "can only be used on variable declaration", "location", "");
+            break;
+        default:
+            break;
+        }
+    }
+
+    // Check packing and matrix
+    if (qualifier.hasUniformLayout()) {
+        switch (qualifier.storage) {
+        case EvqUniform:
+        case EvqBuffer:
+            if (type.getBasicType() != EbtBlock) {
+                if (qualifier.hasMatrix())
+                    error(loc, "cannot specify matrix layout on a variable declaration", "layout", "");
+                if (qualifier.hasPacking())
+                    error(loc, "cannot specify packing on a variable declaration", "layout", "");
+                // "The offset qualifier can only be used on block members of blocks..."
+                if (qualifier.hasOffset() && type.getBasicType() != EbtAtomicUint)
+                    error(loc, "cannot specify on a variable declaration", "offset", "");
+                // "The align qualifier can only be used on blocks or block members..."
+                if (qualifier.hasAlign())
+                    error(loc, "cannot specify on a variable declaration", "align", "");
+                if (qualifier.layoutPushConstant)
+                    error(loc, "can only specify on a uniform block", "push_constant", "");
+            }
+            break;
+        default:
+            // these were already filtered by layoutTypeCheck() (or its callees)
+            break;
+        }
+    }
+}
+
+// Do layout error checking with respect to a type.
+void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
+{
+    const TQualifier& qualifier = type.getQualifier();
+
+    // first, intra-layout qualifier-only error checking
+    layoutQualifierCheck(loc, qualifier);
+
+    // now, error checking combining type and qualifier
+
+    if (qualifier.hasAnyLocation()) {
+        if (qualifier.hasLocation()) {
+            if (qualifier.storage == EvqVaryingOut && language == EShLangFragment) {
+                if (qualifier.layoutLocation >= (unsigned int)resources.maxDrawBuffers)
+                    error(loc, "too large for fragment output", "location", "");
+            }
+        }
+        if (qualifier.hasComponent()) {
+            // "It is a compile-time error if this sequence of components gets larger than 3."
+            if (qualifier.layoutComponent + type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1) > 4)
+                error(loc, "type overflows the available 4 components", "component", "");
+
+            // "It is a compile-time error to apply the component qualifier to a matrix, a structure, a block, or an array containing any of these."
+            if (type.isMatrix() || type.getBasicType() == EbtBlock || type.getBasicType() == EbtStruct)
+                error(loc, "cannot apply to a matrix, structure, or block", "component", "");
+
+            // " It is a compile-time error to use component 1 or 3 as the beginning of a double or dvec2."
+            if (type.getBasicType() == EbtDouble)
+                if (qualifier.layoutComponent & 1)
+                    error(loc, "doubles cannot start on an odd-numbered component", "component", "");
+        }
+
+        switch (qualifier.storage) {
+        case EvqVaryingIn:
+        case EvqVaryingOut:
+            if (type.getBasicType() == EbtBlock)
+                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "location qualifier on in/out block");
+            break;
+        case EvqUniform:
+        case EvqBuffer:
+            break;
+        default:
+            error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
+            break;
+        }
+
+        bool typeCollision;
+        int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision);
+        if (repeated >= 0 && ! typeCollision)
+            error(loc, "overlapping use of location", "location", "%d", repeated);
+        // "fragment-shader outputs ... if two variables are placed within the same
+        // location, they must have the same underlying type (floating-point or integer)"
+        if (typeCollision && language == EShLangFragment && qualifier.isPipeOutput())
+            error(loc, "fragment outputs sharing the same location must be the same basic type", "location", "%d", repeated);
+    }
+
+    if (qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()) {
+        int repeated = intermediate.addXfbBufferOffset(type);
+        if (repeated >= 0)
+            error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer);
+
+        // "The offset must be a multiple of the size of the first component of the first
+        // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate
+        // containing a double, the offset must also be a multiple of 8..."
+        if (type.containsBasicType(EbtDouble) && ! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8))
+            error(loc, "type contains double; xfb_offset must be a multiple of 8", "xfb_offset", "");
+#ifdef AMD_EXTENSIONS
+        // ..., if applied to an aggregate containing a float16_t, the offset must also be a multiple of 2..."
+        else if (type.containsBasicType(EbtFloat16) && !IsMultipleOfPow2(qualifier.layoutXfbOffset, 2))
+            error(loc, "type contains half float; xfb_offset must be a multiple of 2", "xfb_offset", "");
+#endif
+        else if (! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
+            error(loc, "must be a multiple of size of first component", "xfb_offset", "");
+    }
+
+    if (qualifier.hasXfbStride() && qualifier.hasXfbBuffer()) {
+        if (! intermediate.setXfbBufferStride(qualifier.layoutXfbBuffer, qualifier.layoutXfbStride))
+            error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
+    }
+
+    if (qualifier.hasBinding()) {
+        // Binding checking, from the spec:
+        //
+        // "If the binding point for any uniform or shader storage block instance is less than zero, or greater than or
+        // equal to the implementation-dependent maximum number of uniform buffer bindings, a compile-time
+        // error will occur. When the binding identifier is used with a uniform or shader storage block instanced as
+        // an array of size N, all elements of the array from binding through binding + N - 1 must be within this
+        // range."
+        //
+        if (! type.isOpaque() && type.getBasicType() != EbtBlock)
+            error(loc, "requires block, or sampler/image, or atomic-counter type", "binding", "");
+        if (type.getBasicType() == EbtSampler) {
+            int lastBinding = qualifier.layoutBinding;
+            if (type.isArray()) {
+                if (type.isImplicitlySizedArray()) {
+                    lastBinding += 1;
+                    warn(loc, "assuming array size of one for compile-time checking of binding numbers for implicitly-sized array", "[]", "");
+                } else
+                    lastBinding += type.getCumulativeArraySize();
+            }
+            if (lastBinding >= resources.maxCombinedTextureImageUnits)
+                error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
+        }
+        if (type.getBasicType() == EbtAtomicUint) {
+            if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
+                error(loc, "atomic_uint binding is too large; see gl_MaxAtomicCounterBindings", "binding", "");
+                return;
+            }
+        }
+    }
+
+    // atomic_uint
+    if (type.getBasicType() == EbtAtomicUint) {
+        if (! type.getQualifier().hasBinding())
+            error(loc, "layout(binding=X) is required", "atomic_uint", "");
+    }
+
+    // "The offset qualifier can only be used on block members of blocks..."
+    if (qualifier.hasOffset()) {
+        if (type.getBasicType() == EbtBlock)
+            error(loc, "only applies to block members, not blocks", "offset", "");
+    }
+
+    // Image format
+    if (qualifier.hasFormat()) {
+        if (! type.isImage())
+            error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+        else {
+            if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard)
+                error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+            if (type.getSampler().type == EbtInt && (qualifier.layoutFormat < ElfFloatGuard || qualifier.layoutFormat > ElfIntGuard))
+                error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+            if (type.getSampler().type == EbtUint && qualifier.layoutFormat < ElfIntGuard)
+                error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+
+            if (profile == EEsProfile) {
+                // "Except for image variables qualified with the format qualifiers r32f, r32i, and r32ui, image variables must
+                // specify either memory qualifier readonly or the memory qualifier writeonly."
+                if (! (qualifier.layoutFormat == ElfR32f || qualifier.layoutFormat == ElfR32i || qualifier.layoutFormat == ElfR32ui)) {
+                    if (! qualifier.readonly && ! qualifier.writeonly)
+                        error(loc, "format requires readonly or writeonly memory qualifier", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+                }
+            }
+        }
+    } else if (type.isImage() && ! qualifier.writeonly)
+        error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
+
+    if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
+        error(loc, "can only be used with a block", "push_constant", "");
+
+    // input attachment
+    if (type.isSubpass()) {
+        if (! qualifier.hasAttachment())
+            error(loc, "requires an input_attachment_index layout qualifier", "subpass", "");
+    } else {
+        if (qualifier.hasAttachment())
+            error(loc, "can only be used with a subpass", "input_attachment_index", "");
+    }
+
+    // specialization-constant id
+    if (qualifier.hasSpecConstantId()) {
+        if (type.getQualifier().storage != EvqConst)
+            error(loc, "can only be applied to 'const'-qualified scalar", "constant_id", "");
+        if (! type.isScalar())
+            error(loc, "can only be applied to a scalar", "constant_id", "");
+        switch (type.getBasicType())
+        {
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+        case EbtBool:
+        case EbtFloat:
+        case EbtDouble:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            break;
+        default:
+            error(loc, "cannot be applied to this type", "constant_id", "");
+            break;
+        }
+    }
+}
+
+// Do layout error checking that can be done within a layout qualifier proper, not needing to know
+// if there are blocks, atomic counters, variables, etc.
+void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier)
+{
+    if (qualifier.storage == EvqShared && qualifier.hasLayout())
+        error(loc, "cannot apply layout qualifiers to a shared variable", "shared", "");
+
+    // "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
+    if (qualifier.hasComponent() && ! qualifier.hasLocation())
+        error(loc, "must specify 'location' to use 'component'", "component", "");
+
+    if (qualifier.hasAnyLocation()) {
+
+        // "As with input layout qualifiers, all shaders except compute shaders
+        // allow *location* layout qualifiers on output variable declarations,
+        // output block declarations, and output block member declarations."
+
+        switch (qualifier.storage) {
+        case EvqVaryingIn:
+        {
+            const char* feature = "location qualifier on input";
+            if (profile == EEsProfile && version < 310)
+                requireStage(loc, EShLangVertex, feature);
+            else
+                requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
+            if (language == EShLangVertex) {
+                const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+                profileRequires(loc, ~EEsProfile, 330, 2, exts, feature);
+                profileRequires(loc, EEsProfile, 300, nullptr, feature);
+            } else {
+                profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
+                profileRequires(loc, EEsProfile, 310, nullptr, feature);
+            }
+            break;
+        }
+        case EvqVaryingOut:
+        {
+            const char* feature = "location qualifier on output";
+            if (profile == EEsProfile && version < 310)
+                requireStage(loc, EShLangFragment, feature);
+            else
+                requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
+            if (language == EShLangFragment) {
+                const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+                profileRequires(loc, ~EEsProfile, 330, 2, exts, feature);
+                profileRequires(loc, EEsProfile, 300, nullptr, feature);
+            } else {
+                profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
+                profileRequires(loc, EEsProfile, 310, nullptr, feature);
+            }
+            break;
+        }
+        case EvqUniform:
+        case EvqBuffer:
+        {
+            const char* feature = "location qualifier on uniform or buffer";
+            requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
+            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature);
+            profileRequires(loc, EEsProfile, 310, nullptr, feature);
+            break;
+        }
+        default:
+            break;
+        }
+        if (qualifier.hasIndex()) {
+            if (qualifier.storage != EvqVaryingOut)
+                error(loc, "can only be used on an output", "index", "");
+            if (! qualifier.hasLocation())
+                error(loc, "can only be used with an explicit location", "index", "");
+        }
+    }
+
+    if (qualifier.hasBinding()) {
+        if (! qualifier.isUniformOrBuffer())
+            error(loc, "requires uniform or buffer storage qualifier", "binding", "");
+    }
+    if (qualifier.hasStream()) {
+        if (qualifier.storage != EvqVaryingOut)
+            error(loc, "can only be used on an output", "stream", "");
+    }
+    if (qualifier.hasXfb()) {
+        if (qualifier.storage != EvqVaryingOut)
+            error(loc, "can only be used on an output", "xfb layout qualifier", "");
+    }
+    if (qualifier.hasUniformLayout()) {
+        if (! qualifier.isUniformOrBuffer()) {
+            if (qualifier.hasMatrix() || qualifier.hasPacking())
+                error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", "");
+            if (qualifier.hasOffset() || qualifier.hasAlign())
+                error(loc, "offset/align can only be used on a uniform or buffer", "layout", "");
+        }
+    }
+    if (qualifier.layoutPushConstant) {
+        if (qualifier.storage != EvqUniform)
+            error(loc, "can only be used with a uniform", "push_constant", "");
+        if (qualifier.hasSet())
+            error(loc, "cannot be used with push_constant", "set", "");
+    }
+}
+
+// For places that can't have shader-level layout qualifiers
+void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQualifiers& shaderQualifiers)
+{
+    const char* message = "can only apply to a standalone qualifier";
+
+    if (shaderQualifiers.geometry != ElgNone)
+        error(loc, message, TQualifier::getGeometryString(shaderQualifiers.geometry), "");
+    if (shaderQualifiers.invocations != TQualifier::layoutNotSet)
+        error(loc, message, "invocations", "");
+    if (shaderQualifiers.vertices != TQualifier::layoutNotSet) {
+        if (language == EShLangGeometry)
+            error(loc, message, "max_vertices", "");
+        else if (language == EShLangTessControl)
+            error(loc, message, "vertices", "");
+        else
+            assert(0);
+    }
+    for (int i = 0; i < 3; ++i) {
+        if (shaderQualifiers.localSize[i] > 1)
+            error(loc, message, "local_size", "");
+        if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
+            error(loc, message, "local_size id", "");
+    }
+    if (shaderQualifiers.blendEquation)
+        error(loc, message, "blend equation", "");
+    // TBD: correctness: are any of these missing?  pixelCenterInteger, originUpperLeft, spacing, order, pointmode, earlyfragment, depth
+}
+
+// Correct and/or advance an object's offset layout qualifier.
+void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
+{
+    const TQualifier& qualifier = symbol.getType().getQualifier();
+    if (symbol.getType().getBasicType() == EbtAtomicUint) {
+        if (qualifier.hasBinding() && (int)qualifier.layoutBinding < resources.maxAtomicCounterBindings) {
+
+            // Set the offset
+            int offset;
+            if (qualifier.hasOffset())
+                offset = qualifier.layoutOffset;
+            else
+                offset = atomicUintOffsets[qualifier.layoutBinding];
+            symbol.getWritableType().getQualifier().layoutOffset = offset;
+
+            // Check for overlap
+            int numOffsets = 4;
+            if (symbol.getType().isArray()) {
+                if (symbol.getType().isExplicitlySizedArray())
+                    numOffsets *= symbol.getType().getCumulativeArraySize();
+                else {
+                    // TODO: functionality: implicitly-sized atomic_uint arrays.
+                    // We don't know the full size until later.  This might
+                    // be a specification problem, will report to Khronos.  For the
+                    // cases that is not true, the rest of the checking would need
+                    // to be done at link time instead of compile time.
+                    warn(loc, "implicitly sized atomic_uint array treated as having one element for tracking the default offset", "atomic_uint", "");
+                }
+            }
+            int repeated = intermediate.addUsedOffsets(qualifier.layoutBinding, offset, numOffsets);
+            if (repeated >= 0)
+                error(loc, "atomic counters sharing the same offset:", "offset", "%d", repeated);
+
+            // Bump the default offset
+            atomicUintOffsets[qualifier.layoutBinding] = offset + numOffsets;
+        }
+    }
+}
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise nullptr.
+//
+const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
+{
+    const TFunction* function = nullptr;
+
+    if (symbolTable.isFunctionNameVariable(call.getName())) {
+        error(loc, "can't use function syntax on variable", call.getName().c_str(), "");
+        return nullptr;
+    }
+
+    if (profile == EEsProfile || version < 120)
+        function = findFunctionExact(loc, call, builtIn);
+    else if (version < 400)
+        function = findFunction120(loc, call, builtIn);
+    else
+        function = findFunction400(loc, call, builtIn);
+
+    return function;
+}
+
+// Function finding algorithm for ES and desktop 110.
+const TFunction* TParseContext::findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
+{
+    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
+    if (symbol == nullptr) {
+        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
+
+        return nullptr;
+    }
+
+    return symbol->getAsFunction();
+}
+
+// Function finding algorithm for desktop versions 120 through 330.
+const TFunction* TParseContext::findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
+{
+    // first, look for an exact match
+    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
+    if (symbol)
+        return symbol->getAsFunction();
+
+    // exact match not found, look through a list of overloaded functions of the same name
+
+    // "If no exact match is found, then [implicit conversions] will be applied to find a match. Mismatched types
+    // on input parameters (in or inout or default) must have a conversion from the calling argument type to the
+    // formal parameter type. Mismatched types on output parameters (out or inout) must have a conversion
+    // from the formal parameter type to the calling argument type.  When argument conversions are used to find
+    // a match, it is a semantic error if there are multiple ways to apply these conversions to make the call match
+    // more than one function."
+
+    const TFunction* candidate = nullptr;
+    TVector<const TFunction*> candidateList;
+    symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
+
+    for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
+        const TFunction& function = *(*it);
+
+        // to even be a potential match, number of arguments has to match
+        if (call.getParamCount() != function.getParamCount())
+            continue;
+
+        bool possibleMatch = true;
+        for (int i = 0; i < function.getParamCount(); ++i) {
+            // same types is easy
+            if (*function[i].type == *call[i].type)
+                continue;
+
+            // We have a mismatch in type, see if it is implicitly convertible
+
+            if (function[i].type->isArray() || call[i].type->isArray() ||
+                ! function[i].type->sameElementShape(*call[i].type))
+                possibleMatch = false;
+            else {
+                // do direction-specific checks for conversion of basic type
+                if (function[i].type->getQualifier().isParamInput()) {
+                    if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
+                        possibleMatch = false;
+                }
+                if (function[i].type->getQualifier().isParamOutput()) {
+                    if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
+                        possibleMatch = false;
+                }
+            }
+            if (! possibleMatch)
+                break;
+        }
+        if (possibleMatch) {
+            if (candidate) {
+                // our second match, meaning ambiguity
+                error(loc, "ambiguous function signature match: multiple signatures match under implicit type conversion", call.getName().c_str(), "");
+            } else
+                candidate = &function;
+        }
+    }
+
+    if (candidate == nullptr)
+        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
+
+    return candidate;
+}
+
+// Function finding algorithm for desktop version 400 and above.
+//
+// "When function calls are resolved, an exact type match for all the arguments
+// is sought. If an exact match is found, all other functions are ignored, and
+// the exact match is used. If no exact match is found, then the implicit
+// conversions in section 4.1.10 Implicit Conversions will be applied to find
+// a match. Mismatched types on input parameters (in or inout or default) must
+// have a conversion from the calling argument type to the formal parameter type.
+// Mismatched types on output parameters (out or inout) must have a conversion
+// from the formal parameter type to the calling argument type.
+//
+// "If implicit conversions can be used to find more than one matching function,
+// a single best-matching function is sought. To determine a best match, the
+// conversions between calling argument and formal parameter types are compared
+// for each function argument and pair of matching functions. After these
+// comparisons are performed, each pair of matching functions are compared.
+// A function declaration A is considered a better match than function
+// declaration B if
+//
+//  * for at least one function argument, the conversion for that argument in A
+//    is better than the corresponding conversion in B; and
+//  * there is no function argument for which the conversion in B is better than
+//    the corresponding conversion in A.
+//
+// "If a single function declaration is considered a better match than every
+// other matching function declaration, it will be used. Otherwise, a
+// compile-time semantic error for an ambiguous overloaded function call occurs.
+//
+// "To determine whether the conversion for a single argument in one match is
+// better than that for another match, the following rules are applied, in order:
+//
+//  1. An exact match is better than a match involving any implicit conversion.
+//  2. A match involving an implicit conversion from float to double is better
+//     than a match involving any other implicit conversion.
+//  3. A match involving an implicit conversion from either int or uint to float
+//     is better than a match involving an implicit conversion from either int
+//     or uint to double.
+//
+// "If none of the rules above apply to a particular pair of conversions, neither
+// conversion is considered better than the other."
+//
+const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
+{
+    // first, look for an exact match
+    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
+    if (symbol)
+        return symbol->getAsFunction();
+
+    // no exact match, use the generic selector, parameterized by the GLSL rules
+
+    // create list of candidates to send
+    TVector<const TFunction*> candidateList;
+    symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
+
+    // can 'from' convert to 'to'?
+    const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool {
+        if (from == to)
+            return true;
+        if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
+            return false;
+        return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
+    };
+
+    // Is 'to2' a better conversion than 'to1'?
+    // Ties should not be considered as better.
+    // Assumes 'convertible' already said true.
+    const auto better = [](const TType& from, const TType& to1, const TType& to2) -> bool {
+        // 1. exact match
+        if (from == to2)
+            return from != to1;
+        if (from == to1)
+            return false;
+
+        // 2. float -> double is better
+        if (from.getBasicType() == EbtFloat) {
+            if (to2.getBasicType() == EbtDouble && to1.getBasicType() != EbtDouble)
+                return true;
+        }
+
+        // 3. -> float is better than -> double
+        return to2.getBasicType() == EbtFloat && to1.getBasicType() == EbtDouble;
+    };
+
+    // for ambiguity reporting
+    bool tie = false;
+
+    // send to the generic selector
+    const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie);
+
+    if (bestMatch == nullptr)
+        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
+    else if (tie)
+        error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), "");
+
+    return bestMatch;
+}
+
+// When a declaration includes a type, but not a variable name, it can be
+// to establish defaults.
+void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType)
+{
+    if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding() && publicType.qualifier.hasOffset()) {
+        if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
+            error(loc, "atomic_uint binding is too large", "binding", "");
+            return;
+        }
+        atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
+        return;
+    }
+
+    if (publicType.qualifier.hasLayout())
+        warn(loc, "useless application of layout qualifier", "layout", "");
+}
+
+//
+// Do everything necessary to handle a variable (non-block) declaration.
+// Either redeclaring a variable, or making a new one, updating the symbol
+// table, and all error checking.
+//
+// Returns a subtree node that computes an initializer, if needed.
+// Returns nullptr if there is no code to execute for initialization.
+//
+// 'publicType' is the type part of the declaration (to the left)
+// 'arraySizes' is the arrayness tagged on the identifier (to the right)
+//
+TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType, TArraySizes* arraySizes, TIntermTyped* initializer)
+{
+    TType type(publicType);  // shallow copy; 'type' shares the arrayness and structure definition with 'publicType'
+    if (type.isImplicitlySizedArray()) {
+        // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
+        // of different sizes, for this case sharing the shallow copy of arrayness
+        // with the publicType oversubscribes it, so get a deep copy of the arrayness.
+        type.newArraySizes(*publicType.arraySizes);
+    }
+
+    if (voidErrorCheck(loc, identifier, type.getBasicType()))
+        return nullptr;
+
+    if (initializer)
+        rValueErrorCheck(loc, "initializer", initializer);
+    else
+        nonInitConstCheck(loc, identifier, type);
+
+    samplerCheck(loc, type, identifier, initializer);
+    atomicUintCheck(loc, type, identifier);
+    transparentCheck(loc, type, identifier);
+
+    if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
+        error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
+    if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.layoutDepth != EldNone)
+        error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
+
+    // Check for redeclaration of built-ins and/or attempting to declare a reserved name
+    TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers);
+    if (symbol == nullptr)
+        reservedErrorCheck(loc, identifier);
+
+    inheritGlobalDefaults(type.getQualifier());
+
+    // Declare the variable
+    if (arraySizes || type.isArray()) {
+        // Arrayness is potentially coming both from the type and from the
+        // variable: "int[] a[];" or just one or the other.
+        // Merge it all to the type, so all arrayness is part of the type.
+        arrayDimCheck(loc, &type, arraySizes);
+        arrayDimMerge(type, arraySizes);
+
+        // Check that implicit sizing is only where allowed.
+        arrayUnsizedCheck(loc, type.getQualifier(), &type.getArraySizes(), initializer != nullptr, false);
+
+        if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type))
+            declareArray(loc, identifier, type, symbol);
+
+        if (initializer) {
+            profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "initializer");
+            profileRequires(loc, EEsProfile, 300, nullptr, "initializer");
+        }
+    } else {
+        // non-array case
+        if (symbol == nullptr)
+            symbol = declareNonArray(loc, identifier, type);
+        else if (type != symbol->getType())
+            error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
+    }
+
+    if (symbol == nullptr)
+        return nullptr;
+
+    // Deal with initializer
+    TIntermNode* initNode = nullptr;
+    if (symbol != nullptr && initializer) {
+        TVariable* variable = symbol->getAsVariable();
+        if (! variable) {
+            error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
+            return nullptr;
+        }
+        initNode = executeInitializer(loc, initializer, variable);
+    }
+
+    // look for errors in layout qualifier use
+    layoutObjectCheck(loc, *symbol);
+    fixOffset(loc, *symbol);
+
+    return initNode;
+}
+
+// Pick up global defaults from the provide global defaults into dst.
+void TParseContext::inheritGlobalDefaults(TQualifier& dst) const
+{
+    if (dst.storage == EvqVaryingOut) {
+        if (! dst.hasStream() && language == EShLangGeometry)
+            dst.layoutStream = globalOutputDefaults.layoutStream;
+        if (! dst.hasXfbBuffer())
+            dst.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
+    }
+}
+
+//
+// Make an internal-only variable whose name is for debug purposes only
+// and won't be searched for.  Callers will only use the return value to use
+// the variable, not the name to look it up.  It is okay if the name
+// is the same as other names; there won't be any conflict.
+//
+TVariable* TParseContext::makeInternalVariable(const char* name, const TType& type) const
+{
+    TString* nameString = NewPoolTString(name);
+    TVariable* variable = new TVariable(nameString, type);
+    symbolTable.makeInternalVariable(*variable);
+
+    return variable;
+}
+
+//
+// Declare a non-array variable, the main point being there is no redeclaration
+// for resizing allowed.
+//
+// Return the successfully declared variable.
+//
+TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type)
+{
+    // make a new variable
+    TVariable* variable = new TVariable(&identifier, type);
+
+    ioArrayCheck(loc, type, identifier);
+
+    // add variable to symbol table
+    if (symbolTable.insert(*variable)) {
+        if (symbolTable.atGlobalLevel())
+            trackLinkageDeferred(*variable);
+        return variable;
+    }
+
+    error(loc, "redefinition", variable->getName().c_str(), "");
+    return nullptr;
+}
+
+//
+// Handle all types of initializers from the grammar.
+//
+// Returning nullptr just means there is no code to execute to handle the
+// initializer, which will, for example, be the case for constant initializers.
+//
+TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
+{
+    //
+    // Identifier must be of type constant, a global, or a temporary, and
+    // starting at version 120, desktop allows uniforms to have initializers.
+    //
+    TStorageQualifier qualifier = variable->getType().getQualifier().storage;
+    if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
+           (qualifier == EvqUniform && profile != EEsProfile && version >= 120))) {
+        error(loc, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
+        return nullptr;
+    }
+    arrayObjectCheck(loc, variable->getType(), "array initializer");
+
+    //
+    // If the initializer was from braces { ... }, we convert the whole subtree to a
+    // constructor-style subtree, allowing the rest of the code to operate
+    // identically for both kinds of initializers.
+    //
+    // Type can't be deduced from the initializer list, so a skeletal type to
+    // follow has to be passed in.  Constness and specialization-constness
+    // should be deduced bottom up, not dictated by the skeletal type.
+    //
+    TType skeletalType;
+    skeletalType.shallowCopy(variable->getType());
+    skeletalType.getQualifier().makeTemporary();
+    initializer = convertInitializerList(loc, skeletalType, initializer);
+    if (! initializer) {
+        // error recovery; don't leave const without constant values
+        if (qualifier == EvqConst)
+            variable->getWritableType().getQualifier().makeTemporary();
+        return nullptr;
+    }
+
+    // Fix outer arrayness if variable is unsized, getting size from the initializer
+    if (initializer->getType().isExplicitlySizedArray() &&
+        variable->getType().isImplicitlySizedArray())
+        variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize());
+
+    // Inner arrayness can also get set by an initializer
+    if (initializer->getType().isArrayOfArrays() && variable->getType().isArrayOfArrays() &&
+        initializer->getType().getArraySizes()->getNumDims() ==
+           variable->getType().getArraySizes()->getNumDims()) {
+        // adopt unsized sizes from the initializer's sizes
+        for (int d = 1; d < variable->getType().getArraySizes()->getNumDims(); ++d) {
+            if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize)
+                variable->getWritableType().getArraySizes().setDimSize(d, initializer->getType().getArraySizes()->getDimSize(d));
+        }
+    }
+
+    // Uniforms require a compile-time constant initializer
+    if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
+        error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
+        variable->getWritableType().getQualifier().makeTemporary();
+        return nullptr;
+    }
+    // Global consts require a constant initializer (specialization constant is okay)
+    if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
+        error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
+        variable->getWritableType().getQualifier().makeTemporary();
+        return nullptr;
+    }
+
+    // Const variables require a constant initializer, depending on version
+    if (qualifier == EvqConst) {
+        if (! initializer->getType().getQualifier().isConstant()) {
+            const char* initFeature = "non-constant initializer";
+            requireProfile(loc, ~EEsProfile, initFeature);
+            profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
+            variable->getWritableType().getQualifier().storage = EvqConstReadOnly;
+            qualifier = EvqConstReadOnly;
+        }
+    } else {
+        // Non-const global variables in ES need a const initializer.
+        //
+        // "In declarations of global variables with no storage qualifier or with a const
+        // qualifier any initializer must be a constant expression."
+        if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
+            const char* initFeature = "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
+            if (profile == EEsProfile) {
+                if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
+                    warn(loc, "not allowed in this version", initFeature, "");
+                else
+                    profileRequires(loc, EEsProfile, 0, E_GL_EXT_shader_non_constant_global_initializers, initFeature);
+            }
+        }
+    }
+
+    if (qualifier == EvqConst || qualifier == EvqUniform) {
+        // Compile-time tagging of the variable with its constant value...
+
+        initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
+        if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) {
+            error(loc, "non-matching or non-convertible constant type for const initializer",
+                  variable->getType().getStorageQualifierString(), "");
+            variable->getWritableType().getQualifier().makeTemporary();
+            return nullptr;
+        }
+
+        // We either have a folded constant in getAsConstantUnion, or we have to use
+        // the initializer's subtree in the AST to represent the computation of a
+        // specialization constant.
+        assert(initializer->getAsConstantUnion() || initializer->getType().getQualifier().isSpecConstant());
+        if (initializer->getAsConstantUnion())
+            variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
+        else {
+            // It's a specialization constant.
+            variable->getWritableType().getQualifier().makeSpecConstant();
+
+            // Keep the subtree that computes the specialization constant with the variable.
+            // Later, a symbol node will adopt the subtree from the variable.
+            variable->setConstSubtree(initializer);
+        }
+    } else {
+        // normal assigning of a value to a variable...
+        specializationCheck(loc, initializer->getType(), "initializer");
+        TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
+        TIntermTyped* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
+        if (! initNode)
+            assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+
+        return initNode;
+    }
+
+    return nullptr;
+}
+
+//
+// Reprocess any initializer-list (the  "{ ... }" syntax) parts of the
+// initializer.
+//
+// Need to hierarchically assign correct types and implicit
+// conversions. Will do this mimicking the same process used for
+// creating a constructor-style initializer, ensuring we get the
+// same form.  However, it has to in parallel walk the 'type'
+// passed in, as type cannot be deduced from an initializer list.
+//
+TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type, TIntermTyped* initializer)
+{
+    // Will operate recursively.  Once a subtree is found that is constructor style,
+    // everything below it is already good: Only the "top part" of the initializer
+    // can be an initializer list, where "top part" can extend for several (or all) levels.
+
+    // see if we have bottomed out in the tree within the initializer-list part
+    TIntermAggregate* initList = initializer->getAsAggregate();
+    if (! initList || initList->getOp() != EOpNull)
+        return initializer;
+
+    // Of the initializer-list set of nodes, need to process bottom up,
+    // so recurse deep, then process on the way up.
+
+    // Go down the tree here...
+    if (type.isArray()) {
+        // The type's array might be unsized, which could be okay, so base sizes on the size of the aggregate.
+        // Later on, initializer execution code will deal with array size logic.
+        TType arrayType;
+        arrayType.shallowCopy(type);                     // sharing struct stuff is fine
+        arrayType.newArraySizes(*type.getArraySizes());  // but get a fresh copy of the array information, to edit below
+
+        // edit array sizes to fill in unsized dimensions
+        arrayType.changeOuterArraySize((int)initList->getSequence().size());
+        TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped();
+        if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() &&
+            arrayType.getArraySizes().getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) {
+            for (int d = 1; d < arrayType.getArraySizes().getNumDims(); ++d) {
+                if (arrayType.getArraySizes().getDimSize(d) == UnsizedArraySize)
+                    arrayType.getArraySizes().setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1));
+            }
+        }
+
+        TType elementType(arrayType, 0); // dereferenced type
+        for (size_t i = 0; i < initList->getSequence().size(); ++i) {
+            initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped());
+            if (initList->getSequence()[i] == nullptr)
+                return nullptr;
+        }
+
+        return addConstructor(loc, initList, arrayType);
+    } else if (type.isStruct()) {
+        if (type.getStruct()->size() != initList->getSequence().size()) {
+            error(loc, "wrong number of structure members", "initializer list", "");
+            return nullptr;
+        }
+        for (size_t i = 0; i < type.getStruct()->size(); ++i) {
+            initList->getSequence()[i] = convertInitializerList(loc, *(*type.getStruct())[i].type, initList->getSequence()[i]->getAsTyped());
+            if (initList->getSequence()[i] == nullptr)
+                return nullptr;
+        }
+    } else if (type.isMatrix()) {
+        if (type.getMatrixCols() != (int)initList->getSequence().size()) {
+            error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str());
+            return nullptr;
+        }
+        TType vectorType(type, 0); // dereferenced type
+        for (int i = 0; i < type.getMatrixCols(); ++i) {
+            initList->getSequence()[i] = convertInitializerList(loc, vectorType, initList->getSequence()[i]->getAsTyped());
+            if (initList->getSequence()[i] == nullptr)
+                return nullptr;
+        }
+    } else if (type.isVector()) {
+        if (type.getVectorSize() != (int)initList->getSequence().size()) {
+            error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str());
+            return nullptr;
+        }
+    } else {
+        error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str());
+        return nullptr;
+    }
+
+    // Now that the subtree is processed, process this node as if the
+    // initializer list is a set of arguments to a constructor.
+    TIntermNode* emulatedConstructorArguments;
+    if (initList->getSequence().size() == 1)
+        emulatedConstructorArguments = initList->getSequence()[0];
+    else
+        emulatedConstructorArguments = initList;
+    return addConstructor(loc, emulatedConstructorArguments, type);
+}
+
+//
+// Test for the correctness of the parameters passed to various constructor functions
+// and also convert them to the right data type, if allowed and required.
+//
+// Returns nullptr for an error or the constructed node (aggregate or typed) for no error.
+//
+TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type)
+{
+    if (node == nullptr || node->getAsTyped() == nullptr)
+        return nullptr;
+    rValueErrorCheck(loc, "constructor", node->getAsTyped());
+
+    TIntermAggregate* aggrNode = node->getAsAggregate();
+    TOperator op = intermediate.mapTypeToConstructorOp(type);
+
+    // Combined texture-sampler constructors are completely semantic checked
+    // in constructorTextureSamplerError()
+    if (op == EOpConstructTextureSampler)
+        return intermediate.setAggregateOperator(aggrNode, op, type, loc);
+
+    TTypeList::const_iterator memberTypes;
+    if (op == EOpConstructStruct)
+        memberTypes = type.getStruct()->begin();
+
+    TType elementType;
+    if (type.isArray()) {
+        TType dereferenced(type, 0);
+        elementType.shallowCopy(dereferenced);
+    } else
+        elementType.shallowCopy(type);
+
+    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 constructAggregate function once.
+        if (type.isArray())
+            newNode = constructAggregate(node, elementType, 1, node->getLoc());
+        else if (op == EOpConstructStruct)
+            newNode = constructAggregate(node, *(*memberTypes).type, 1, node->getLoc());
+        else
+            newNode = constructBuiltIn(type, op, node->getAsTyped(), node->getLoc(), false);
+
+        if (newNode && (type.isArray() || op == EOpConstructStruct))
+            newNode = intermediate.setAggregateOperator(newNode, EOpConstructStruct, type, loc);
+
+        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 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 = constructAggregate(*p, elementType, paramCount+1, node->getLoc());
+        else if (op == EOpConstructStruct)
+            newNode = constructAggregate(*p, *(memberTypes[paramCount]).type, paramCount+1, node->getLoc());
+        else
+            newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
+
+        if (newNode)
+            *p = newNode;
+        else
+            return nullptr;
+    }
+
+    return intermediate.setAggregateOperator(aggrNode, op, type, loc);
+}
+
+// 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 nullptr for an error or the constructed node.
+//
+TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, const TSourceLoc& loc, bool subset)
+{
+    TIntermTyped* newNode;
+    TOperator basicOp;
+
+    //
+    // First, convert types as needed.
+    //
+    switch (op) {
+    case EOpConstructVec2:
+    case EOpConstructVec3:
+    case EOpConstructVec4:
+    case EOpConstructMat2x2:
+    case EOpConstructMat2x3:
+    case EOpConstructMat2x4:
+    case EOpConstructMat3x2:
+    case EOpConstructMat3x3:
+    case EOpConstructMat3x4:
+    case EOpConstructMat4x2:
+    case EOpConstructMat4x3:
+    case EOpConstructMat4x4:
+    case EOpConstructFloat:
+        basicOp = EOpConstructFloat;
+        break;
+
+    case EOpConstructDVec2:
+    case EOpConstructDVec3:
+    case EOpConstructDVec4:
+    case EOpConstructDMat2x2:
+    case EOpConstructDMat2x3:
+    case EOpConstructDMat2x4:
+    case EOpConstructDMat3x2:
+    case EOpConstructDMat3x3:
+    case EOpConstructDMat3x4:
+    case EOpConstructDMat4x2:
+    case EOpConstructDMat4x3:
+    case EOpConstructDMat4x4:
+    case EOpConstructDouble:
+        basicOp = EOpConstructDouble;
+        break;
+
+#ifdef AMD_EXTENSIONS
+    case EOpConstructF16Vec2:
+    case EOpConstructF16Vec3:
+    case EOpConstructF16Vec4:
+    case EOpConstructF16Mat2x2:
+    case EOpConstructF16Mat2x3:
+    case EOpConstructF16Mat2x4:
+    case EOpConstructF16Mat3x2:
+    case EOpConstructF16Mat3x3:
+    case EOpConstructF16Mat3x4:
+    case EOpConstructF16Mat4x2:
+    case EOpConstructF16Mat4x3:
+    case EOpConstructF16Mat4x4:
+    case EOpConstructFloat16:
+        basicOp = EOpConstructFloat16;
+        break;
+#endif
+
+    case EOpConstructIVec2:
+    case EOpConstructIVec3:
+    case EOpConstructIVec4:
+    case EOpConstructInt:
+        basicOp = EOpConstructInt;
+        break;
+
+    case EOpConstructUVec2:
+    case EOpConstructUVec3:
+    case EOpConstructUVec4:
+    case EOpConstructUint:
+        basicOp = EOpConstructUint;
+        break;
+
+    case EOpConstructI64Vec2:
+    case EOpConstructI64Vec3:
+    case EOpConstructI64Vec4:
+    case EOpConstructInt64:
+        basicOp = EOpConstructInt64;
+        break;
+
+    case EOpConstructU64Vec2:
+    case EOpConstructU64Vec3:
+    case EOpConstructU64Vec4:
+    case EOpConstructUint64:
+        basicOp = EOpConstructUint64;
+        break;
+
+    case EOpConstructBVec2:
+    case EOpConstructBVec3:
+    case EOpConstructBVec4:
+    case EOpConstructBool:
+        basicOp = EOpConstructBool;
+        break;
+
+    default:
+        error(loc, "unsupported construction", "", "");
+
+        return nullptr;
+    }
+    newNode = intermediate.addUnaryMath(basicOp, node, node->getLoc());
+    if (newNode == nullptr) {
+        error(loc, "can't convert", "constructor", "");
+        return nullptr;
+    }
+
+    //
+    // 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, type, loc);
+}
+
+// This function tests for the type of the parameters to the structure or array constructor. Raises
+// an error message if the expected type does not match the parameter passed to the constructor.
+//
+// Returns nullptr for an error or the input node itself if the expected and the given parameter types match.
+//
+TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount, const TSourceLoc& loc)
+{
+    TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped());
+    if (! converted || converted->getType() != type) {
+        error(loc, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount,
+              node->getAsTyped()->getType().getCompleteString().c_str(), type.getCompleteString().c_str());
+
+        return nullptr;
+    }
+
+    return converted;
+}
+
+//
+// Do everything needed to add an interface block.
+//
+void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
+{
+    blockStageIoCheck(loc, currentBlockQualifier);
+    blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr);
+    if (arraySizes) {
+        arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes, false, false);
+        arrayDimCheck(loc, arraySizes, 0);
+        if (arraySizes->getNumDims() > 1)
+            requireProfile(loc, ~EEsProfile, "array-of-array of block");
+    }
+
+    // fix and check for member storage qualifiers and types that don't belong within a block
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TType& memberType = *typeList[member].type;
+        TQualifier& memberQualifier = memberType.getQualifier();
+        const TSourceLoc& memberLoc = typeList[member].loc;
+        globalQualifierFixCheck(memberLoc, memberQualifier);
+        if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
+            error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
+        memberQualifier.storage = currentBlockQualifier.storage;
+        if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
+            error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), "");
+        if (memberType.isArray())
+            arrayUnsizedCheck(memberLoc, currentBlockQualifier, &memberType.getArraySizes(), false, member == typeList.size() - 1);
+        if (memberQualifier.hasOffset()) {
+            requireProfile(memberLoc, ~EEsProfile, "offset on block member");
+            profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member");
+        }
+
+        if (memberType.containsOpaque())
+            error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), "");
+    }
+
+    // This might be a redeclaration of a built-in block.  If so, redeclareBuiltinBlock() will
+    // do all the rest.
+    if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) {
+        redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes);
+        return;
+    }
+
+    // Not a redeclaration of a built-in; check that all names are user names.
+    reservedErrorCheck(loc, *blockName);
+    if (instanceName)
+        reservedErrorCheck(loc, *instanceName);
+    for (unsigned int member = 0; member < typeList.size(); ++member)
+        reservedErrorCheck(typeList[member].loc, typeList[member].type->getFieldName());
+
+    // Make default block qualification, and adjust the member qualifications
+
+    TQualifier defaultQualification;
+    switch (currentBlockQualifier.storage) {
+    case EvqUniform:    defaultQualification = globalUniformDefaults;    break;
+    case EvqBuffer:     defaultQualification = globalBufferDefaults;     break;
+    case EvqVaryingIn:  defaultQualification = globalInputDefaults;      break;
+    case EvqVaryingOut: defaultQualification = globalOutputDefaults;     break;
+    default:            defaultQualification.clear();                    break;
+    }
+
+    // Special case for "push_constant uniform", which has a default of std430,
+    // contrary to normal uniform defaults, and can't have a default tracked for it.
+    if (currentBlockQualifier.layoutPushConstant && !currentBlockQualifier.hasPacking())
+        currentBlockQualifier.layoutPacking = ElpStd430;
+
+    // fix and check for member layout qualifiers
+
+    mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
+
+    // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts."
+    // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts."
+    if (currentBlockQualifier.hasAlign() || currentBlockQualifier.hasAlign()) {
+        if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) {
+            error(loc, "can only be used with std140 or std430 layout packing", "offset/align", "");
+            defaultQualification.layoutAlign = -1;
+        }
+    }
+
+    bool memberWithLocation = false;
+    bool memberWithoutLocation = false;
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        const TSourceLoc& memberLoc = typeList[member].loc;
+        if (memberQualifier.hasStream()) {
+            if (defaultQualification.layoutStream != memberQualifier.layoutStream)
+                error(memberLoc, "member cannot contradict block", "stream", "");
+        }
+
+        // "This includes a block's inheritance of the
+        // current global default buffer, a block member's inheritance of the block's
+        // buffer, and the requirement that any *xfb_buffer* declared on a block
+        // member must match the buffer inherited from the block."
+        if (memberQualifier.hasXfbBuffer()) {
+            if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer)
+                error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", "");
+        }
+
+        if (memberQualifier.hasPacking())
+            error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), "");
+        if (memberQualifier.hasLocation()) {
+            const char* feature = "location on block member";
+            switch (currentBlockQualifier.storage) {
+            case EvqVaryingIn:
+            case EvqVaryingOut:
+                requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature);
+                profileRequires(memberLoc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
+                profileRequires(memberLoc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
+                memberWithLocation = true;
+                break;
+            default:
+                error(memberLoc, "can only use in an in/out block", feature, "");
+                break;
+            }
+        } else
+            memberWithoutLocation = true;
+        if (memberQualifier.hasAlign()) {
+            if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430)
+                error(memberLoc, "can only be used with std140 or std430 layout packing", "align", "");
+        }
+
+        TQualifier newMemberQualification = defaultQualification;
+        mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false);
+        memberQualifier = newMemberQualification;
+    }
+
+    // Process the members
+    fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
+    fixBlockXfbOffsets(currentBlockQualifier, typeList);
+    fixBlockUniformOffsets(currentBlockQualifier, typeList);
+    for (unsigned int member = 0; member < typeList.size(); ++member)
+        layoutTypeCheck(typeList[member].loc, *typeList[member].type);
+
+    // reverse merge, so that currentBlockQualifier now has all layout information
+    // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
+    mergeObjectLayoutQualifiers(currentBlockQualifier, defaultQualification, true);
+
+    //
+    // Build and add the interface block as a new type named 'blockName'
+    //
+
+    TType blockType(&typeList, *blockName, currentBlockQualifier);
+    if (arraySizes)
+        blockType.newArraySizes(*arraySizes);
+    else
+        ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
+
+    //
+    // Don't make a user-defined type out of block name; that will cause an error
+    // if the same block name gets reused in a different interface.
+    //
+    // "Block names have no other use within a shader
+    // beyond interface matching; it is a compile-time error to use a block name at global scope for anything
+    // other than as a block name (e.g., use of a block name for a global variable name or function name is
+    // currently reserved)."
+    //
+    // Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
+    // whose type is EbtBlock, but without all the structure; that will come from the type
+    // the instances point to.
+    //
+    TType blockNameType(EbtBlock, blockType.getQualifier().storage);
+    TVariable* blockNameVar = new TVariable(blockName, blockNameType);
+    if (! symbolTable.insert(*blockNameVar)) {
+        TSymbol* existingName = symbolTable.find(*blockName);
+        if (existingName->getType().getBasicType() == EbtBlock) {
+            if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
+                error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
+                return;
+            }
+        } else {
+            error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
+            return;
+        }
+    }
+
+    // Add the variable, as anonymous or named instanceName.
+    // Make an anonymous variable if no name was provided.
+    if (! instanceName)
+        instanceName = NewPoolTString("");
+
+    TVariable& variable = *new TVariable(instanceName, blockType);
+    if (! symbolTable.insert(variable)) {
+        if (*instanceName == "")
+            error(loc, "nameless block contains a member that already has a name at global scope", blockName->c_str(), "");
+        else
+            error(loc, "block instance name redefinition", variable.getName().c_str(), "");
+
+        return;
+    }
+
+    // Check for general layout qualifier errors
+    layoutObjectCheck(loc, variable);
+
+    if (isIoResizeArray(blockType)) {
+        ioArraySymbolResizeList.push_back(&variable);
+        checkIoArraysConsistency(loc, true);
+    } else
+        fixIoArraySize(loc, variable.getWritableType());
+
+    // Save it in the AST for linker use.
+    trackLinkageDeferred(variable);
+}
+
+// Do all block-declaration checking regarding the combination of in/out/uniform/buffer
+// with a particular stage.
+void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& qualifier)
+{
+    switch (qualifier.storage) {
+    case EvqUniform:
+        profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
+        profileRequires(loc, ENoProfile, 140, nullptr, "uniform block");
+        if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant)
+            error(loc, "requires the 'buffer' storage qualifier", "std430", "");
+        break;
+    case EvqBuffer:
+        requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "buffer block");
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, "buffer block");
+        profileRequires(loc, EEsProfile, 310, nullptr, "buffer block");
+        break;
+    case EvqVaryingIn:
+        profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "input block");
+        // It is a compile-time error to have an input block in a vertex shader or an output block in a fragment shader
+        // "Compute shaders do not permit user-defined input variables..."
+        requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|EShLangFragmentMask), "input block");
+        if (language == EShLangFragment)
+            profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block");
+        break;
+    case EvqVaryingOut:
+        profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block");
+        requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask), "output block");
+        // ES 310 can have a block before shader_io is turned on, so skip this test for built-ins
+        if (language == EShLangVertex && ! parsingBuiltins)
+            profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block");
+        break;
+    default:
+        error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
+        break;
+    }
+}
+
+// Do all block-declaration checking regarding its qualifiers.
+void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool instanceName)
+{
+    // The 4.5 specification says:
+    //
+    // interface-block :
+    //    layout-qualifieropt interface-qualifier  block-name { member-list } instance-nameopt ;
+    //
+    // interface-qualifier :
+    //    in
+    //    out
+    //    patch in
+    //    patch out
+    //    uniform
+    //    buffer
+    //
+    // Note however memory qualifiers aren't included, yet the specification also says
+    //
+    // "...memory qualifiers may also be used in the declaration of shader storage blocks..."
+
+    if (qualifier.isInterpolation())
+        error(loc, "cannot use interpolation qualifiers on an interface block", "flat/smooth/noperspective", "");
+    if (qualifier.centroid)
+        error(loc, "cannot use centroid qualifier on an interface block", "centroid", "");
+    if (qualifier.sample)
+        error(loc, "cannot use sample qualifier on an interface block", "sample", "");
+    if (qualifier.invariant)
+        error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
+    if (qualifier.layoutPushConstant) {
+        intermediate.addPushConstantCount();
+        if (! instanceName)
+            error(loc, "requires an instance name", "push_constant", "");
+    }
+}
+
+//
+// "For a block, this process applies to the entire block, or until the first member
+// is reached that has a location layout qualifier. When a block member is declared with a location
+// qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level
+// declaration. Subsequent members are again assigned consecutive locations, based on the newest location,
+// until the next member declared with a location qualifier. The values used for locations do not have to be
+// declared in increasing order."
+void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation)
+{
+    // "If a block has no block-level location layout qualifier, it is required that either all or none of its members
+    // have a location layout qualifier, or a compile-time error results."
+    if (! qualifier.hasLocation() && memberWithLocation && memberWithoutLocation)
+        error(loc, "either the block needs a location, or all members need a location, or no members have a location", "location", "");
+    else {
+        if (memberWithLocation) {
+            // remove any block-level location and make it per *every* member
+            int nextLocation = 0;  // by the rule above, initial value is not relevant
+            if (qualifier.hasAnyLocation()) {
+                nextLocation = qualifier.layoutLocation;
+                qualifier.layoutLocation = TQualifier::layoutLocationEnd;
+                if (qualifier.hasComponent()) {
+                    // "It is a compile-time error to apply the *component* qualifier to a ... block"
+                    error(loc, "cannot apply to a block", "component", "");
+                }
+                if (qualifier.hasIndex()) {
+                    error(loc, "cannot apply to a block", "index", "");
+                }
+            }
+            for (unsigned int member = 0; member < typeList.size(); ++member) {
+                TQualifier& memberQualifier = typeList[member].type->getQualifier();
+                const TSourceLoc& memberLoc = typeList[member].loc;
+                if (! memberQualifier.hasLocation()) {
+                    if (nextLocation >= (int)TQualifier::layoutLocationEnd)
+                        error(memberLoc, "location is too large", "location", "");
+                    memberQualifier.layoutLocation = nextLocation;
+                    memberQualifier.layoutComponent = 0;
+                }
+                nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize(*typeList[member].type);
+            }
+        }
+    }
+}
+
+void TParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
+{
+    // "If a block is qualified with xfb_offset, all its
+    // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any
+    // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer
+    // offsets."
+
+    if (! qualifier.hasXfbBuffer() || ! qualifier.hasXfbOffset())
+        return;
+
+    int nextOffset = qualifier.layoutXfbOffset;
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        bool containsDouble = false;
+        int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, containsDouble);
+        // see if we need to auto-assign an offset to this member
+        if (! memberQualifier.hasXfbOffset()) {
+            // "if applied to an aggregate containing a double, the offset must also be a multiple of 8"
+            if (containsDouble)
+                RoundToPow2(nextOffset, 8);
+            memberQualifier.layoutXfbOffset = nextOffset;
+        } else
+            nextOffset = memberQualifier.layoutXfbOffset;
+        nextOffset += memberSize;
+    }
+
+    // The above gave all block members an offset, so we can take it off the block now,
+    // which will avoid double counting the offset usage.
+    qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd;
+}
+
+// Calculate and save the offset of each block member, using the recursively
+// defined block offset rules and the user-provided offset and align.
+//
+// Also, compute and save the total size of the block. For the block's size, arrayness
+// is not taken into account, as each element is backed by a separate buffer.
+//
+void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList)
+{
+    if (! qualifier.isUniformOrBuffer())
+        return;
+    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
+        return;
+
+    int offset = 0;
+    int memberSize;
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        const TSourceLoc& memberLoc = typeList[member].loc;
+
+        // "When align is applied to an array, it effects only the start of the array, not the array's internal stride."
+
+        // modify just the children's view of matrix layout, if there is one for this member
+        TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
+        int dummyStride;
+        int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140,
+                                                            subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
+        if (memberQualifier.hasOffset()) {
+            // "The specified offset must be a multiple
+            // of the base alignment of the type of the block member it qualifies, or a compile-time error results."
+            if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment))
+                error(memberLoc, "must be a multiple of the member's alignment", "offset", "");
+
+            // GLSL: "It is a compile-time error to specify an offset that is smaller than the offset of the previous
+            // member in the block or that lies within the previous member of the block"
+            if (spvVersion.spv == 0) {
+                if (memberQualifier.layoutOffset < offset)
+                    error(memberLoc, "cannot lie in previous members", "offset", "");
+
+                // "The offset qualifier forces the qualified member to start at or after the specified
+                // integral-constant expression, which will be its byte offset from the beginning of the buffer.
+                // "The actual offset of a member is computed as
+                // follows: If offset was declared, start with that offset, otherwise start with the next available offset."
+                offset = std::max(offset, memberQualifier.layoutOffset);
+            } else {
+                // TODO: Vulkan: "It is a compile-time error to have any offset, explicit or assigned,
+                // that lies within another member of the block."
+
+                offset = memberQualifier.layoutOffset;
+            }
+        }
+
+        // "The actual alignment of a member will be the greater of the specified align alignment and the standard
+        // (e.g., std140) base alignment for the member's type."
+        if (memberQualifier.hasAlign())
+            memberAlignment = std::max(memberAlignment, memberQualifier.layoutAlign);
+
+        // "If the resulting offset is not a multiple of the actual alignment,
+        // increase it to the first offset that is a multiple of
+        // the actual alignment."
+        RoundToPow2(offset, memberAlignment);
+        typeList[member].type->getQualifier().layoutOffset = offset;
+        offset += memberSize;
+    }
+}
+
+// For an identifier that is already declared, add more qualification to it.
+void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier)
+{
+    TSymbol* symbol = symbolTable.find(identifier);
+    if (! symbol) {
+        error(loc, "identifier not previously declared", identifier.c_str(), "");
+        return;
+    }
+    if (symbol->getAsFunction()) {
+        error(loc, "cannot re-qualify a function name", identifier.c_str(), "");
+        return;
+    }
+
+    if (qualifier.isAuxiliary() ||
+        qualifier.isMemory() ||
+        qualifier.isInterpolation() ||
+        qualifier.hasLayout() ||
+        qualifier.storage != EvqTemporary ||
+        qualifier.precision != EpqNone) {
+        error(loc, "cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable", identifier.c_str(), "");
+        return;
+    }
+
+    // For read-only built-ins, add a new symbol for holding the modified qualifier.
+    // This will bring up an entire block, if a block type has to be modified (e.g., gl_Position inside a block)
+    if (symbol->isReadOnly())
+        symbol = symbolTable.copyUp(symbol);
+
+    if (qualifier.invariant) {
+        if (intermediate.inIoAccessed(identifier))
+            error(loc, "cannot change qualification after use", "invariant", "");
+        symbol->getWritableType().getQualifier().invariant = true;
+        invariantCheck(loc, symbol->getType().getQualifier());
+    } else if (qualifier.noContraction) {
+        if (intermediate.inIoAccessed(identifier))
+            error(loc, "cannot change qualification after use", "precise", "");
+        symbol->getWritableType().getQualifier().noContraction = true;
+    } else if (qualifier.specConstant) {
+        symbol->getWritableType().getQualifier().makeSpecConstant();
+        if (qualifier.hasSpecConstantId())
+            symbol->getWritableType().getQualifier().layoutSpecConstantId = qualifier.layoutSpecConstantId;
+    } else
+        warn(loc, "unknown requalification", "", "");
+}
+
+void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, TIdentifierList& identifiers)
+{
+    for (unsigned int i = 0; i < identifiers.size(); ++i)
+        addQualifierToExisting(loc, qualifier, *identifiers[i]);
+}
+
+// Make sure 'invariant' isn't being applied to a non-allowed object.
+void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qualifier)
+{
+    if (! qualifier.invariant)
+        return;
+
+    bool pipeOut = qualifier.isPipeOutput();
+    bool pipeIn = qualifier.isPipeInput();
+    if (version >= 300 || (profile != EEsProfile && version >= 420)) {
+        if (! pipeOut)
+            error(loc, "can only apply to an output", "invariant", "");
+    } else {
+        if ((language == EShLangVertex && pipeIn) || (! pipeOut && ! pipeIn))
+            error(loc, "can only apply to an output, or to an input in a non-vertex stage\n", "invariant", "");
+    }
+}
+
+//
+// Updating default qualifier for the case of a declaration with just a qualifier,
+// no type, block, or identifier.
+//
+void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType)
+{
+    if (publicType.shaderQualifiers.vertices != TQualifier::layoutNotSet) {
+        assert(language == EShLangTessControl || language == EShLangGeometry);
+        const char* id = (language == EShLangTessControl) ? "vertices" : "max_vertices";
+
+        if (publicType.qualifier.storage != EvqVaryingOut)
+            error(loc, "can only apply to 'out'", id, "");
+        if (! intermediate.setVertices(publicType.shaderQualifiers.vertices))
+            error(loc, "cannot change previously set layout value", id, "");
+
+        if (language == EShLangTessControl)
+            checkIoArraysConsistency(loc);
+    }
+    if (publicType.shaderQualifiers.invocations != TQualifier::layoutNotSet) {
+        if (publicType.qualifier.storage != EvqVaryingIn)
+            error(loc, "can only apply to 'in'", "invocations", "");
+        if (! intermediate.setInvocations(publicType.shaderQualifiers.invocations))
+            error(loc, "cannot change previously set layout value", "invocations", "");
+    }
+    if (publicType.shaderQualifiers.geometry != ElgNone) {
+        if (publicType.qualifier.storage == EvqVaryingIn) {
+            switch (publicType.shaderQualifiers.geometry) {
+            case ElgPoints:
+            case ElgLines:
+            case ElgLinesAdjacency:
+            case ElgTriangles:
+            case ElgTrianglesAdjacency:
+            case ElgQuads:
+            case ElgIsolines:
+                if (intermediate.setInputPrimitive(publicType.shaderQualifiers.geometry)) {
+                    if (language == EShLangGeometry)
+                        checkIoArraysConsistency(loc);
+                } else
+                    error(loc, "cannot change previously set input primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
+                break;
+            default:
+                error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
+            }
+        } else if (publicType.qualifier.storage == EvqVaryingOut) {
+            switch (publicType.shaderQualifiers.geometry) {
+            case ElgPoints:
+            case ElgLineStrip:
+            case ElgTriangleStrip:
+                if (! intermediate.setOutputPrimitive(publicType.shaderQualifiers.geometry))
+                    error(loc, "cannot change previously set output primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
+                break;
+            default:
+                error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
+            }
+        } else
+            error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
+    }
+    if (publicType.shaderQualifiers.spacing != EvsNone) {
+        if (publicType.qualifier.storage == EvqVaryingIn) {
+            if (! intermediate.setVertexSpacing(publicType.shaderQualifiers.spacing))
+                error(loc, "cannot change previously set vertex spacing", TQualifier::getVertexSpacingString(publicType.shaderQualifiers.spacing), "");
+        } else
+            error(loc, "can only apply to 'in'", TQualifier::getVertexSpacingString(publicType.shaderQualifiers.spacing), "");
+    }
+    if (publicType.shaderQualifiers.order != EvoNone) {
+        if (publicType.qualifier.storage == EvqVaryingIn) {
+            if (! intermediate.setVertexOrder(publicType.shaderQualifiers.order))
+                error(loc, "cannot change previously set vertex order", TQualifier::getVertexOrderString(publicType.shaderQualifiers.order), "");
+        } else
+            error(loc, "can only apply to 'in'", TQualifier::getVertexOrderString(publicType.shaderQualifiers.order), "");
+    }
+    if (publicType.shaderQualifiers.pointMode) {
+        if (publicType.qualifier.storage == EvqVaryingIn)
+            intermediate.setPointMode();
+        else
+            error(loc, "can only apply to 'in'", "point_mode", "");
+    }
+    for (int i = 0; i < 3; ++i) {
+        if (publicType.shaderQualifiers.localSize[i] > 1) {
+            if (publicType.qualifier.storage == EvqVaryingIn) {
+                if (! intermediate.setLocalSize(i, publicType.shaderQualifiers.localSize[i]))
+                    error(loc, "cannot change previously set size", "local_size", "");
+                else {
+                    int max = 0;
+                    switch (i) {
+                    case 0: max = resources.maxComputeWorkGroupSizeX; break;
+                    case 1: max = resources.maxComputeWorkGroupSizeY; break;
+                    case 2: max = resources.maxComputeWorkGroupSizeZ; break;
+                    default: break;
+                    }
+                    if (intermediate.getLocalSize(i) > (unsigned int)max)
+                        error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
+
+                    // Fix the existing constant gl_WorkGroupSize with this new information.
+                    TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
+                    if (workGroupSize != nullptr)
+                        workGroupSize->getWritableConstArray()[i].setUConst(intermediate.getLocalSize(i));
+                }
+            } else
+                error(loc, "can only apply to 'in'", "local_size", "");
+        }
+        if (publicType.shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) {
+            if (publicType.qualifier.storage == EvqVaryingIn) {
+                if (! intermediate.setLocalSizeSpecId(i, publicType.shaderQualifiers.localSizeSpecId[i]))
+                    error(loc, "cannot change previously set size", "local_size", "");
+            } else
+                error(loc, "can only apply to 'in'", "local_size id", "");
+            // Set the workgroup built-in variable as a specialization constant
+            TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
+            if (workGroupSize != nullptr)
+                workGroupSize->getWritableType().getQualifier().specConstant = true;
+        }
+    }
+    if (publicType.shaderQualifiers.earlyFragmentTests) {
+        if (publicType.qualifier.storage == EvqVaryingIn)
+            intermediate.setEarlyFragmentTests();
+        else
+            error(loc, "can only apply to 'in'", "early_fragment_tests", "");
+    }
+    if (publicType.shaderQualifiers.blendEquation) {
+        if (publicType.qualifier.storage != EvqVaryingOut)
+            error(loc, "can only apply to 'out'", "blend equation", "");
+    }
+
+    const TQualifier& qualifier = publicType.qualifier;
+
+    if (qualifier.isAuxiliary() ||
+        qualifier.isMemory() ||
+        qualifier.isInterpolation() ||
+        qualifier.precision != EpqNone)
+        error(loc, "cannot use auxiliary, memory, interpolation, or precision qualifier in a default qualifier declaration (declaration with no type)", "qualifier", "");
+    // "The offset qualifier can only be used on block members of blocks..."
+    // "The align qualifier can only be used on blocks or block members..."
+    if (qualifier.hasOffset() ||
+        qualifier.hasAlign())
+        error(loc, "cannot use offset or align qualifiers in a default qualifier declaration (declaration with no type)", "layout qualifier", "");
+
+    layoutQualifierCheck(loc, qualifier);
+
+    switch (qualifier.storage) {
+    case EvqUniform:
+        if (qualifier.hasMatrix())
+            globalUniformDefaults.layoutMatrix = qualifier.layoutMatrix;
+        if (qualifier.hasPacking())
+            globalUniformDefaults.layoutPacking = qualifier.layoutPacking;
+        break;
+    case EvqBuffer:
+        if (qualifier.hasMatrix())
+            globalBufferDefaults.layoutMatrix = qualifier.layoutMatrix;
+        if (qualifier.hasPacking())
+            globalBufferDefaults.layoutPacking = qualifier.layoutPacking;
+        break;
+    case EvqVaryingIn:
+        break;
+    case EvqVaryingOut:
+        if (qualifier.hasStream())
+            globalOutputDefaults.layoutStream = qualifier.layoutStream;
+        if (qualifier.hasXfbBuffer())
+            globalOutputDefaults.layoutXfbBuffer = qualifier.layoutXfbBuffer;
+        if (globalOutputDefaults.hasXfbBuffer() && qualifier.hasXfbStride()) {
+            if (! intermediate.setXfbBufferStride(globalOutputDefaults.layoutXfbBuffer, qualifier.layoutXfbStride))
+                error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
+        }
+        break;
+    default:
+        error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", "");
+        return;
+    }
+
+    if (qualifier.hasBinding())
+        error(loc, "cannot declare a default, include a type or full declaration", "binding", "");
+    if (qualifier.hasAnyLocation())
+        error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
+    if (qualifier.hasXfbOffset())
+        error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
+    if (qualifier.layoutPushConstant)
+        error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
+    if (qualifier.hasSpecConstantId())
+        error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
+}
+
+//
+// Take the sequence of statements that has been built up since the last case/default,
+// put it on the list of top-level nodes for the current (inner-most) switch statement,
+// and follow that by the case/default we are on now.  (See switch topology comment on
+// TIntermSwitch.)
+//
+void TParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode)
+{
+    TIntermSequence* switchSequence = switchSequenceStack.back();
+
+    if (statements) {
+        if (switchSequence->size() == 0)
+            error(statements->getLoc(), "cannot have statements before first case/default label", "switch", "");
+        statements->setOperator(EOpSequence);
+        switchSequence->push_back(statements);
+    }
+    if (branchNode) {
+        // check all previous cases for the same label (or both are 'default')
+        for (unsigned int s = 0; s < switchSequence->size(); ++s) {
+            TIntermBranch* prevBranch = (*switchSequence)[s]->getAsBranchNode();
+            if (prevBranch) {
+                TIntermTyped* prevExpression = prevBranch->getExpression();
+                TIntermTyped* newExpression = branchNode->getAsBranchNode()->getExpression();
+                if (prevExpression == nullptr && newExpression == nullptr)
+                    error(branchNode->getLoc(), "duplicate label", "default", "");
+                else if (prevExpression != nullptr &&
+                          newExpression != nullptr &&
+                         prevExpression->getAsConstantUnion() &&
+                          newExpression->getAsConstantUnion() &&
+                         prevExpression->getAsConstantUnion()->getConstArray()[0].getIConst() ==
+                          newExpression->getAsConstantUnion()->getConstArray()[0].getIConst())
+                    error(branchNode->getLoc(), "duplicated value", "case", "");
+            }
+        }
+        switchSequence->push_back(branchNode);
+    }
+}
+
+//
+// Turn the top-level node sequence built up of wrapupSwitchSubsequence9)
+// into a switch node.
+//
+TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermAggregate* lastStatements)
+{
+    profileRequires(loc, EEsProfile, 300, nullptr, "switch statements");
+    profileRequires(loc, ENoProfile, 130, nullptr, "switch statements");
+
+    wrapupSwitchSubsequence(lastStatements, nullptr);
+
+    if (expression == nullptr ||
+        (expression->getBasicType() != EbtInt && expression->getBasicType() != EbtUint) ||
+        expression->getType().isArray() || expression->getType().isMatrix() || expression->getType().isVector())
+            error(loc, "condition must be a scalar integer expression", "switch", "");
+
+    // If there is nothing to do, drop the switch but still execute the expression
+    TIntermSequence* switchSequence = switchSequenceStack.back();
+    if (switchSequence->size() == 0)
+        return expression;
+
+    if (lastStatements == nullptr) {
+        // This was originally an ERRROR, because early versions of the specification said
+        // "it is an error to have no statement between a label and the end of the switch statement."
+        // The specifications were updated to remove this (being ill-defined what a "statement" was),
+        // so, this became a warning.  However, 3.0 tests still check for the error.
+        if (profile == EEsProfile && version <= 300 && ! relaxedErrors())
+            error(loc, "last case/default label not followed by statements", "switch", "");
+        else
+            warn(loc, "last case/default label not followed by statements", "switch", "");
+
+        // emulate a break for error recovery
+        lastStatements = intermediate.makeAggregate(intermediate.addBranch(EOpBreak, loc));
+        lastStatements->setOperator(EOpSequence);
+        switchSequence->push_back(lastStatements);
+    }
+
+    TIntermAggregate* body = new TIntermAggregate(EOpSequence);
+    body->getSequence() = *switchSequenceStack.back();
+    body->setLoc(loc);
+
+    TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
+    switchNode->setLoc(loc);
+
+    return switchNode;
+}
+
+} // end namespace glslang

+ 464 - 0
src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h

@@ -0,0 +1,464 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// This header defines a two-level parse-helper hierarchy, derived from
+// TParseVersions:
+//  - TParseContextBase:  sharable across multiple parsers
+//  - TParseContext:      GLSL specific helper
+//
+
+#ifndef _PARSER_HELPER_INCLUDED_
+#define _PARSER_HELPER_INCLUDED_
+
+#include "parseVersions.h"
+#include "../Include/ShHandle.h"
+#include "SymbolTable.h"
+#include "localintermediate.h"
+#include "Scan.h"
+#include <cstdarg>
+#include <functional>
+
+namespace glslang {
+
+struct TPragma {
+    TPragma(bool o, bool d) : optimize(o), debug(d) { }
+    bool optimize;
+    bool debug;
+    TPragmaTable pragmaTable;
+};
+
+class TScanContext;
+class TPpContext;
+
+typedef std::set<int> TIdSetType;
+
+//
+// Sharable code (as well as what's in TParseVersions) across
+// parse helpers.
+//
+class TParseContextBase : public TParseVersions {
+public:
+    TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version,
+                      EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
+                      TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
+          : TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
+            symbolTable(symbolTable),
+            parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr),
+            globalUniformBlock(nullptr)
+    {
+        linkage = new TIntermAggregate;
+    }
+    virtual ~TParseContextBase() { }
+
+    virtual void C_DECL   error(const TSourceLoc&, const char* szReason, const char* szToken,
+                                const char* szExtraInfoFormat, ...);
+    virtual void C_DECL    warn(const TSourceLoc&, const char* szReason, const char* szToken,
+                                const char* szExtraInfoFormat, ...);
+    virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
+                                const char* szExtraInfoFormat, ...);
+    virtual void C_DECL  ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
+                                const char* szExtraInfoFormat, ...);
+
+    virtual void setLimits(const TBuiltInResource&) = 0;
+
+    EShLanguage getLanguage() const { return language; }
+    void setScanContext(TScanContext* c) { scanContext = c; }
+    TScanContext* getScanContext() const { return scanContext; }
+    void setPpContext(TPpContext* c) { ppContext = c; }
+    TPpContext* getPpContext() const { return ppContext; }
+
+    virtual void setLineCallback(const std::function<void(int, int, bool, int, const char*)>& func) { lineCallback = func; }
+    virtual void setExtensionCallback(const std::function<void(int, const char*, const char*)>& func) { extensionCallback = func; }
+    virtual void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; }
+    virtual void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; }
+    virtual void setErrorCallback(const std::function<void(int, const char*)>& func) { errorCallback = func; }
+
+    virtual void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) = 0;
+    virtual bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) = 0;
+    virtual bool lineDirectiveShouldSetNextLine() const = 0;
+    virtual void handlePragma(const TSourceLoc&, const TVector<TString>&) = 0;
+
+    virtual bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) = 0;
+
+    virtual void notifyVersion(int line, int version, const char* type_string)
+    {
+        if (versionCallback)
+            versionCallback(line, version, type_string);
+    }
+    virtual void notifyErrorDirective(int line, const char* error_message)
+    {
+        if (errorCallback)
+            errorCallback(line, error_message);
+    }
+    virtual void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName)
+    {
+        if (lineCallback)
+            lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName);
+    }
+    virtual void notifyExtensionDirective(int line, const char* extension, const char* behavior)
+    {
+        if (extensionCallback)
+            extensionCallback(line, extension, behavior);
+    }
+
+    TSymbolTable& symbolTable;   // symbol table that goes with the current language, version, and profile
+
+    // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
+    // TODO: This could perhaps get its own object, but the current design doesn't work
+    // yet when new uniform variables are declared between function definitions, so
+    // this is pending getting a fully functional design.
+    virtual void growGlobalUniformBlock(TSourceLoc&, TType&, TString& memberName);
+    virtual bool insertGlobalUniformBlock();
+
+    virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
+    virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
+
+protected:
+    TParseContextBase(TParseContextBase&);
+    TParseContextBase& operator=(TParseContextBase&);
+
+    const bool parsingBuiltins;       // true if parsing built-in symbols/functions
+    TVector<TSymbol*> linkageSymbols; // these need to be transferred to 'linkage', after all editing is done
+    TScanContext* scanContext;
+    TPpContext* ppContext;
+
+    // These, if set, will be called when a line, pragma ... is preprocessed.
+    // They will be called with any parameters to the original directive.
+    std::function<void(int, int, bool, int, const char*)> lineCallback;
+    std::function<void(int, const TVector<TString>&)> pragmaCallback;
+    std::function<void(int, int, const char*)> versionCallback;
+    std::function<void(int, const char*, const char*)> extensionCallback;
+    std::function<void(int, const char*)> errorCallback;
+
+    // see implementation for detail
+    const TFunction* selectFunction(const TVector<const TFunction*>, const TFunction&,
+        std::function<bool(const TType&, const TType&, TOperator, int arg)>,
+        std::function<bool(const TType&, const TType&, const TType&)>,
+        /* output */ bool& tie);
+
+    virtual void parseSwizzleSelector(const TSourceLoc&, const TString&, int size,
+                                      TSwizzleSelectors<TVectorSelector>&);
+
+    // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
+    TVariable* globalUniformBlock;   // the actual block, inserted into the symbol table
+    int firstNewMember;              // the index of the first member not yet inserted into the symbol table
+    // override this to set the language-specific name
+    virtual const char* getGlobalUniformBlockName() { return ""; }
+    virtual void finalizeGlobalUniformBlockLayout(TVariable&) { }
+    virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
+                               const char* szExtraInfoFormat, TPrefixType prefix,
+                               va_list args);
+    virtual void trackLinkage(TSymbol& symbol);
+    virtual void trackLinkageDeferred(TSymbol& symbol);
+    virtual void makeEditable(TSymbol*&);
+    virtual TVariable* getEditableVariable(const char* name);
+    virtual void finish();
+
+private:
+    TIntermAggregate* linkage;
+};
+
+//
+// Manage the state for when to respect precision qualifiers and when to warn about
+// the defaults being different than might be expected.
+//
+class TPrecisionManager {
+public:
+    TPrecisionManager() : obey(false), warn(false), explicitIntDefault(false), explicitFloatDefault(false){ }
+    virtual ~TPrecisionManager() {}
+
+    void respectPrecisionQualifiers() { obey = true; }
+    bool respectingPrecisionQualifiers() const { return obey; }
+    bool shouldWarnAboutDefaults() const { return warn; }
+    void defaultWarningGiven() { warn = false; }
+    void warnAboutDefaults() { warn = true; }
+    void explicitIntDefaultSeen()
+    {
+        explicitIntDefault = true;
+        if (explicitFloatDefault)
+            warn = false;
+    }
+    void explicitFloatDefaultSeen()
+    {
+        explicitFloatDefault = true;
+        if (explicitIntDefault)
+            warn = false;
+    }
+
+protected:
+    bool obey;                  // respect precision qualifiers
+    bool warn;                  // need to give a warning about the defaults
+    bool explicitIntDefault;    // user set the default for int/uint
+    bool explicitFloatDefault;  // user set the default for float
+};
+
+//
+// GLSL-specific parse helper.  Should have GLSL in the name, but that's
+// too big of a change for comparing branches at the moment, and perhaps
+// impacts downstream consumers as well.
+//
+class TParseContext : public TParseContextBase {
+public:
+    TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&,
+                  bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
+    virtual ~TParseContext();
+
+    bool obeyPrecisionQualifiers() const { return precisionManager.respectingPrecisionQualifiers(); };
+    void setPrecisionDefaults();
+
+    void setLimits(const TBuiltInResource&) override;
+    bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) override;
+    void parserError(const char* s);     // for bison's yyerror
+
+    void reservedErrorCheck(const TSourceLoc&, const TString&);
+    void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) override;
+    bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) override;
+    bool lineDirectiveShouldSetNextLine() const override;
+    bool builtInName(const TString&);
+
+    void handlePragma(const TSourceLoc&, const TVector<TString>&) override;
+    TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string);
+    TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
+    void checkIndex(const TSourceLoc&, const TType&, int& index);
+    void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
+
+    void makeEditable(TSymbol*&) override;
+    bool isIoResizeArray(const TType&) const;
+    void fixIoArraySize(const TSourceLoc&, TType&);
+    void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
+    void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base);
+    void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false);
+    int getIoArrayImplicitSize() const;
+    void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&);
+
+    TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
+    TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
+    TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
+    void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field);
+    TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
+    TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
+    TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
+    TIntermTyped* handleBuiltInFunctionCall(TSourceLoc, TIntermNode& arguments, const TFunction& function);
+    void computeBuiltinPrecisions(TIntermTyped&, const TFunction&);
+    TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
+    void checkLocation(const TSourceLoc&, TOperator);
+    TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
+    void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
+    TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
+    void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
+    void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&);
+    void userFunctionCallCheck(const TSourceLoc&, TIntermAggregate&);
+    void samplerConstructorLocationCheck(const TSourceLoc&, const char* token, TIntermNode*);
+    TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&);
+    void handlePrecisionQualifier(const TSourceLoc&, TQualifier&, TPrecisionQualifier);
+    void checkPrecisionQualifier(const TSourceLoc&, TPrecisionQualifier);
+
+    void assignError(const TSourceLoc&, const char* op, TString left, TString right);
+    void unaryOpError(const TSourceLoc&, const char* op, TString operand);
+    void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right);
+    void variableCheck(TIntermTyped*& nodePtr);
+    bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
+    void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
+    void constantValueCheck(TIntermTyped* node, const char* token);
+    void integerCheck(const TIntermTyped* node, const char* token);
+    void globalCheck(const TSourceLoc&, const char* token);
+    bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
+    bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
+    void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&);
+    bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
+    bool arrayError(const TSourceLoc&, const TType&);
+    void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
+    void structArrayCheck(const TSourceLoc&, const TType& structure);
+    void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer, bool lastMember);
+    void arrayOfArrayVersionCheck(const TSourceLoc&);
+    void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2);
+    void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*);
+    void arrayDimMerge(TType& type, const TArraySizes* sizes);
+    bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType);
+    void boolCheck(const TSourceLoc&, const TIntermTyped*);
+    void boolCheck(const TSourceLoc&, const TPublicType&);
+    void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer);
+    void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier);
+    void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier);
+    void globalQualifierFixCheck(const TSourceLoc&, TQualifier&);
+    void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
+    bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
+    void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);
+    void setDefaultPrecision(const TSourceLoc&, TPublicType&, TPrecisionQualifier);
+    int computeSamplerTypeIndex(TSampler&);
+    TPrecisionQualifier getDefaultPrecision(TPublicType&);
+    void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&);
+    void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type);
+    bool containsFieldWithBasicType(const TType& type ,TBasicType basicType);
+    TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&);
+    void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes);
+    void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type);
+    void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type);
+    void nestedBlockCheck(const TSourceLoc&);
+    void nestedStructCheck(const TSourceLoc&);
+    void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op);
+    void opaqueCheck(const TSourceLoc&, const TType&, const char* op);
+    void specializationCheck(const TSourceLoc&, const TType&, const char* op);
+    void structTypeCheck(const TSourceLoc&, TPublicType&);
+    void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop);
+    void arrayLimitCheck(const TSourceLoc&, const TString&, int size);
+    void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature);
+
+    void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&);
+    void constantIndexExpressionCheck(TIntermNode*);
+
+    void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&);
+    void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*);
+    void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly);
+    void layoutObjectCheck(const TSourceLoc&, const TSymbol&);
+    void layoutTypeCheck(const TSourceLoc&, const TType&);
+    void layoutQualifierCheck(const TSourceLoc&, const TQualifier&);
+    void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&);
+    void fixOffset(const TSourceLoc&, TSymbol&);
+
+    const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
+    const TFunction* findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
+    const TFunction* findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
+    const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
+    void declareTypeDefaults(const TSourceLoc&, const TPublicType&);
+    TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
+    TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
+    TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
+    TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
+    void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
+    void blockStageIoCheck(const TSourceLoc&, const TQualifier&);
+    void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName);
+    void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
+    void fixBlockXfbOffsets(TQualifier&, TTypeList&);
+    void fixBlockUniformOffsets(TQualifier&, TTypeList&);
+    void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier);
+    void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
+    void invariantCheck(const TSourceLoc&, const TQualifier&);
+    void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
+    void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
+    TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
+
+    void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
+
+protected:
+    void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
+    void inheritGlobalDefaults(TQualifier& dst) const;
+    TVariable* makeInternalVariable(const char* name, const TType&) const;
+    TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&);
+    void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&);
+    TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
+    TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
+    void finish() override;
+
+public:
+    //
+    // Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access
+    //
+
+    // Current state of parsing
+    struct TPragma contextPragma;
+    int loopNestingLevel;        // 0 if outside all loops
+    int structNestingLevel;      // 0 if outside blocks and structures
+    int controlFlowNestingLevel; // 0 if outside all flow control
+    int statementNestingLevel;   // 0 if outside all flow control or compound statements
+    TList<TIntermSequence*> switchSequenceStack;  // case, node, case, case, node, ...; ensure only one node between cases;   stack of them for nesting
+    TList<int> switchLevel;      // the statementNestingLevel the current switch statement is at, which must match the level of its case statements
+    bool inMain;                 // if inside a function, true if the function is main
+    bool postMainReturn;         // if inside a function, true if the function is main and this is after a return statement
+    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
+    const TString* blockName;
+    TQualifier currentBlockQualifier;
+    TPrecisionQualifier defaultPrecision[EbtNumTypes];
+    TBuiltInResource resources;
+    TLimits& limits;
+
+protected:
+    TParseContext(TParseContext&);
+    TParseContext& operator=(TParseContext&);
+
+    static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex()
+    TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
+    TPrecisionManager precisionManager;
+    TQualifier globalBufferDefaults;
+    TQualifier globalUniformDefaults;
+    TQualifier globalInputDefaults;
+    TQualifier globalOutputDefaults;
+    int* atomicUintOffsets;       // to become an array of the right size to hold an offset per binding point
+    TString currentCaller;        // name of last function body entered (not valid when at global scope)
+    TIdSetType inductiveLoopIds;
+    bool anyIndexLimits;
+    TVector<TIntermTyped*> needsIndexLimitationChecking;
+
+    //
+    // Geometry shader input arrays:
+    //  - array sizing is based on input primitive and/or explicit size
+    //
+    // Tessellation control output arrays:
+    //  - array sizing is based on output layout(vertices=...) and/or explicit size
+    //
+    // Both:
+    //  - array sizing is retroactive
+    //  - built-in block redeclarations interact with this
+    //
+    // Design:
+    //  - use a per-context "resize-list", a list of symbols whose array sizes
+    //    can be fixed
+    //
+    //  - the resize-list starts empty at beginning of user-shader compilation, it does
+    //    not have built-ins in it
+    //
+    //  - on built-in array use: copyUp() symbol and add it to the resize-list
+    //
+    //  - on user array declaration: add it to the resize-list
+    //
+    //  - on block redeclaration: copyUp() symbol and add it to the resize-list
+    //     * note, that appropriately gives an error if redeclaring a block that
+    //       was already used and hence already copied-up
+    //
+    //  - on seeing a layout declaration that sizes the array, fix everything in the
+    //    resize-list, giving errors for mismatch
+    //
+    //  - on seeing an array size declaration, give errors on mismatch between it and previous
+    //    array-sizing declarations
+    //
+    TVector<TSymbol*> ioArraySymbolResizeList;
+};
+
+} // end namespace glslang
+
+#endif // _PARSER_HELPER_INCLUDED_

+ 345 - 0
src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp

@@ -0,0 +1,345 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "../Include/PoolAlloc.h"
+
+#include "../Include/InitializeGlobals.h"
+#include "../OSDependent/osinclude.h"
+
+namespace glslang {
+
+OS_TLSIndex PoolIndex;
+
+void InitializeMemoryPools()
+{
+    TThreadMemoryPools* pools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
+    if (pools)
+        return;
+
+    TPoolAllocator *threadPoolAllocator = new TPoolAllocator();
+
+    TThreadMemoryPools* threadData = new TThreadMemoryPools();
+
+    threadData->threadPoolAllocator = threadPoolAllocator;
+
+    OS_SetTLSValue(PoolIndex, threadData);
+}
+
+void FreeGlobalPools()
+{
+    // Release the allocated memory for this thread.
+    TThreadMemoryPools* globalPools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
+    if (! globalPools)
+        return;
+
+    GetThreadPoolAllocator().popAll();
+    delete &GetThreadPoolAllocator();
+    delete globalPools;
+}
+
+bool InitializePoolIndex()
+{
+    // Allocate a TLS index.
+    if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX)
+        return false;
+
+    return true;
+}
+
+void FreePoolIndex()
+{
+    // Release the TLS index.
+    OS_FreeTLSIndex(PoolIndex);
+}
+
+TPoolAllocator& GetThreadPoolAllocator()
+{
+    TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
+
+    return *threadData->threadPoolAllocator;
+}
+
+void SetThreadPoolAllocator(TPoolAllocator& poolAllocator)
+{
+    TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
+
+    threadData->threadPoolAllocator = &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)
+{
+    //
+    // 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.
+    //
+    size_t minAlign = sizeof(void*);
+    alignment &= ~(minAlign - 1);
+    if (alignment < minAlign)
+        alignment = minAlign;
+    size_t a = 1;
+    while (a < alignment)
+        a <<= 1;
+    alignment = a;
+    alignmentMask = a - 1;
+
+    //
+    // Align header skip
+    //
+    headerSkip = minAlign;
+    if (headerSkip < sizeof(tHeader)) {
+        headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+    }
+
+    push();
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+    while (inUseList) {
+        tHeader* next = inUseList->nextPage;
+        inUseList->~tHeader();
+        delete [] reinterpret_cast<char*>(inUseList);
+        inUseList = next;
+    }
+
+    //
+    // Always delete the free list memory - it can't be being
+    // (correctly) referenced, whether the pool allocator was
+    // global or not.  We should not check the guard blocks
+    // here, because we did it already when the block was
+    // placed into the free list.
+    //
+    while (freeList) {
+        tHeader* next = freeList->nextPage;
+        delete [] reinterpret_cast<char*>(freeList);
+        freeList = next;
+    }
+}
+
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal   = 0xfe;
+const unsigned char TAllocation::userDataFill       = 0xcd;
+
+#   ifdef GUARD_BLOCKS
+    const size_t TAllocation::guardBlockSize = 16;
+#   else
+    const size_t TAllocation::guardBlockSize = 0;
+#   endif
+
+//
+// Check a single guard block for damage
+//
+#ifdef GUARD_BLOCKS
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+#else
+void TAllocation::checkGuardBlock(unsigned char*, unsigned char, const char*) const
+#endif
+{
+#ifdef GUARD_BLOCKS
+    for (size_t x = 0; x < guardBlockSize; x++) {
+        if (blockMem[x] != val) {
+            const int maxSize = 80;
+            char assertMsg[maxSize];
+
+            // We don't print the assert message.  It's here just to be helpful.
+            snprintf(assertMsg, maxSize, "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
+                      locText, size, data());
+            assert(0 && "PoolAlloc: Damage in guard block");
+        }
+    }
+#else
+    assert(guardBlockSize == 0);
+#endif
+}
+
+void TPoolAllocator::push()
+{
+    tAllocState state = { currentPageOffset, inUseList };
+
+    stack.push_back(state);
+
+    //
+    // Indicate there is no current page to allocate from.
+    //
+    currentPageOffset = pageSize;
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+    if (stack.size() < 1)
+        return;
+
+    tHeader* page = stack.back().page;
+    currentPageOffset = stack.back().offset;
+
+    while (inUseList != page) {
+        // invoke destructor to free allocation list
+        inUseList->~tHeader();
+
+        tHeader* nextInUse = inUseList->nextPage;
+        if (inUseList->pageCount > 1)
+            delete [] reinterpret_cast<char*>(inUseList);
+        else {
+            inUseList->nextPage = freeList;
+            freeList = inUseList;
+        }
+        inUseList = nextInUse;
+    }
+
+    stack.pop_back();
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+    while (stack.size() > 0)
+        pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+    // If we are using guard blocks, all allocations are bracketed by
+    // them: [guardblock][allocation][guardblock].  numBytes is how
+    // much memory the caller asked for.  allocationSize is the total
+    // size including guard blocks.  In release build,
+    // guardBlockSize=0 and this all gets optimized away.
+    size_t allocationSize = TAllocation::allocationSize(numBytes);
+
+    //
+    // Just keep some interesting statistics.
+    //
+    ++numCalls;
+    totalBytes += numBytes;
+
+    //
+    // Do the allocation, most likely case first, for efficiency.
+    // This step could be moved to be inline sometime.
+    //
+    if (currentPageOffset + allocationSize <= pageSize) {
+        //
+        // Safe to allocate from currentPageOffset.
+        //
+        unsigned char* memory = reinterpret_cast<unsigned char*>(inUseList) + currentPageOffset;
+        currentPageOffset += allocationSize;
+        currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+        return initializeAllocation(inUseList, memory, numBytes);
+    }
+
+    if (allocationSize + headerSkip > pageSize) {
+        //
+        // Do a multi-page allocation.  Don't mix these with the others.
+        // The OS is efficient and allocating and free-ing multiple pages.
+        //
+        size_t numBytesToAlloc = allocationSize + headerSkip;
+        tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+        if (memory == 0)
+            return 0;
+
+        // Use placement-new to initialize header
+        new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+        inUseList = memory;
+
+        currentPageOffset = pageSize;  // make next allocation come from a new page
+
+        // No guard blocks for multi-page allocations (yet)
+        return reinterpret_cast<void*>(reinterpret_cast<UINT_PTR>(memory) + headerSkip);
+    }
+
+    //
+    // Need a simple page to allocate from.
+    //
+    tHeader* memory;
+    if (freeList) {
+        memory = freeList;
+        freeList = freeList->nextPage;
+    } else {
+        memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+        if (memory == 0)
+            return 0;
+    }
+
+    // Use placement-new to initialize header
+    new(memory) tHeader(inUseList, 1);
+    inUseList = memory;
+
+    unsigned char* ret = reinterpret_cast<unsigned char*>(inUseList) + headerSkip;
+    currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+    return initializeAllocation(inUseList, ret, numBytes);
+}
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+    for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+        alloc->check();
+}
+
+} // end namespace glslang

+ 118 - 0
src/libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp

@@ -0,0 +1,118 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/intermediate.h"
+#include "RemoveTree.h"
+
+namespace glslang {
+
+//
+// Code to recursively delete the intermediate tree.
+//
+struct TRemoveTraverser : TIntermTraverser {
+    TRemoveTraverser() : TIntermTraverser(false, false, true, false) {}
+
+    virtual void visitSymbol(TIntermSymbol* node)
+    {
+        delete node;
+    }
+
+    virtual bool visitBinary(TVisit /* visit*/ , TIntermBinary* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual bool visitUnary(TVisit /* visit */, TIntermUnary* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual bool visitAggregate(TVisit /* visit*/ , TIntermAggregate* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual bool visitSelection(TVisit /* visit*/ , TIntermSelection* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual bool visitSwitch(TVisit /* visit*/ , TIntermSwitch* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual void visitConstantUnion(TIntermConstantUnion* node)
+    {
+        delete node;
+    }
+
+    virtual bool visitLoop(TVisit /* visit*/ , TIntermLoop* node)
+    {
+        delete node;
+
+        return true;
+    }
+
+    virtual bool visitBranch(TVisit /* visit*/ , TIntermBranch* node)
+    {
+        delete node;
+
+        return true;
+    }
+};
+
+//
+// Entry point.
+//
+void RemoveAllTreeNodes(TIntermNode* root)
+{
+    TRemoveTraverser it;
+
+    root->traverse(&it);
+}
+
+} // end namespace glslang

+ 39 - 0
src/libraries/glslang/glslang/MachineIndependent/RemoveTree.h

@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+namespace glslang {
+
+void RemoveAllTreeNodes(TIntermNode*);
+
+} // end namespace glslang

+ 1395 - 0
src/libraries/glslang/glslang/MachineIndependent/Scan.cpp

@@ -0,0 +1,1395 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// GLSL scanning, leveraging the scanning done by the preprocessor.
+//
+
+#include <cstring>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "../Include/Types.h"
+#include "SymbolTable.h"
+#include "ParseHelper.h"
+#include "glslang_tab.cpp.h"
+#include "ScanContext.h"
+#include "Scan.h"
+
+// preprocessor includes
+#include "preprocessor/PpContext.h"
+#include "preprocessor/PpTokens.h"
+
+// Required to avoid missing prototype warnings for some compilers
+int yylex(YYSTYPE*, glslang::TParseContext&);
+
+namespace glslang {
+
+// read past any white space
+void TInputScanner::consumeWhiteSpace(bool& foundNonSpaceTab)
+{
+    int c = peek();  // don't accidentally consume anything other than whitespace
+    while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+        if (c == '\r' || c == '\n')
+            foundNonSpaceTab = true;
+        get();
+        c = peek();
+    }
+}
+
+// return true if a comment was actually consumed
+bool TInputScanner::consumeComment()
+{
+    if (peek() != '/')
+        return false;
+
+    get();  // consume the '/'
+    int c = peek();
+    if (c == '/') {
+
+        // a '//' style comment
+        get();  // consume the second '/'
+        c = get();
+        do {
+            while (c != EndOfInput && c != '\\' && c != '\r' && c != '\n')
+                c = get();
+
+            if (c == EndOfInput || c == '\r' || c == '\n') {
+                while (c == '\r' || c == '\n')
+                    c = get();
+
+                // we reached the end of the comment
+                break;
+            } else {
+                // it's a '\', so we need to keep going, after skipping what's escaped
+
+                // read the skipped character
+                c = get();
+
+                // if it's a two-character newline, skip both characters
+                if (c == '\r' && peek() == '\n')
+                    get();
+                c = get();
+            }
+        } while (true);
+
+        // put back the last non-comment character
+        if (c != EndOfInput)
+            unget();
+
+        return true;
+    } else if (c == '*') {
+
+        // a '/*' style comment
+        get();  // consume the '*'
+        c = get();
+        do {
+            while (c != EndOfInput && c != '*')
+                c = get();
+            if (c == '*') {
+                c = get();
+                if (c == '/')
+                    break;  // end of comment
+                // not end of comment
+            } else // end of input
+                break;
+        } while (true);
+
+        return true;
+    } else {
+        // it's not a comment, put the '/' back
+        unget();
+
+        return false;
+    }
+}
+
+// skip whitespace, then skip a comment, rinse, repeat
+void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
+{
+    do {
+        consumeWhiteSpace(foundNonSpaceTab);
+
+        // if not starting a comment now, then done
+        int c = peek();
+        if (c != '/' || c == EndOfInput)
+            return;
+
+        // skip potential comment
+        foundNonSpaceTab = true;
+        if (! consumeComment())
+            return;
+
+    } while (true);
+}
+
+// Returns true if there was non-white space (e.g., a comment, newline) before the #version
+// or no #version was found; otherwise, returns false.  There is no error case, it always
+// succeeds, but will leave version == 0 if no #version was found.
+//
+// Sets notFirstToken based on whether tokens (beyond white space and comments)
+// appeared before the #version.
+//
+// N.B. does not attempt to leave input in any particular known state.  The assumption
+// is that scanning will start anew, following the rules for the chosen version/profile,
+// and with a corresponding parsing context.
+//
+bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstToken)
+{
+    // This function doesn't have to get all the semantics correct,
+    // just find the #version if there is a correct one present.
+    // The preprocessor will have the responsibility of getting all the semantics right.
+
+    bool versionNotFirst = false;  // means not first WRT comments and white space, nothing more
+    notFirstToken = false;         // means not first WRT to real tokens
+    version = 0;  // means not found
+    profile = ENoProfile;
+
+    bool foundNonSpaceTab = false;
+    bool lookingInMiddle = false;
+    int c;
+    do {
+        if (lookingInMiddle) {
+            notFirstToken = true;
+            // make forward progress by finishing off the current line plus extra new lines
+            if (peek() == '\n' || peek() == '\r') {
+                while (peek() == '\n' || peek() == '\r')
+                    get();
+            } else
+                do {
+                    c = get();
+                } while (c != EndOfInput && c != '\n' && c != '\r');
+                while (peek() == '\n' || peek() == '\r')
+                    get();
+                if (peek() == EndOfInput)
+                    return true;
+        }
+        lookingInMiddle = true;
+
+        // Nominal start, skipping the desktop allowed comments and white space, but tracking if
+        // something else was found for ES:
+        consumeWhitespaceComment(foundNonSpaceTab);
+        if (foundNonSpaceTab)
+            versionNotFirst = true;
+
+        // "#"
+        if (get() != '#') {
+            versionNotFirst = true;
+            continue;
+        }
+
+        // whitespace
+        do {
+            c = get();
+        } while (c == ' ' || c == '\t');
+
+        // "version"
+        if (    c != 'v' ||
+            get() != 'e' ||
+            get() != 'r' ||
+            get() != 's' ||
+            get() != 'i' ||
+            get() != 'o' ||
+            get() != 'n') {
+            versionNotFirst = true;
+            continue;
+        }
+
+        // whitespace
+        do {
+            c = get();
+        } while (c == ' ' || c == '\t');
+
+        // version number
+        while (c >= '0' && c <= '9') {
+            version = 10 * version + (c - '0');
+            c = get();
+        }
+        if (version == 0) {
+            versionNotFirst = true;
+            continue;
+        }
+
+        // whitespace
+        while (c == ' ' || c == '\t')
+            c = get();
+
+        // profile
+        const int maxProfileLength = 13;  // not including any 0
+        char profileString[maxProfileLength];
+        int profileLength;
+        for (profileLength = 0; profileLength < maxProfileLength; ++profileLength) {
+            if (c == EndOfInput || c == ' ' || c == '\t' || c == '\n' || c == '\r')
+                break;
+            profileString[profileLength] = (char)c;
+            c = get();
+        }
+        if (c != EndOfInput && c != ' ' && c != '\t' && c != '\n' && c != '\r') {
+            versionNotFirst = true;
+            continue;
+        }
+
+        if (profileLength == 2 && strncmp(profileString, "es", profileLength) == 0)
+            profile = EEsProfile;
+        else if (profileLength == 4 && strncmp(profileString, "core", profileLength) == 0)
+            profile = ECoreProfile;
+        else if (profileLength == 13 && strncmp(profileString, "compatibility", profileLength) == 0)
+            profile = ECompatibilityProfile;
+
+        return versionNotFirst;
+    } while (true);
+}
+
+// Fill this in when doing glslang-level scanning, to hand back to the parser.
+class TParserToken {
+public:
+    explicit TParserToken(YYSTYPE& b) : sType(b) { }
+
+    YYSTYPE& sType;
+protected:
+    TParserToken(TParserToken&);
+    TParserToken& operator=(TParserToken&);
+};
+
+} // end namespace glslang
+
+// This is the function the glslang parser (i.e., bison) calls to get its next token
+int yylex(YYSTYPE* glslangTokenDesc, glslang::TParseContext& parseContext)
+{
+    glslang::TParserToken token(*glslangTokenDesc);
+
+    return parseContext.getScanContext()->tokenize(parseContext.getPpContext(), token);
+}
+
+namespace {
+
+struct str_eq
+{
+    bool operator()(const char* lhs, const char* rhs) const
+    {
+        return strcmp(lhs, rhs) == 0;
+    }
+};
+
+struct str_hash
+{
+    size_t operator()(const char* str) const
+    {
+        // djb2
+        unsigned long hash = 5381;
+        int c;
+
+        while ((c = *str++) != 0)
+            hash = ((hash << 5) + hash) + c;
+
+        return hash;
+    }
+};
+
+// A single global usable by all threads, by all versions, by all languages.
+// After a single process-level initialization, this is read only and thread safe
+std::unordered_map<const char*, int, str_hash, str_eq>* KeywordMap = nullptr;
+std::unordered_set<const char*, str_hash, str_eq>* ReservedSet = nullptr;
+
+};
+
+namespace glslang {
+
+void TScanContext::fillInKeywordMap()
+{
+    if (KeywordMap != nullptr) {
+        // this is really an error, as this should called only once per process
+        // but, the only risk is if two threads called simultaneously
+        return;
+    }
+    KeywordMap = new std::unordered_map<const char*, int, str_hash, str_eq>;
+
+    (*KeywordMap)["const"] =                   CONST;
+    (*KeywordMap)["uniform"] =                 UNIFORM;
+    (*KeywordMap)["in"] =                      IN;
+    (*KeywordMap)["out"] =                     OUT;
+    (*KeywordMap)["inout"] =                   INOUT;
+    (*KeywordMap)["struct"] =                  STRUCT;
+    (*KeywordMap)["break"] =                   BREAK;
+    (*KeywordMap)["continue"] =                CONTINUE;
+    (*KeywordMap)["do"] =                      DO;
+    (*KeywordMap)["for"] =                     FOR;
+    (*KeywordMap)["while"] =                   WHILE;
+    (*KeywordMap)["switch"] =                  SWITCH;
+    (*KeywordMap)["case"] =                    CASE;
+    (*KeywordMap)["default"] =                 DEFAULT;
+    (*KeywordMap)["if"] =                      IF;
+    (*KeywordMap)["else"] =                    ELSE;
+    (*KeywordMap)["discard"] =                 DISCARD;
+    (*KeywordMap)["return"] =                  RETURN;
+    (*KeywordMap)["void"] =                    VOID;
+    (*KeywordMap)["bool"] =                    BOOL;
+    (*KeywordMap)["float"] =                   FLOAT;
+    (*KeywordMap)["int"] =                     INT;
+    (*KeywordMap)["bvec2"] =                   BVEC2;
+    (*KeywordMap)["bvec3"] =                   BVEC3;
+    (*KeywordMap)["bvec4"] =                   BVEC4;
+    (*KeywordMap)["vec2"] =                    VEC2;
+    (*KeywordMap)["vec3"] =                    VEC3;
+    (*KeywordMap)["vec4"] =                    VEC4;
+    (*KeywordMap)["ivec2"] =                   IVEC2;
+    (*KeywordMap)["ivec3"] =                   IVEC3;
+    (*KeywordMap)["ivec4"] =                   IVEC4;
+    (*KeywordMap)["mat2"] =                    MAT2;
+    (*KeywordMap)["mat3"] =                    MAT3;
+    (*KeywordMap)["mat4"] =                    MAT4;
+    (*KeywordMap)["true"] =                    BOOLCONSTANT;
+    (*KeywordMap)["false"] =                   BOOLCONSTANT;
+    (*KeywordMap)["attribute"] =               ATTRIBUTE;
+    (*KeywordMap)["varying"] =                 VARYING;
+    (*KeywordMap)["buffer"] =                  BUFFER;
+    (*KeywordMap)["coherent"] =                COHERENT;
+    (*KeywordMap)["restrict"] =                RESTRICT;
+    (*KeywordMap)["readonly"] =                READONLY;
+    (*KeywordMap)["writeonly"] =               WRITEONLY;
+    (*KeywordMap)["atomic_uint"] =             ATOMIC_UINT;
+    (*KeywordMap)["volatile"] =                VOLATILE;
+    (*KeywordMap)["layout"] =                  LAYOUT;
+    (*KeywordMap)["shared"] =                  SHARED;
+    (*KeywordMap)["patch"] =                   PATCH;
+    (*KeywordMap)["sample"] =                  SAMPLE;
+    (*KeywordMap)["subroutine"] =              SUBROUTINE;
+    (*KeywordMap)["highp"] =                   HIGH_PRECISION;
+    (*KeywordMap)["mediump"] =                 MEDIUM_PRECISION;
+    (*KeywordMap)["lowp"] =                    LOW_PRECISION;
+    (*KeywordMap)["precision"] =               PRECISION;
+    (*KeywordMap)["mat2x2"] =                  MAT2X2;
+    (*KeywordMap)["mat2x3"] =                  MAT2X3;
+    (*KeywordMap)["mat2x4"] =                  MAT2X4;
+    (*KeywordMap)["mat3x2"] =                  MAT3X2;
+    (*KeywordMap)["mat3x3"] =                  MAT3X3;
+    (*KeywordMap)["mat3x4"] =                  MAT3X4;
+    (*KeywordMap)["mat4x2"] =                  MAT4X2;
+    (*KeywordMap)["mat4x3"] =                  MAT4X3;
+    (*KeywordMap)["mat4x4"] =                  MAT4X4;
+    (*KeywordMap)["dmat2"] =                   DMAT2;
+    (*KeywordMap)["dmat3"] =                   DMAT3;
+    (*KeywordMap)["dmat4"] =                   DMAT4;
+    (*KeywordMap)["dmat2x2"] =                 DMAT2X2;
+    (*KeywordMap)["dmat2x3"] =                 DMAT2X3;
+    (*KeywordMap)["dmat2x4"] =                 DMAT2X4;
+    (*KeywordMap)["dmat3x2"] =                 DMAT3X2;
+    (*KeywordMap)["dmat3x3"] =                 DMAT3X3;
+    (*KeywordMap)["dmat3x4"] =                 DMAT3X4;
+    (*KeywordMap)["dmat4x2"] =                 DMAT4X2;
+    (*KeywordMap)["dmat4x3"] =                 DMAT4X3;
+    (*KeywordMap)["dmat4x4"] =                 DMAT4X4;
+    (*KeywordMap)["image1D"] =                 IMAGE1D;
+    (*KeywordMap)["iimage1D"] =                IIMAGE1D;
+    (*KeywordMap)["uimage1D"] =                UIMAGE1D;
+    (*KeywordMap)["image2D"] =                 IMAGE2D;
+    (*KeywordMap)["iimage2D"] =                IIMAGE2D;
+    (*KeywordMap)["uimage2D"] =                UIMAGE2D;
+    (*KeywordMap)["image3D"] =                 IMAGE3D;
+    (*KeywordMap)["iimage3D"] =                IIMAGE3D;
+    (*KeywordMap)["uimage3D"] =                UIMAGE3D;
+    (*KeywordMap)["image2DRect"] =             IMAGE2DRECT;
+    (*KeywordMap)["iimage2DRect"] =            IIMAGE2DRECT;
+    (*KeywordMap)["uimage2DRect"] =            UIMAGE2DRECT;
+    (*KeywordMap)["imageCube"] =               IMAGECUBE;
+    (*KeywordMap)["iimageCube"] =              IIMAGECUBE;
+    (*KeywordMap)["uimageCube"] =              UIMAGECUBE;
+    (*KeywordMap)["imageBuffer"] =             IMAGEBUFFER;
+    (*KeywordMap)["iimageBuffer"] =            IIMAGEBUFFER;
+    (*KeywordMap)["uimageBuffer"] =            UIMAGEBUFFER;
+    (*KeywordMap)["image1DArray"] =            IMAGE1DARRAY;
+    (*KeywordMap)["iimage1DArray"] =           IIMAGE1DARRAY;
+    (*KeywordMap)["uimage1DArray"] =           UIMAGE1DARRAY;
+    (*KeywordMap)["image2DArray"] =            IMAGE2DARRAY;
+    (*KeywordMap)["iimage2DArray"] =           IIMAGE2DARRAY;
+    (*KeywordMap)["uimage2DArray"] =           UIMAGE2DARRAY;
+    (*KeywordMap)["imageCubeArray"] =          IMAGECUBEARRAY;
+    (*KeywordMap)["iimageCubeArray"] =         IIMAGECUBEARRAY;
+    (*KeywordMap)["uimageCubeArray"] =         UIMAGECUBEARRAY;
+    (*KeywordMap)["image2DMS"] =               IMAGE2DMS;
+    (*KeywordMap)["iimage2DMS"] =              IIMAGE2DMS;
+    (*KeywordMap)["uimage2DMS"] =              UIMAGE2DMS;
+    (*KeywordMap)["image2DMSArray"] =          IMAGE2DMSARRAY;
+    (*KeywordMap)["iimage2DMSArray"] =         IIMAGE2DMSARRAY;
+    (*KeywordMap)["uimage2DMSArray"] =         UIMAGE2DMSARRAY;
+    (*KeywordMap)["double"] =                  DOUBLE;
+    (*KeywordMap)["dvec2"] =                   DVEC2;
+    (*KeywordMap)["dvec3"] =                   DVEC3;
+    (*KeywordMap)["dvec4"] =                   DVEC4;
+    (*KeywordMap)["uint"] =                    UINT;
+    (*KeywordMap)["uvec2"] =                   UVEC2;
+    (*KeywordMap)["uvec3"] =                   UVEC3;
+    (*KeywordMap)["uvec4"] =                   UVEC4;
+
+    (*KeywordMap)["int64_t"] =                 INT64_T;
+    (*KeywordMap)["uint64_t"] =                UINT64_T;
+    (*KeywordMap)["i64vec2"] =                 I64VEC2;
+    (*KeywordMap)["i64vec3"] =                 I64VEC3;
+    (*KeywordMap)["i64vec4"] =                 I64VEC4;
+    (*KeywordMap)["u64vec2"] =                 U64VEC2;
+    (*KeywordMap)["u64vec3"] =                 U64VEC3;
+    (*KeywordMap)["u64vec4"] =                 U64VEC4;
+
+#ifdef AMD_EXTENSIONS
+    (*KeywordMap)["float16_t"] =               FLOAT16_T;
+    (*KeywordMap)["f16vec2"] =                 F16VEC2;
+    (*KeywordMap)["f16vec3"] =                 F16VEC3;
+    (*KeywordMap)["f16vec4"] =                 F16VEC4;
+    (*KeywordMap)["f16mat2"] =                 F16MAT2;
+    (*KeywordMap)["f16mat3"] =                 F16MAT3;
+    (*KeywordMap)["f16mat4"] =                 F16MAT4;
+    (*KeywordMap)["f16mat2x2"] =               F16MAT2X2;
+    (*KeywordMap)["f16mat2x3"] =               F16MAT2X3;
+    (*KeywordMap)["f16mat2x4"] =               F16MAT2X4;
+    (*KeywordMap)["f16mat3x2"] =               F16MAT3X2;
+    (*KeywordMap)["f16mat3x3"] =               F16MAT3X3;
+    (*KeywordMap)["f16mat3x4"] =               F16MAT3X4;
+    (*KeywordMap)["f16mat4x2"] =               F16MAT4X2;
+    (*KeywordMap)["f16mat4x3"] =               F16MAT4X3;
+    (*KeywordMap)["f16mat4x4"] =               F16MAT4X4;
+#endif
+
+    (*KeywordMap)["sampler2D"] =               SAMPLER2D;
+    (*KeywordMap)["samplerCube"] =             SAMPLERCUBE;
+    (*KeywordMap)["samplerCubeArray"] =        SAMPLERCUBEARRAY;
+    (*KeywordMap)["samplerCubeArrayShadow"] =  SAMPLERCUBEARRAYSHADOW;
+    (*KeywordMap)["isamplerCubeArray"] =       ISAMPLERCUBEARRAY;
+    (*KeywordMap)["usamplerCubeArray"] =       USAMPLERCUBEARRAY;
+    (*KeywordMap)["sampler1DArrayShadow"] =    SAMPLER1DARRAYSHADOW;
+    (*KeywordMap)["isampler1DArray"] =         ISAMPLER1DARRAY;
+    (*KeywordMap)["usampler1D"] =              USAMPLER1D;
+    (*KeywordMap)["isampler1D"] =              ISAMPLER1D;
+    (*KeywordMap)["usampler1DArray"] =         USAMPLER1DARRAY;
+    (*KeywordMap)["samplerBuffer"] =           SAMPLERBUFFER;
+    (*KeywordMap)["samplerCubeShadow"] =       SAMPLERCUBESHADOW;
+    (*KeywordMap)["sampler2DArray"] =          SAMPLER2DARRAY;
+    (*KeywordMap)["sampler2DArrayShadow"] =    SAMPLER2DARRAYSHADOW;
+    (*KeywordMap)["isampler2D"] =              ISAMPLER2D;
+    (*KeywordMap)["isampler3D"] =              ISAMPLER3D;
+    (*KeywordMap)["isamplerCube"] =            ISAMPLERCUBE;
+    (*KeywordMap)["isampler2DArray"] =         ISAMPLER2DARRAY;
+    (*KeywordMap)["usampler2D"] =              USAMPLER2D;
+    (*KeywordMap)["usampler3D"] =              USAMPLER3D;
+    (*KeywordMap)["usamplerCube"] =            USAMPLERCUBE;
+    (*KeywordMap)["usampler2DArray"] =         USAMPLER2DARRAY;
+    (*KeywordMap)["isampler2DRect"] =          ISAMPLER2DRECT;
+    (*KeywordMap)["usampler2DRect"] =          USAMPLER2DRECT;
+    (*KeywordMap)["isamplerBuffer"] =          ISAMPLERBUFFER;
+    (*KeywordMap)["usamplerBuffer"] =          USAMPLERBUFFER;
+    (*KeywordMap)["sampler2DMS"] =             SAMPLER2DMS;
+    (*KeywordMap)["isampler2DMS"] =            ISAMPLER2DMS;
+    (*KeywordMap)["usampler2DMS"] =            USAMPLER2DMS;
+    (*KeywordMap)["sampler2DMSArray"] =        SAMPLER2DMSARRAY;
+    (*KeywordMap)["isampler2DMSArray"] =       ISAMPLER2DMSARRAY;
+    (*KeywordMap)["usampler2DMSArray"] =       USAMPLER2DMSARRAY;
+    (*KeywordMap)["sampler1D"] =               SAMPLER1D;
+    (*KeywordMap)["sampler1DShadow"] =         SAMPLER1DSHADOW;
+    (*KeywordMap)["sampler3D"] =               SAMPLER3D;
+    (*KeywordMap)["sampler2DShadow"] =         SAMPLER2DSHADOW;
+    (*KeywordMap)["sampler2DRect"] =           SAMPLER2DRECT;
+    (*KeywordMap)["sampler2DRectShadow"] =     SAMPLER2DRECTSHADOW;
+    (*KeywordMap)["sampler1DArray"] =          SAMPLER1DARRAY;
+
+    (*KeywordMap)["samplerExternalOES"] =      SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
+
+    (*KeywordMap)["sampler"] =                 SAMPLER;
+    (*KeywordMap)["samplerShadow"] =           SAMPLERSHADOW;
+
+    (*KeywordMap)["texture2D"] =               TEXTURE2D;
+    (*KeywordMap)["textureCube"] =             TEXTURECUBE;
+    (*KeywordMap)["textureCubeArray"] =        TEXTURECUBEARRAY;
+    (*KeywordMap)["itextureCubeArray"] =       ITEXTURECUBEARRAY;
+    (*KeywordMap)["utextureCubeArray"] =       UTEXTURECUBEARRAY;
+    (*KeywordMap)["itexture1DArray"] =         ITEXTURE1DARRAY;
+    (*KeywordMap)["utexture1D"] =              UTEXTURE1D;
+    (*KeywordMap)["itexture1D"] =              ITEXTURE1D;
+    (*KeywordMap)["utexture1DArray"] =         UTEXTURE1DARRAY;
+    (*KeywordMap)["textureBuffer"] =           TEXTUREBUFFER;
+    (*KeywordMap)["texture2DArray"] =          TEXTURE2DARRAY;
+    (*KeywordMap)["itexture2D"] =              ITEXTURE2D;
+    (*KeywordMap)["itexture3D"] =              ITEXTURE3D;
+    (*KeywordMap)["itextureCube"] =            ITEXTURECUBE;
+    (*KeywordMap)["itexture2DArray"] =         ITEXTURE2DARRAY;
+    (*KeywordMap)["utexture2D"] =              UTEXTURE2D;
+    (*KeywordMap)["utexture3D"] =              UTEXTURE3D;
+    (*KeywordMap)["utextureCube"] =            UTEXTURECUBE;
+    (*KeywordMap)["utexture2DArray"] =         UTEXTURE2DARRAY;
+    (*KeywordMap)["itexture2DRect"] =          ITEXTURE2DRECT;
+    (*KeywordMap)["utexture2DRect"] =          UTEXTURE2DRECT;
+    (*KeywordMap)["itextureBuffer"] =          ITEXTUREBUFFER;
+    (*KeywordMap)["utextureBuffer"] =          UTEXTUREBUFFER;
+    (*KeywordMap)["texture2DMS"] =             TEXTURE2DMS;
+    (*KeywordMap)["itexture2DMS"] =            ITEXTURE2DMS;
+    (*KeywordMap)["utexture2DMS"] =            UTEXTURE2DMS;
+    (*KeywordMap)["texture2DMSArray"] =        TEXTURE2DMSARRAY;
+    (*KeywordMap)["itexture2DMSArray"] =       ITEXTURE2DMSARRAY;
+    (*KeywordMap)["utexture2DMSArray"] =       UTEXTURE2DMSARRAY;
+    (*KeywordMap)["texture1D"] =               TEXTURE1D;
+    (*KeywordMap)["texture3D"] =               TEXTURE3D;
+    (*KeywordMap)["texture2DRect"] =           TEXTURE2DRECT;
+    (*KeywordMap)["texture1DArray"] =          TEXTURE1DARRAY;
+
+    (*KeywordMap)["subpassInput"] =            SUBPASSINPUT;
+    (*KeywordMap)["subpassInputMS"] =          SUBPASSINPUTMS;
+    (*KeywordMap)["isubpassInput"] =           ISUBPASSINPUT;
+    (*KeywordMap)["isubpassInputMS"] =         ISUBPASSINPUTMS;
+    (*KeywordMap)["usubpassInput"] =           USUBPASSINPUT;
+    (*KeywordMap)["usubpassInputMS"] =         USUBPASSINPUTMS;
+
+    (*KeywordMap)["noperspective"] =           NOPERSPECTIVE;
+    (*KeywordMap)["smooth"] =                  SMOOTH;
+    (*KeywordMap)["flat"] =                    FLAT;
+#ifdef AMD_EXTENSIONS
+    (*KeywordMap)["__explicitInterpAMD"] =     __EXPLICITINTERPAMD;
+#endif
+    (*KeywordMap)["centroid"] =                CENTROID;
+    (*KeywordMap)["precise"] =                 PRECISE;
+    (*KeywordMap)["invariant"] =               INVARIANT;
+    (*KeywordMap)["packed"] =                  PACKED;
+    (*KeywordMap)["resource"] =                RESOURCE;
+    (*KeywordMap)["superp"] =                  SUPERP;
+
+    ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
+
+    ReservedSet->insert("common");
+    ReservedSet->insert("partition");
+    ReservedSet->insert("active");
+    ReservedSet->insert("asm");
+    ReservedSet->insert("class");
+    ReservedSet->insert("union");
+    ReservedSet->insert("enum");
+    ReservedSet->insert("typedef");
+    ReservedSet->insert("template");
+    ReservedSet->insert("this");
+    ReservedSet->insert("goto");
+    ReservedSet->insert("inline");
+    ReservedSet->insert("noinline");
+    ReservedSet->insert("public");
+    ReservedSet->insert("static");
+    ReservedSet->insert("extern");
+    ReservedSet->insert("external");
+    ReservedSet->insert("interface");
+    ReservedSet->insert("long");
+    ReservedSet->insert("short");
+    ReservedSet->insert("half");
+    ReservedSet->insert("fixed");
+    ReservedSet->insert("unsigned");
+    ReservedSet->insert("input");
+    ReservedSet->insert("output");
+    ReservedSet->insert("hvec2");
+    ReservedSet->insert("hvec3");
+    ReservedSet->insert("hvec4");
+    ReservedSet->insert("fvec2");
+    ReservedSet->insert("fvec3");
+    ReservedSet->insert("fvec4");
+    ReservedSet->insert("sampler3DRect");
+    ReservedSet->insert("filter");
+    ReservedSet->insert("sizeof");
+    ReservedSet->insert("cast");
+    ReservedSet->insert("namespace");
+    ReservedSet->insert("using");
+}
+
+void TScanContext::deleteKeywordMap()
+{
+    delete KeywordMap;
+    KeywordMap = nullptr;
+    delete ReservedSet;
+    ReservedSet = nullptr;
+}
+
+// Called by yylex to get the next token.
+// Returning 0 implies end of input.
+int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
+{
+    do {
+        parserToken = &token;
+        TPpToken ppToken;
+        int token = pp->tokenize(ppToken);
+        if (token == EndOfInput)
+            return 0;
+
+        tokenText = ppToken.name;
+        loc = ppToken.loc;
+        parserToken->sType.lex.loc = loc;
+        switch (token) {
+        case ';':  afterType = false;   return SEMICOLON;
+        case ',':  afterType = false;   return COMMA;
+        case ':':                       return COLON;
+        case '=':  afterType = false;   return EQUAL;
+        case '(':  afterType = false;   return LEFT_PAREN;
+        case ')':  afterType = false;   return RIGHT_PAREN;
+        case '.':  field = true;        return DOT;
+        case '!':                       return BANG;
+        case '-':                       return DASH;
+        case '~':                       return TILDE;
+        case '+':                       return PLUS;
+        case '*':                       return STAR;
+        case '/':                       return SLASH;
+        case '%':                       return PERCENT;
+        case '<':                       return LEFT_ANGLE;
+        case '>':                       return RIGHT_ANGLE;
+        case '|':                       return VERTICAL_BAR;
+        case '^':                       return CARET;
+        case '&':                       return AMPERSAND;
+        case '?':                       return QUESTION;
+        case '[':                       return LEFT_BRACKET;
+        case ']':                       return RIGHT_BRACKET;
+        case '{':                       return LEFT_BRACE;
+        case '}':                       return RIGHT_BRACE;
+        case '\\':
+            parseContext.error(loc, "illegal use of escape character", "\\", "");
+            break;
+
+        case PPAtomAddAssign:          return ADD_ASSIGN;
+        case PPAtomSubAssign:          return SUB_ASSIGN;
+        case PPAtomMulAssign:          return MUL_ASSIGN;
+        case PPAtomDivAssign:          return DIV_ASSIGN;
+        case PPAtomModAssign:          return MOD_ASSIGN;
+
+        case PpAtomRight:              return RIGHT_OP;
+        case PpAtomLeft:               return LEFT_OP;
+
+        case PpAtomRightAssign:        return RIGHT_ASSIGN;
+        case PpAtomLeftAssign:         return LEFT_ASSIGN;
+        case PpAtomAndAssign:          return AND_ASSIGN;
+        case PpAtomOrAssign:           return OR_ASSIGN;
+        case PpAtomXorAssign:          return XOR_ASSIGN;
+
+        case PpAtomAnd:                return AND_OP;
+        case PpAtomOr:                 return OR_OP;
+        case PpAtomXor:                return XOR_OP;
+
+        case PpAtomEQ:                 return EQ_OP;
+        case PpAtomGE:                 return GE_OP;
+        case PpAtomNE:                 return NE_OP;
+        case PpAtomLE:                 return LE_OP;
+
+        case PpAtomDecrement:          return DEC_OP;
+        case PpAtomIncrement:          return INC_OP;
+
+        case PpAtomConstInt:           parserToken->sType.lex.i   = ppToken.ival;       return INTCONSTANT;
+        case PpAtomConstUint:          parserToken->sType.lex.i   = ppToken.ival;       return UINTCONSTANT;
+        case PpAtomConstInt64:         parserToken->sType.lex.i64 = ppToken.i64val;     return INT64CONSTANT;
+        case PpAtomConstUint64:        parserToken->sType.lex.i64 = ppToken.i64val;     return UINT64CONSTANT;
+        case PpAtomConstFloat:         parserToken->sType.lex.d   = ppToken.dval;       return FLOATCONSTANT;
+        case PpAtomConstDouble:        parserToken->sType.lex.d   = ppToken.dval;       return DOUBLECONSTANT;
+#ifdef AMD_EXTENSIONS
+        case PpAtomConstFloat16:       parserToken->sType.lex.d   = ppToken.dval;       return FLOAT16CONSTANT;
+#endif
+        case PpAtomIdentifier:
+        {
+            int token = tokenizeIdentifier();
+            field = false;
+            return token;
+        }
+
+        case EndOfInput:               return 0;
+
+        default:
+            char buf[2];
+            buf[0] = (char)token;
+            buf[1] = 0;
+            parseContext.error(loc, "unexpected token", buf, "");
+            break;
+        }
+    } while (true);
+}
+
+int TScanContext::tokenizeIdentifier()
+{
+    if (ReservedSet->find(tokenText) != ReservedSet->end())
+        return reservedWord();
+
+    auto it = KeywordMap->find(tokenText);
+    if (it == KeywordMap->end()) {
+        // Should have an identifier of some sort
+        return identifierOrType();
+    }
+    keyword = it->second;
+
+    switch (keyword) {
+    case CONST:
+    case UNIFORM:
+    case IN:
+    case OUT:
+    case INOUT:
+    case STRUCT:
+    case BREAK:
+    case CONTINUE:
+    case DO:
+    case FOR:
+    case WHILE:
+    case IF:
+    case ELSE:
+    case DISCARD:
+    case RETURN:
+    case CASE:
+        return keyword;
+
+    case SWITCH:
+    case DEFAULT:
+        if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 130))
+            reservedWord();
+        return keyword;
+
+    case VOID:
+    case BOOL:
+    case FLOAT:
+    case INT:
+    case BVEC2:
+    case BVEC3:
+    case BVEC4:
+    case VEC2:
+    case VEC3:
+    case VEC4:
+    case IVEC2:
+    case IVEC3:
+    case IVEC4:
+    case MAT2:
+    case MAT3:
+    case MAT4:
+    case SAMPLER2D:
+    case SAMPLERCUBE:
+        afterType = true;
+        return keyword;
+
+    case BOOLCONSTANT:
+        if (strcmp("true", tokenText) == 0)
+            parserToken->sType.lex.b = true;
+        else
+            parserToken->sType.lex.b = false;
+        return keyword;
+
+    case ATTRIBUTE:
+    case VARYING:
+        if (parseContext.profile == EEsProfile && parseContext.version >= 300)
+            reservedWord();
+        return keyword;
+
+    case BUFFER:
+        if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 430))
+            return identifierOrType();
+        return keyword;
+
+    case ATOMIC_UINT:
+        if ((parseContext.profile == EEsProfile && parseContext.version >= 310) ||
+            parseContext.extensionTurnedOn(E_GL_ARB_shader_atomic_counters))
+            return keyword;
+        return es30ReservedFromGLSL(420);
+
+    case COHERENT:
+    case RESTRICT:
+    case READONLY:
+    case WRITEONLY:
+        if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+            return keyword;
+        return es30ReservedFromGLSL(parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store) ? 130 : 420);
+
+    case VOLATILE:
+        if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+            return keyword;
+        if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store))))
+            reservedWord();
+        return keyword;
+
+    case LAYOUT:
+    {
+        const int numLayoutExts = 2;
+        const char* layoutExts[numLayoutExts] = { E_GL_ARB_shading_language_420pack,
+                                                  E_GL_ARB_explicit_attrib_location };
+        if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 140 &&
+            ! parseContext.extensionsTurnedOn(numLayoutExts, layoutExts)))
+            return identifierOrType();
+        return keyword;
+    }
+    case SHARED:
+        if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 140))
+            return identifierOrType();
+        return keyword;
+
+    case PATCH:
+        if (parseContext.symbolTable.atBuiltInLevel() ||
+            (parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) ||
+            (parseContext.profile != EEsProfile && parseContext.extensionTurnedOn(E_GL_ARB_tessellation_shader)))
+            return keyword;
+
+        return es30ReservedFromGLSL(400);
+
+    case SAMPLE:
+        if (parseContext.extensionsTurnedOn(1, &E_GL_OES_shader_multisample_interpolation))
+            return keyword;
+        return es30ReservedFromGLSL(400);
+
+    case SUBROUTINE:
+        return es30ReservedFromGLSL(400);
+
+    case HIGH_PRECISION:
+    case MEDIUM_PRECISION:
+    case LOW_PRECISION:
+    case PRECISION:
+        return precisionKeyword();
+
+    case MAT2X2:
+    case MAT2X3:
+    case MAT2X4:
+    case MAT3X2:
+    case MAT3X3:
+    case MAT3X4:
+    case MAT4X2:
+    case MAT4X3:
+    case MAT4X4:
+        return matNxM();
+
+    case DMAT2:
+    case DMAT3:
+    case DMAT4:
+    case DMAT2X2:
+    case DMAT2X3:
+    case DMAT2X4:
+    case DMAT3X2:
+    case DMAT3X3:
+    case DMAT3X4:
+    case DMAT4X2:
+    case DMAT4X3:
+    case DMAT4X4:
+        return dMat();
+
+    case IMAGE1D:
+    case IIMAGE1D:
+    case UIMAGE1D:
+    case IMAGE1DARRAY:
+    case IIMAGE1DARRAY:
+    case UIMAGE1DARRAY:
+    case IMAGE2DRECT:
+    case IIMAGE2DRECT:
+    case UIMAGE2DRECT:
+        afterType = true;
+        return firstGenerationImage(false);
+
+    case IMAGEBUFFER:
+    case IIMAGEBUFFER:
+    case UIMAGEBUFFER:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
+            return keyword;
+        return firstGenerationImage(false);
+
+    case IMAGE2D:
+    case IIMAGE2D:
+    case UIMAGE2D:
+    case IMAGE3D:
+    case IIMAGE3D:
+    case UIMAGE3D:
+    case IMAGECUBE:
+    case IIMAGECUBE:
+    case UIMAGECUBE:
+    case IMAGE2DARRAY:
+    case IIMAGE2DARRAY:
+    case UIMAGE2DARRAY:
+        afterType = true;
+        return firstGenerationImage(true);
+
+    case IMAGECUBEARRAY:
+    case IIMAGECUBEARRAY:
+    case UIMAGECUBEARRAY:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
+            return keyword;
+        return secondGenerationImage();
+
+    case IMAGE2DMS:
+    case IIMAGE2DMS:
+    case UIMAGE2DMS:
+    case IMAGE2DMSARRAY:
+    case IIMAGE2DMSARRAY:
+    case UIMAGE2DMSARRAY:
+        afterType = true;
+        return secondGenerationImage();
+
+    case DOUBLE:
+    case DVEC2:
+    case DVEC3:
+    case DVEC4:
+        afterType = true;
+        if (parseContext.profile == EEsProfile || parseContext.version < 400)
+            reservedWord();
+        return keyword;
+
+    case INT64_T:
+    case UINT64_T:
+    case I64VEC2:
+    case I64VEC3:
+    case I64VEC4:
+    case U64VEC2:
+    case U64VEC3:
+    case U64VEC4:
+        afterType = true;
+        if (parseContext.symbolTable.atBuiltInLevel() ||
+            (parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64) &&
+             parseContext.profile != EEsProfile && parseContext.version >= 450))
+            return keyword;
+        return identifierOrType();
+
+#ifdef AMD_EXTENSIONS
+    case FLOAT16_T:
+    case F16VEC2:
+    case F16VEC3:
+    case F16VEC4:
+    case F16MAT2:
+    case F16MAT3:
+    case F16MAT4:
+    case F16MAT2X2:
+    case F16MAT2X3:
+    case F16MAT2X4:
+    case F16MAT3X2:
+    case F16MAT3X3:
+    case F16MAT3X4:
+    case F16MAT4X2:
+    case F16MAT4X3:
+    case F16MAT4X4:
+        afterType = true;
+        if (parseContext.symbolTable.atBuiltInLevel() ||
+            (parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float) &&
+             parseContext.profile != EEsProfile && parseContext.version >= 450))
+            return keyword;
+        return identifierOrType();
+#endif
+
+    case SAMPLERCUBEARRAY:
+    case SAMPLERCUBEARRAYSHADOW:
+    case ISAMPLERCUBEARRAY:
+    case USAMPLERCUBEARRAY:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
+            return keyword;
+        if (parseContext.profile == EEsProfile || (parseContext.version < 400 && ! parseContext.extensionTurnedOn(E_GL_ARB_texture_cube_map_array)))
+            reservedWord();
+        return keyword;
+
+    case ISAMPLER1D:
+    case ISAMPLER1DARRAY:
+    case SAMPLER1DARRAYSHADOW:
+    case USAMPLER1D:
+    case USAMPLER1DARRAY:
+        afterType = true;
+        return es30ReservedFromGLSL(130);
+
+    case UINT:
+    case UVEC2:
+    case UVEC3:
+    case UVEC4:
+    case SAMPLERCUBESHADOW:
+    case SAMPLER2DARRAY:
+    case SAMPLER2DARRAYSHADOW:
+    case ISAMPLER2D:
+    case ISAMPLER3D:
+    case ISAMPLERCUBE:
+    case ISAMPLER2DARRAY:
+    case USAMPLER2D:
+    case USAMPLER3D:
+    case USAMPLERCUBE:
+    case USAMPLER2DARRAY:
+        afterType = true;
+        return nonreservedKeyword(300, 130);
+
+    case ISAMPLER2DRECT:
+    case USAMPLER2DRECT:
+        afterType = true;
+        return es30ReservedFromGLSL(140);
+
+    case SAMPLERBUFFER:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
+            return keyword;
+        return es30ReservedFromGLSL(130);
+
+    case ISAMPLERBUFFER:
+    case USAMPLERBUFFER:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
+            return keyword;
+        return es30ReservedFromGLSL(140);
+
+    case SAMPLER2DMS:
+    case ISAMPLER2DMS:
+    case USAMPLER2DMS:
+        afterType = true;
+        if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+            return keyword;
+        return es30ReservedFromGLSL(150);
+
+    case SAMPLER2DMSARRAY:
+    case ISAMPLER2DMSARRAY:
+    case USAMPLER2DMSARRAY:
+        afterType = true;
+        if (parseContext.extensionsTurnedOn(1, &E_GL_OES_texture_storage_multisample_2d_array))
+            return keyword;
+        return es30ReservedFromGLSL(150);
+
+    case SAMPLER1D:
+    case SAMPLER1DSHADOW:
+        afterType = true;
+        if (parseContext.profile == EEsProfile)
+            reservedWord();
+        return keyword;
+
+    case SAMPLER3D:
+        afterType = true;
+        if (parseContext.profile == EEsProfile && parseContext.version < 300) {
+            if (! parseContext.extensionTurnedOn(E_GL_OES_texture_3D))
+                reservedWord();
+        }
+        return keyword;
+
+    case SAMPLER2DSHADOW:
+        afterType = true;
+        if (parseContext.profile == EEsProfile && parseContext.version < 300)
+            reservedWord();
+        return keyword;
+
+    case SAMPLER2DRECT:
+    case SAMPLER2DRECTSHADOW:
+        afterType = true;
+        if (parseContext.profile == EEsProfile)
+            reservedWord();
+        else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionTurnedOn(E_GL_ARB_texture_rectangle)) {
+            if (parseContext.relaxedErrors())
+                parseContext.requireExtensions(loc, 1, &E_GL_ARB_texture_rectangle, "texture-rectangle sampler keyword");
+            else
+                reservedWord();
+        }
+        return keyword;
+
+    case SAMPLER1DARRAY:
+        afterType = true;
+        if (parseContext.profile == EEsProfile && parseContext.version == 300)
+            reservedWord();
+        else if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+                 (parseContext.profile != EEsProfile && parseContext.version < 130))
+            return identifierOrType();
+        return keyword;
+
+    case SAMPLEREXTERNALOES:
+        afterType = true;
+        if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external))
+            return keyword;
+        return identifierOrType();
+
+    case TEXTURE2D:
+    case TEXTURECUBE:
+    case TEXTURECUBEARRAY:
+    case ITEXTURECUBEARRAY:
+    case UTEXTURECUBEARRAY:
+    case ITEXTURE1DARRAY:
+    case UTEXTURE1D:
+    case ITEXTURE1D:
+    case UTEXTURE1DARRAY:
+    case TEXTUREBUFFER:
+    case TEXTURE2DARRAY:
+    case ITEXTURE2D:
+    case ITEXTURE3D:
+    case ITEXTURECUBE:
+    case ITEXTURE2DARRAY:
+    case UTEXTURE2D:
+    case UTEXTURE3D:
+    case UTEXTURECUBE:
+    case UTEXTURE2DARRAY:
+    case ITEXTURE2DRECT:
+    case UTEXTURE2DRECT:
+    case ITEXTUREBUFFER:
+    case UTEXTUREBUFFER:
+    case TEXTURE2DMS:
+    case ITEXTURE2DMS:
+    case UTEXTURE2DMS:
+    case TEXTURE2DMSARRAY:
+    case ITEXTURE2DMSARRAY:
+    case UTEXTURE2DMSARRAY:
+    case TEXTURE1D:
+    case TEXTURE3D:
+    case TEXTURE2DRECT:
+    case TEXTURE1DARRAY:
+    case SAMPLER:
+    case SAMPLERSHADOW:
+        if (parseContext.spvVersion.vulkan >= 100)
+            return keyword;
+        else
+            return identifierOrType();
+
+    case SUBPASSINPUT:
+    case SUBPASSINPUTMS:
+    case ISUBPASSINPUT:
+    case ISUBPASSINPUTMS:
+    case USUBPASSINPUT:
+    case USUBPASSINPUTMS:
+        if (parseContext.spvVersion.vulkan >= 100)
+            return keyword;
+        else
+            return identifierOrType();
+
+    case NOPERSPECTIVE:
+        return es30ReservedFromGLSL(130);
+
+    case SMOOTH:
+        if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 130))
+            return identifierOrType();
+        return keyword;
+
+#ifdef AMD_EXTENSIONS
+    case __EXPLICITINTERPAMD:
+        if (parseContext.profile != EEsProfile && parseContext.version >= 450 &&
+            parseContext.extensionTurnedOn(E_GL_AMD_shader_explicit_vertex_parameter))
+            return keyword;
+        return identifierOrType();
+#endif
+
+    case FLAT:
+        if (parseContext.profile == EEsProfile && parseContext.version < 300)
+            reservedWord();
+        else if (parseContext.profile != EEsProfile && parseContext.version < 130)
+            return identifierOrType();
+        return keyword;
+
+    case CENTROID:
+        if (parseContext.version < 120)
+            return identifierOrType();
+        return keyword;
+
+    case PRECISE:
+        if ((parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5)) ||
+            (parseContext.profile != EEsProfile && parseContext.version >= 400))
+            return keyword;
+        if (parseContext.profile == EEsProfile && parseContext.version == 310) {
+            reservedWord();
+            return keyword;
+        }
+        return identifierOrType();
+
+    case INVARIANT:
+        if (parseContext.profile != EEsProfile && parseContext.version < 120)
+            return identifierOrType();
+        return keyword;
+
+    case PACKED:
+        if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+            (parseContext.profile != EEsProfile && parseContext.version < 330))
+            return reservedWord();
+        return identifierOrType();
+
+    case RESOURCE:
+    {
+        bool reserved = (parseContext.profile == EEsProfile && parseContext.version >= 300) ||
+                        (parseContext.profile != EEsProfile && parseContext.version >= 420);
+        return identifierOrReserved(reserved);
+    }
+    case SUPERP:
+    {
+        bool reserved = parseContext.profile == EEsProfile || parseContext.version >= 130;
+        return identifierOrReserved(reserved);
+    }
+
+    default:
+        parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
+        return 0;
+    }
+}
+
+int TScanContext::identifierOrType()
+{
+    parserToken->sType.lex.string = NewPoolTString(tokenText);
+    if (field)
+        return IDENTIFIER;
+
+    parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
+    if (afterType == false && parserToken->sType.lex.symbol) {
+        if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
+            if (variable->isUserType()) {
+                afterType = true;
+
+                return TYPE_NAME;
+            }
+        }
+    }
+
+    return IDENTIFIER;
+}
+
+// Give an error for use of a reserved symbol.
+// However, allow built-in declarations to use reserved words, to allow
+// extension support before the extension is enabled.
+int TScanContext::reservedWord()
+{
+    if (! parseContext.symbolTable.atBuiltInLevel())
+        parseContext.error(loc, "Reserved word.", tokenText, "", "");
+
+    return 0;
+}
+
+int TScanContext::identifierOrReserved(bool reserved)
+{
+    if (reserved) {
+        reservedWord();
+
+        return 0;
+    }
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using future reserved keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+// For keywords that suddenly showed up on non-ES (not previously reserved)
+// but then got reserved by ES 3.0.
+int TScanContext::es30ReservedFromGLSL(int version)
+{
+    if (parseContext.symbolTable.atBuiltInLevel())
+        return keyword;
+
+    if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+        (parseContext.profile != EEsProfile && parseContext.version < version)) {
+            if (parseContext.forwardCompatible)
+                parseContext.warn(loc, "future reserved word in ES 300 and keyword in GLSL", tokenText, "");
+
+            return identifierOrType();
+    } else if (parseContext.profile == EEsProfile && parseContext.version >= 300)
+        reservedWord();
+
+    return keyword;
+}
+
+// For a keyword that was never reserved, until it suddenly
+// showed up, both in an es version and a non-ES version.
+int TScanContext::nonreservedKeyword(int esVersion, int nonEsVersion)
+{
+    if ((parseContext.profile == EEsProfile && parseContext.version < esVersion) ||
+        (parseContext.profile != EEsProfile && parseContext.version < nonEsVersion)) {
+        if (parseContext.forwardCompatible)
+            parseContext.warn(loc, "using future keyword", tokenText, "");
+
+        return identifierOrType();
+    }
+
+    return keyword;
+}
+
+int TScanContext::precisionKeyword()
+{
+    if (parseContext.profile == EEsProfile || parseContext.version >= 130)
+        return keyword;
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using ES precision qualifier keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+int TScanContext::matNxM()
+{
+    afterType = true;
+
+    if (parseContext.version > 110)
+        return keyword;
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using future non-square matrix type keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+int TScanContext::dMat()
+{
+    afterType = true;
+
+    if (parseContext.profile == EEsProfile && parseContext.version >= 300) {
+        reservedWord();
+
+        return keyword;
+    }
+
+    if (parseContext.profile != EEsProfile && parseContext.version >= 400)
+        return keyword;
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using future type keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+int TScanContext::firstGenerationImage(bool inEs310)
+{
+    if (parseContext.symbolTable.atBuiltInLevel() ||
+        (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store))) ||
+        (inEs310 && parseContext.profile == EEsProfile && parseContext.version >= 310))
+        return keyword;
+
+    if ((parseContext.profile == EEsProfile && parseContext.version >= 300) ||
+        (parseContext.profile != EEsProfile && parseContext.version >= 130)) {
+        reservedWord();
+
+        return keyword;
+    }
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using future type keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+int TScanContext::secondGenerationImage()
+{
+    if (parseContext.profile == EEsProfile && parseContext.version >= 310) {
+        reservedWord();
+        return keyword;
+    }
+
+    if (parseContext.symbolTable.atBuiltInLevel() ||
+        (parseContext.profile != EEsProfile &&
+         (parseContext.version >= 420 || parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store))))
+        return keyword;
+
+    if (parseContext.forwardCompatible)
+        parseContext.warn(loc, "using future type keyword", tokenText, "");
+
+    return identifierOrType();
+}
+
+} // end namespace glslang

+ 275 - 0
src/libraries/glslang/glslang/MachineIndependent/Scan.h

@@ -0,0 +1,275 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef _GLSLANG_SCAN_INCLUDED_
+#define _GLSLANG_SCAN_INCLUDED_
+
+#include "Versions.h"
+
+namespace glslang {
+
+// Use a global end-of-input character, so no translation is needed across
+// layers of encapsulation.  Characters are all 8 bit, and positive, so there is
+// no aliasing of character 255 onto -1, for example.
+const int EndOfInput = -1;
+
+//
+// A character scanner that seamlessly, on read-only strings, reads across an
+// array of strings without assuming null termination.
+//
+class TInputScanner {
+public:
+    TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
+        numSources(n),
+        sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
+        lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), endOfFileReached(false)
+    {
+        loc = new TSourceLoc[numSources];
+        for (int i = 0; i < numSources; ++i) {
+            loc[i].init();
+        }
+        if (names != nullptr) {
+            for (int i = 0; i < numSources; ++i)
+                loc[i].name = names[i];
+        }
+        loc[currentSource].string = -stringBias;
+        loc[currentSource].line = 1;
+        loc[currentSource].column = 0;
+        logicalSourceLoc.string = 0;
+        logicalSourceLoc.line = 1;
+        logicalSourceLoc.column = 0;
+        logicalSourceLoc.name = loc[0].name;
+    }
+
+    virtual ~TInputScanner()
+    {
+        delete [] loc;
+    }
+
+    // retrieve the next character and advance one character
+    int get()
+    {
+        int ret = peek();
+        if (ret == EndOfInput)
+            return ret;
+        ++loc[currentSource].column;
+        ++logicalSourceLoc.column;
+        if (ret == '\n') {
+            ++loc[currentSource].line;
+            ++logicalSourceLoc.line;
+            logicalSourceLoc.column = 0;
+            loc[currentSource].column = 0;
+        }
+        advance();
+
+        return ret;
+    }
+
+    // retrieve the next character, no advance
+    int peek()
+    {
+        if (currentSource >= numSources) {
+            endOfFileReached = true;
+            return EndOfInput;
+        }
+        // Make sure we do not read off the end of a string.
+        // N.B. Sources can have a length of 0.
+        int sourceToRead = currentSource;
+        size_t charToRead = currentChar;
+        while(charToRead >= lengths[sourceToRead]) {
+            charToRead = 0;
+            sourceToRead += 1;
+            if (sourceToRead >= numSources) {
+                return EndOfInput;
+            }
+        }
+
+        // Here, we care about making negative valued characters positive
+        return sources[sourceToRead][charToRead];
+    }
+
+    // go back one character
+    void unget()
+    {
+        // Do not roll back once we've reached the end of the file.
+        if (endOfFileReached)
+            return;
+
+        if (currentChar > 0) {
+            --currentChar;
+            --loc[currentSource].column;
+            --logicalSourceLoc.column;
+            if (loc[currentSource].column < 0) {
+                // We've moved back past a new line. Find the
+                // previous newline (or start of the file) to compute
+                // the column count on the now current line.
+                size_t chIndex = currentChar;
+                while (chIndex > 0) {
+                    if (sources[currentSource][chIndex] == '\n') {
+                        break;
+                    }
+                    --chIndex;
+                }
+                logicalSourceLoc.column = (int)(currentChar - chIndex);
+                loc[currentSource].column = (int)(currentChar - chIndex);
+            }
+        } else {
+            do {
+                --currentSource;
+            } while (currentSource > 0 && lengths[currentSource] == 0);
+            if (lengths[currentSource] == 0) {
+                // set to 0 if we've backed up to the start of an empty string
+                currentChar = 0;
+            } else
+                currentChar = lengths[currentSource] - 1;
+        }
+        if (peek() == '\n') {
+            --loc[currentSource].line;
+            --logicalSourceLoc.line;
+        }
+    }
+
+    // for #line override
+    void setLine(int newLine)
+    {
+        logicalSourceLoc.line = newLine;
+        loc[getLastValidSourceIndex()].line = newLine;
+    }
+
+    // for #line override in filename based parsing
+    void setFile(const char* filename)
+    {
+        logicalSourceLoc.name = filename;
+        loc[getLastValidSourceIndex()].name = filename;
+    }
+
+    void setFile(const char* filename, int i)
+    {
+        if (i == getLastValidSourceIndex()) {
+            logicalSourceLoc.name = filename;
+        }
+        loc[i].name = filename;
+    }
+
+    void setString(int newString)
+    {
+        logicalSourceLoc.string = newString;
+        loc[getLastValidSourceIndex()].string = newString;
+        logicalSourceLoc.name = nullptr;
+        loc[getLastValidSourceIndex()].name = nullptr;
+    }
+
+    // for #include content indentation
+    void setColumn(int col)
+    {
+        logicalSourceLoc.column = col;
+        loc[getLastValidSourceIndex()].column = col;
+    }
+
+    void setEndOfInput()
+    {
+        endOfFileReached = true;
+        currentSource = numSources;
+    }
+
+    bool atEndOfInput() const { return endOfFileReached; }
+
+    const TSourceLoc& getSourceLoc() const
+    {
+        if (singleLogical) {
+            return logicalSourceLoc;
+        } else {
+            return loc[std::max(0, std::min(currentSource, numSources - finale - 1))];
+        }
+    }
+    // Returns the index (starting from 0) of the most recent valid source string we are reading from.
+    int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
+
+    void consumeWhiteSpace(bool& foundNonSpaceTab);
+    bool consumeComment();
+    void consumeWhitespaceComment(bool& foundNonSpaceTab);
+    bool scanVersion(int& version, EProfile& profile, bool& notFirstToken);
+
+protected:
+
+    // advance one character
+    void advance()
+    {
+        ++currentChar;
+        if (currentChar >= lengths[currentSource]) {
+            ++currentSource;
+            if (currentSource < numSources) {
+                loc[currentSource].string = loc[currentSource - 1].string + 1;
+                loc[currentSource].line = 1;
+                loc[currentSource].column = 0;
+            }
+            while (currentSource < numSources && lengths[currentSource] == 0) {
+                ++currentSource;
+                if (currentSource < numSources) {
+                    loc[currentSource].string = loc[currentSource - 1].string + 1;
+                    loc[currentSource].line = 1;
+                    loc[currentSource].column = 0;
+                }
+            }
+            currentChar = 0;
+        }
+    }
+
+    int numSources;                      // number of strings in source
+    const unsigned char* const *sources; // array of strings; must be converted to positive values on use, to avoid aliasing with -1 as EndOfInput
+    const size_t *lengths;               // length of each string
+    int currentSource;
+    size_t currentChar;
+
+    // This is for reporting what string/line an error occurred on, and can be overridden by #line.
+    // It remembers the last state of each source string as it is left for the next one, so unget()
+    // can restore that state.
+    TSourceLoc* loc;  // an array
+
+    int stringBias;   // the first string that is the user's string number 0
+    int finale;       // number of internal strings after user's last string
+
+    TSourceLoc logicalSourceLoc;
+    bool singleLogical; // treats the strings as a single logical string.
+                        // locations will be reported from the first string.
+
+    // Set to true once peek() returns EndOfFile, so that we won't roll back
+    // once we've reached EndOfFile.
+    bool endOfFileReached;
+};
+
+} // end namespace glslang
+
+#endif // _GLSLANG_SCAN_INCLUDED_

+ 86 - 0
src/libraries/glslang/glslang/MachineIndependent/ScanContext.h

@@ -0,0 +1,86 @@
+//
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// This holds context specific to the GLSL scanner, which
+// sits between the preprocessor scanner and parser.
+//
+
+#include "ParseHelper.h"
+
+namespace glslang {
+
+class TPpContext;
+class TPpToken;
+class TParserToken;
+
+class TScanContext {
+public:
+    explicit TScanContext(TParseContextBase& pc) : parseContext(pc), afterType(false), field(false) { }
+    virtual ~TScanContext() { }
+
+    static void fillInKeywordMap();
+    static void deleteKeywordMap();
+
+    int tokenize(TPpContext*, TParserToken&);
+
+protected:
+    TScanContext(TScanContext&);
+    TScanContext& operator=(TScanContext&);
+
+    int tokenizeIdentifier();
+    int identifierOrType();
+    int reservedWord();
+    int identifierOrReserved(bool reserved);
+    int es30ReservedFromGLSL(int version);
+    int nonreservedKeyword(int esVersion, int nonEsVersion);
+    int precisionKeyword();
+    int matNxM();
+    int dMat();
+    int firstGenerationImage(bool inEs310);
+    int secondGenerationImage();
+
+    TParseContextBase& parseContext;
+    bool afterType;           // true if we've recognized a type, so can only be looking for an identifier
+    bool field;               // true if we're on a field, right after a '.'
+    TSourceLoc loc;
+    TParserToken* parserToken;
+    TPpToken* ppToken;
+
+    const char* tokenText;
+    int keyword;
+};
+
+} // end namespace glslang

+ 1800 - 0
src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp

@@ -0,0 +1,1800 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013-2016 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Implement the top-level of interface to the compiler/linker,
+// as defined in ShaderLang.h
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler/linker.
+//
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <memory>
+#include "SymbolTable.h"
+#include "ParseHelper.h"
+#include "Scan.h"
+#include "ScanContext.h"
+
+#ifdef ENABLE_HLSL
+#include "../../hlsl/hlslParseHelper.h"
+#include "../../hlsl/hlslParseables.h"
+#include "../../hlsl/hlslScanContext.h"
+#endif
+
+#include "../Include/ShHandle.h"
+#include "../../OGLCompilersDLL/InitializeDll.h"
+
+#include "preprocessor/PpContext.h"
+
+#define SH_EXPORTING
+#include "../Public/ShaderLang.h"
+#include "reflection.h"
+#include "iomapper.h"
+#include "Initialize.h"
+
+namespace { // anonymous namespace for file-local functions and symbols
+
+using namespace glslang;
+
+// Create a language specific version of parseables.
+TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource source)
+{
+    switch (source) {
+    case EShSourceGlsl: return new TBuiltIns();              // GLSL builtIns
+#ifdef ENABLE_HLSL
+    case EShSourceHlsl: return new TBuiltInParseablesHlsl(); // HLSL intrinsics
+#endif
+
+    default:
+        infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
+        return nullptr;
+    }
+}
+
+// Create a language specific version of a parse context.
+TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate& intermediate,
+                                      int version, EProfile profile, EShSource source,
+                                      EShLanguage language, TInfoSink& infoSink,
+                                      SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
+                                      bool parsingBuiltIns, const std::string sourceEntryPointName = "")
+{
+#ifndef ENABLE_HLSL
+    (void)sourceEntryPointName; // Unused argument.
+#endif
+
+    switch (source) {
+    case EShSourceGlsl:
+        intermediate.setEntryPointName("main");
+        return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
+                                 language, infoSink, forwardCompatible, messages);
+
+#ifdef ENABLE_HLSL
+    case EShSourceHlsl:
+        return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
+                                    language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages);
+#endif
+    default:
+        infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
+        return nullptr;
+    }
+}
+
+// Local mapping functions for making arrays of symbol tables....
+
+const int VersionCount = 15;  // index range in MapVersionToIndex
+
+int MapVersionToIndex(int version)
+{
+    int index = 0;
+
+    switch (version) {
+    case 100: index =  0; break;
+    case 110: index =  1; break;
+    case 120: index =  2; break;
+    case 130: index =  3; break;
+    case 140: index =  4; break;
+    case 150: index =  5; break;
+    case 300: index =  6; break;
+    case 330: index =  7; break;
+    case 400: index =  8; break;
+    case 410: index =  9; break;
+    case 420: index = 10; break;
+    case 430: index = 11; break;
+    case 440: index = 12; break;
+    case 310: index = 13; break;
+    case 450: index = 14; break;
+    default:              break;
+    }
+
+    assert(index < VersionCount);
+
+    return index;
+}
+
+const int SpvVersionCount = 3;  // index range in MapSpvVersionToIndex
+
+int MapSpvVersionToIndex(const SpvVersion& spvVersion)
+{
+    int index = 0;
+
+    if (spvVersion.openGl > 0)
+        index = 1;
+    else if (spvVersion.vulkan > 0)
+        index = 2;
+
+    assert(index < SpvVersionCount);
+
+    return index;
+}
+
+const int ProfileCount = 4;   // index range in MapProfileToIndex
+
+int MapProfileToIndex(EProfile profile)
+{
+    int index = 0;
+
+    switch (profile) {
+    case ENoProfile:            index = 0; break;
+    case ECoreProfile:          index = 1; break;
+    case ECompatibilityProfile: index = 2; break;
+    case EEsProfile:            index = 3; break;
+    default:                               break;
+    }
+
+    assert(index < ProfileCount);
+
+    return index;
+}
+
+const int SourceCount = 2;
+
+int MapSourceToIndex(EShSource source)
+{
+    int index = 0;
+
+    switch (source) {
+    case EShSourceGlsl: index = 0; break;
+    case EShSourceHlsl: index = 1; break;
+    default:                       break;
+    }
+
+    assert(index < SourceCount);
+
+    return index;
+}
+
+// only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
+enum EPrecisionClass {
+    EPcGeneral,
+    EPcFragment,
+    EPcCount
+};
+
+// A process-global symbol table per version per profile for built-ins common
+// to multiple stages (languages), and a process-global symbol table per version
+// per profile per stage for built-ins unique to each stage.  They will be sparsely
+// populated, so they will only be generated as needed.
+//
+// Each has a different set of built-ins, and we want to preserve that from
+// compile to compile.
+//
+TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
+TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
+
+TPoolAllocator* PerProcessGPA = 0;
+
+//
+// Parse and add to the given symbol table the content of the given shader string.
+//
+bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
+                           EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable)
+{
+    TIntermediate intermediate(language, version, profile);
+
+    intermediate.setSource(source);
+
+    std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source,
+                                                                       language, infoSink, spvVersion, true, EShMsgDefault,
+                                                                       true));
+
+    TShader::ForbidIncluder includer;
+    TPpContext ppContext(*parseContext, "", includer);
+    TScanContext scanContext(*parseContext);
+    parseContext->setScanContext(&scanContext);
+    parseContext->setPpContext(&ppContext);
+
+    //
+    // Push the symbol table to give it an initial scope.  This
+    // push should not have a corresponding pop, so that built-ins
+    // are preserved, and the test for an empty table fails.
+    //
+
+    symbolTable.push();
+
+    const char* builtInShaders[2];
+    size_t builtInLengths[2];
+    builtInShaders[0] = builtIns.c_str();
+    builtInLengths[0] = builtIns.size();
+
+    if (builtInLengths[0] == 0)
+        return true;
+
+    TInputScanner input(1, builtInShaders, builtInLengths);
+    if (! parseContext->parseShaderStrings(ppContext, input) != 0) {
+        infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
+        printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
+        printf("%s\n", builtInShaders[0]);
+
+        return false;
+    }
+
+    return true;
+}
+
+int CommonIndex(EProfile profile, EShLanguage language)
+{
+    return (profile == EEsProfile && language == EShLangFragment) ? EPcFragment : EPcGeneral;
+}
+
+//
+// To initialize per-stage shared tables, with the common table already complete.
+//
+void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
+                                EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
+                                TSymbolTable** symbolTables)
+{
+    (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
+    InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
+                          infoSink, *symbolTables[language]);
+    builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
+    if (profile == EEsProfile && version >= 300)
+        (*symbolTables[language]).setNoBuiltInRedeclarations();
+    if (version == 110)
+        (*symbolTables[language]).setSeparateNameSpaces();
+}
+
+//
+// Initialize the full set of shareable symbol tables;
+// The common (cross-stage) and those shareable per-stage.
+//
+bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable,  TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
+{
+    std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
+
+    if (builtInParseables == nullptr)
+        return false;
+
+    builtInParseables->initialize(version, profile, spvVersion);
+
+    // do the common tables
+    InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
+                          infoSink, *commonTable[EPcGeneral]);
+    if (profile == EEsProfile)
+        InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
+                              infoSink, *commonTable[EPcFragment]);
+
+    // do the per-stage tables
+
+    // always have vertex and fragment
+    InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
+                               infoSink, commonTable, symbolTables);
+    InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
+                               infoSink, commonTable, symbolTables);
+
+    // check for tessellation
+    if ((profile != EEsProfile && version >= 150) ||
+        (profile == EEsProfile && version >= 310)) {
+        InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
+                                   infoSink, commonTable, symbolTables);
+        InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
+                                   infoSink, commonTable, symbolTables);
+    }
+
+    // check for geometry
+    if ((profile != EEsProfile && version >= 150) ||
+        (profile == EEsProfile && version >= 310))
+        InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
+                                   infoSink, commonTable, symbolTables);
+
+    // check for compute
+    if ((profile != EEsProfile && version >= 420) ||
+        (profile == EEsProfile && version >= 310))
+        InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
+                                   infoSink, commonTable, symbolTables);
+
+    return true;
+}
+
+bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version,
+                               EProfile profile, const SpvVersion& spvVersion, EShLanguage language, EShSource source)
+{
+    std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
+
+    if (builtInParseables == nullptr)
+        return false;
+
+    builtInParseables->initialize(*resources, version, profile, spvVersion, language);
+    InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
+    builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
+
+    return true;
+}
+
+//
+// To do this on the fly, we want to leave the current state of our thread's
+// pool allocator intact, so:
+//  - Switch to a new pool for parsing the built-ins
+//  - Do the parsing, which builds the symbol table, using the new pool
+//  - Switch to the process-global pool to save a copy the resulting symbol table
+//  - Free up the new pool used to parse the built-ins
+//  - Switch back to the original thread's pool
+//
+// This only gets done the first time any thread needs a particular symbol table
+// (lazy evaluation).
+//
+void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
+{
+    TInfoSink infoSink;
+
+    // Make sure only one thread tries to do this at a time
+    glslang::GetGlobalLock();
+
+    // See if it's already been done for this version/profile combination
+    int versionIndex = MapVersionToIndex(version);
+    int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
+    int profileIndex = MapProfileToIndex(profile);
+    int sourceIndex = MapSourceToIndex(source);
+    if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
+        glslang::ReleaseGlobalLock();
+
+        return;
+    }
+
+    // Switch to a new pool
+    TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
+    TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
+    SetThreadPoolAllocator(*builtInPoolAllocator);
+
+    // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
+    TSymbolTable* commonTable[EPcCount];
+    TSymbolTable* stageTables[EShLangCount];
+    for (int precClass = 0; precClass < EPcCount; ++precClass)
+        commonTable[precClass] = new TSymbolTable;
+    for (int stage = 0; stage < EShLangCount; ++stage)
+        stageTables[stage] = new TSymbolTable;
+
+    // Generate the local symbol tables using the new pool
+    InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
+
+    // Switch to the process-global pool
+    SetThreadPoolAllocator(*PerProcessGPA);
+
+    // Copy the local symbol tables from the new pool to the global tables using the process-global pool
+    for (int precClass = 0; precClass < EPcCount; ++precClass) {
+        if (! commonTable[precClass]->isEmpty()) {
+            CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable;
+            CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]);
+            CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly();
+        }
+    }
+    for (int stage = 0; stage < EShLangCount; ++stage) {
+        if (! stageTables[stage]->isEmpty()) {
+            SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable;
+            SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable
+                              [versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]);
+            SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]);
+            SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
+        }
+    }
+
+    // Clean up the local tables before deleting the pool they used.
+    for (int precClass = 0; precClass < EPcCount; ++precClass)
+        delete commonTable[precClass];
+    for (int stage = 0; stage < EShLangCount; ++stage)
+        delete stageTables[stage];
+
+    delete builtInPoolAllocator;
+    SetThreadPoolAllocator(previousAllocator);
+
+    glslang::ReleaseGlobalLock();
+}
+
+// Return true if the shader was correctly specified for version/profile/stage.
+bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
+                          EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
+{
+    const int FirstProfileVersion = 150;
+    bool correct = true;
+
+    if (source == EShSourceHlsl) {
+        version = 450;          // TODO: GLSL parser is still used for builtins.
+        profile = ECoreProfile; // allow doubles in prototype parsing
+        return correct;
+    }
+
+    // Get a good version...
+    if (version == 0) {
+        version = defaultVersion;
+        // infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader");
+    }
+
+    // Get a good profile...
+    if (profile == ENoProfile) {
+        if (version == 300 || version == 310) {
+            correct = false;
+            infoSink.info.message(EPrefixError, "#version: versions 300 and 310 require specifying the 'es' profile");
+            profile = EEsProfile;
+        } else if (version == 100)
+            profile = EEsProfile;
+        else if (version >= FirstProfileVersion)
+            profile = ECoreProfile;
+        else
+            profile = ENoProfile;
+    } else {
+        // a profile was provided...
+        if (version < 150) {
+            correct = false;
+            infoSink.info.message(EPrefixError, "#version: versions before 150 do not allow a profile token");
+            if (version == 100)
+                profile = EEsProfile;
+            else
+                profile = ENoProfile;
+        } else if (version == 300 || version == 310) {
+            if (profile != EEsProfile) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: versions 300 and 310 support only the es profile");
+            }
+            profile = EEsProfile;
+        } else {
+            if (profile == EEsProfile) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: only version 300 and 310 support the es profile");
+                if (version >= FirstProfileVersion)
+                    profile = ECoreProfile;
+                else
+                    profile = ENoProfile;
+            }
+            // else: typical desktop case... e.g., "#version 410 core"
+        }
+    }
+
+    // Correct for stage type...
+    switch (stage) {
+    case EShLangGeometry:
+        if ((profile == EEsProfile && version < 310) ||
+            (profile != EEsProfile && version < 150)) {
+            correct = false;
+            infoSink.info.message(EPrefixError, "#version: geometry shaders require es profile with version 310 or non-es profile with version 150 or above");
+            version = (profile == EEsProfile) ? 310 : 150;
+            if (profile == EEsProfile || profile == ENoProfile)
+                profile = ECoreProfile;
+        }
+        break;
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        if ((profile == EEsProfile && version < 310) ||
+            (profile != EEsProfile && version < 150)) {
+            correct = false;
+            infoSink.info.message(EPrefixError, "#version: tessellation shaders require es profile with version 310 or non-es profile with version 150 or above");
+            version = (profile == EEsProfile) ? 310 : 400; // 150 supports the extension, correction is to 400 which does not
+            if (profile == EEsProfile || profile == ENoProfile)
+                profile = ECoreProfile;
+        }
+        break;
+    case EShLangCompute:
+        if ((profile == EEsProfile && version < 310) ||
+            (profile != EEsProfile && version < 420)) {
+            correct = false;
+            infoSink.info.message(EPrefixError, "#version: compute shaders require es profile with version 310 or above, or non-es profile with version 420 or above");
+            version = profile == EEsProfile ? 310 : 420;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (profile == EEsProfile && version >= 300 && versionNotFirst) {
+        correct = false;
+        infoSink.info.message(EPrefixError, "#version: statement must appear first in es-profile shader; before comments or newlines");
+    }
+
+    // Check for SPIR-V compatibility
+    if (spvVersion.spv != 0) {
+        switch (profile) {
+        case  EEsProfile:
+            if (spvVersion.vulkan >= 100 && version < 310) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: ES shaders for Vulkan SPIR-V require version 310 or higher");
+                version = 310;
+            }
+            if (spvVersion.openGl >= 100) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: ES shaders for OpenGL SPIR-V are not supported");
+                version = 310;
+            }
+            break;
+        case ECompatibilityProfile:
+            infoSink.info.message(EPrefixError, "#version: compilation for SPIR-V does not support the compatibility profile");
+            break;
+        default:
+            if (spvVersion.vulkan >= 100 && version < 140) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: Desktop shaders for Vulkan SPIR-V require version 140 or higher");
+                version = 140;
+            }
+            if (spvVersion.openGl >= 100 && version < 330) {
+                correct = false;
+                infoSink.info.message(EPrefixError, "#version: Desktop shaders for OpenGL SPIR-V require version 330 or higher");
+                version = 330;
+            }
+            break;
+        }
+    }
+
+    // A meta check on the condition of the compiler itself...
+    switch (version) {
+
+    // ES versions
+    case 100:
+    case 300:
+        // versions are complete
+        break;
+
+    // Desktop versions
+    case 110:
+    case 120:
+    case 130:
+    case 140:
+    case 150:
+    case 330:
+        // versions are complete
+        break;
+
+    case 310:
+    case 400:
+    case 410:
+    case 420:
+    case 430:
+    case 440:
+    case 450:
+        infoSink.info << "Warning, version " << version << " is not yet complete; most version-specific features are present, but some are missing.\n";
+        break;
+
+    default:
+        infoSink.info << "Warning, version " << version << " is unknown.\n";
+        break;
+
+    }
+
+    return correct;
+}
+
+// This is the common setup and cleanup code for PreprocessDeferred and
+// CompileDeferred.
+// It takes any callable with a signature of
+//  bool (TParseContextBase& parseContext, TPpContext& ppContext,
+//                  TInputScanner& input, bool versionWillBeError,
+//                  TSymbolTable& , TIntermediate& ,
+//                  EShOptimizationLevel , EShMessages );
+// Which returns false if a failure was detected and true otherwise.
+//
+template<typename ProcessingContext>
+bool ProcessDeferred(
+    TCompiler* compiler,
+    const char* const shaderStrings[],
+    const int numStrings,
+    const int* inputLengths,
+    const char* const stringNames[],
+    const char* customPreamble,
+    const EShOptimizationLevel optLevel,
+    const TBuiltInResource* resources,
+    int defaultVersion,         // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
+    EProfile defaultProfile,
+    // set version/profile to defaultVersion/defaultProfile regardless of the #version
+    // directive in the source code
+    bool forceDefaultVersionAndProfile,
+    bool forwardCompatible,     // give errors for use of deprecated features
+    EShMessages messages,       // warnings/errors/AST; things to print out
+    TIntermediate& intermediate, // returned tree, etc.
+    ProcessingContext& processingContext,
+    bool requireNonempty,
+    TShader::Includer& includer,
+    const std::string sourceEntryPointName = ""
+    )
+{
+    if (! InitThread())
+        return false;
+
+    // This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
+    GetThreadPoolAllocator().push();
+
+    if (numStrings == 0)
+        return true;
+
+    // Move to length-based strings, rather than null-terminated strings.
+    // Also, add strings to include the preamble and to ensure the shader is not null,
+    // which lets the grammar accept what was a null (post preprocessing) shader.
+    //
+    // Shader will look like
+    //   string 0:                system preamble
+    //   string 1:                custom preamble
+    //   string 2...numStrings+1: user's shader
+    //   string numStrings+2:     "int;"
+    const int numPre = 2;
+    const int numPost = requireNonempty? 1 : 0;
+    const int numTotal = numPre + numStrings + numPost;
+    size_t* lengths = new size_t[numTotal];
+    const char** strings = new const char*[numTotal];
+    const char** names = new const char*[numTotal];
+    for (int s = 0; s < numStrings; ++s) {
+        strings[s + numPre] = shaderStrings[s];
+        if (inputLengths == 0 || inputLengths[s] < 0)
+            lengths[s + numPre] = strlen(shaderStrings[s]);
+        else
+            lengths[s + numPre] = inputLengths[s];
+    }
+    if (stringNames != nullptr) {
+        for (int s = 0; s < numStrings; ++s)
+            names[s + numPre] = stringNames[s];
+    } else {
+        for (int s = 0; s < numStrings; ++s)
+            names[s + numPre] = nullptr;
+    }
+
+    // First, without using the preprocessor or parser, find the #version, so we know what
+    // symbol tables, processing rules, etc. to set up.  This does not need the extra strings
+    // outlined above, just the user shader.
+    int version;
+    EProfile profile;
+    glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]);  // no preamble
+    bool versionNotFirstToken;
+    bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken);
+    bool versionNotFound = version == 0;
+    if (forceDefaultVersionAndProfile) {
+        if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
+            (version != defaultVersion || profile != defaultProfile)) {
+            compiler->infoSink.info << "Warning, (version, profile) forced to be ("
+                                    << defaultVersion << ", " << ProfileName(defaultProfile)
+                                    << "), while in source code it is ("
+                                    << version << ", " << ProfileName(profile) << ")\n";
+        }
+
+        if (versionNotFound) {
+            versionNotFirstToken = false;
+            versionNotFirst = false;
+            versionNotFound = false;
+        }
+        version = defaultVersion;
+        profile = defaultProfile;
+    }
+    SpvVersion spvVersion;
+    if (messages & EShMsgSpvRules)
+        spvVersion.spv = 0x00010000;    // TODO: eventually have this come from the outside
+    EShSource source = (messages & EShMsgReadHlsl) ? EShSourceHlsl : EShSourceGlsl;
+    if (messages & EShMsgVulkanRules)
+        spvVersion.vulkan = 100;     // TODO: eventually have this come from the outside
+    else if (spvVersion.spv != 0)
+        spvVersion.openGl = 100;     // TODO: eventually have this come from the outside
+    bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, source, version, profile, spvVersion);
+    bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
+    bool warnVersionNotFirst = false;
+    if (! versionWillBeError && versionNotFirstToken) {
+        if (messages & EShMsgRelaxedErrors)
+            warnVersionNotFirst = true;
+        else
+            versionWillBeError = true;
+    }
+
+    intermediate.setSource(source);
+    intermediate.setVersion(version);
+    intermediate.setProfile(profile);
+    intermediate.setSpv(spvVersion);
+    if (spvVersion.vulkan >= 100)
+        intermediate.setOriginUpperLeft();
+    SetupBuiltinSymbolTable(version, profile, spvVersion, source);
+
+    TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
+                                                  [MapSpvVersionToIndex(spvVersion)]
+                                                  [MapProfileToIndex(profile)]
+                                                  [MapSourceToIndex(source)]
+                                                  [compiler->getLanguage()];
+
+    // Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
+    TSymbolTable* symbolTableMemory = new TSymbolTable;
+    TSymbolTable& symbolTable = *symbolTableMemory;
+    if (cachedTable)
+        symbolTable.adoptLevels(*cachedTable);
+
+    // Add built-in symbols that are potentially context dependent;
+    // they get popped again further down.
+    if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
+                                    compiler->getLanguage(), source))
+        return false;
+
+    //
+    // Now we can process the full shader under proper symbols and rules.
+    //
+
+    TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
+                                                         compiler->getLanguage(), compiler->infoSink,
+                                                         spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
+
+    TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer);
+
+    // only GLSL (bison triggered, really) needs an externally set scan context
+    glslang::TScanContext scanContext(*parseContext);
+    if ((messages & EShMsgReadHlsl) == 0)
+        parseContext->setScanContext(&scanContext);
+
+    parseContext->setPpContext(&ppContext);
+    parseContext->setLimits(*resources);
+    if (! goodVersion)
+        parseContext->addError();
+    if (warnVersionNotFirst) {
+        TSourceLoc loc;
+        loc.init();
+        parseContext->warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", "");
+    }
+
+    parseContext->initializeExtensionBehavior();
+
+    // Fill in the strings as outlined above.
+    std::string preamble;
+    parseContext->getPreamble(preamble);
+    strings[0] = preamble.c_str();
+    lengths[0] = strlen(strings[0]);
+    names[0] = nullptr;
+    strings[1] = customPreamble;
+    lengths[1] = strlen(strings[1]);
+    names[1] = nullptr;
+    assert(2 == numPre);
+    if (requireNonempty) {
+        const int postIndex = numStrings + numPre;
+        strings[postIndex] = "\n int;";
+        lengths[postIndex] = strlen(strings[numStrings + numPre]);
+        names[postIndex] = nullptr;
+    }
+    TInputScanner fullInput(numStrings + numPre + numPost, strings, lengths, names, numPre, numPost);
+
+    // Push a new symbol allocation scope that will get used for the shader's globals.
+    symbolTable.push();
+
+    bool success = processingContext(*parseContext, ppContext, fullInput,
+                                     versionWillBeError, symbolTable,
+                                     intermediate, optLevel, messages);
+
+    // Clean up the symbol table. The AST is self-sufficient now.
+    delete symbolTableMemory;
+
+    delete parseContext;
+    delete [] lengths;
+    delete [] strings;
+    delete [] names;
+
+    return success;
+}
+
+// Responsible for keeping track of the most recent source string and line in
+// the preprocessor and outputting newlines appropriately if the source string
+// or line changes.
+class SourceLineSynchronizer {
+public:
+    SourceLineSynchronizer(const std::function<int()>& lastSourceIndex,
+                           std::stringstream* output)
+      : getLastSourceIndex(lastSourceIndex), output(output), lastSource(-1), lastLine(0) {}
+//    SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
+//    SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
+
+    // Sets the internally tracked source string index to that of the most
+    // recently read token. If we switched to a new source string, returns
+    // true and inserts a newline. Otherwise, returns false and outputs nothing.
+    bool syncToMostRecentString() {
+        if (getLastSourceIndex() != lastSource) {
+            // After switching to a new source string, we need to reset lastLine
+            // because line number resets every time a new source string is
+            // used. We also need to output a newline to separate the output
+            // from the previous source string (if there is one).
+            if (lastSource != -1 || lastLine != 0)
+                *output << std::endl;
+            lastSource = getLastSourceIndex();
+            lastLine = -1;
+            return true;
+        }
+        return false;
+    }
+
+    // Calls syncToMostRecentString() and then sets the internally tracked line
+    // number to tokenLine. If we switched to a new line, returns true and inserts
+    // newlines appropriately. Otherwise, returns false and outputs nothing.
+    bool syncToLine(int tokenLine) {
+        syncToMostRecentString();
+        const bool newLineStarted = lastLine < tokenLine;
+        for (; lastLine < tokenLine; ++lastLine) {
+            if (lastLine > 0) *output << std::endl;
+        }
+        return newLineStarted;
+    }
+
+    // Sets the internally tracked line number to newLineNum.
+    void setLineNum(int newLineNum) { lastLine = newLineNum; }
+
+private:
+    SourceLineSynchronizer& operator=(const SourceLineSynchronizer&);
+
+    // A function for getting the index of the last valid source string we've
+    // read tokens from.
+    const std::function<int()> getLastSourceIndex;
+    // output stream for newlines.
+    std::stringstream* output;
+    // lastSource is the source string index (starting from 0) of the last token
+    // processed. It is tracked in order for newlines to be inserted when a new
+    // source string starts. -1 means we haven't started processing any source
+    // string.
+    int lastSource;
+    // lastLine is the line number (starting from 1) of the last token processed.
+    // It is tracked in order for newlines to be inserted when a token appears
+    // on a new line. 0 means we haven't started processing any line in the
+    // current source string.
+    int lastLine;
+};
+
+// DoPreprocessing is a valid ProcessingContext template argument,
+// which only performs the preprocessing step of compilation.
+// It places the result in the "string" argument to its constructor.
+struct DoPreprocessing {
+    explicit DoPreprocessing(std::string* string): outputString(string) {}
+    bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
+                    TInputScanner& input, bool versionWillBeError,
+                    TSymbolTable&, TIntermediate&,
+                    EShOptimizationLevel, EShMessages)
+    {
+        // This is a list of tokens that do not require a space before or after.
+        static const std::string unNeededSpaceTokens = ";()[]";
+        static const std::string noSpaceBeforeTokens = ",";
+        glslang::TPpToken ppToken;
+
+        parseContext.setScanner(&input);
+        ppContext.setInput(input, versionWillBeError);
+
+        std::stringstream outputStream;
+        SourceLineSynchronizer lineSync(
+            std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputStream);
+
+        parseContext.setExtensionCallback([&lineSync, &outputStream](
+            int line, const char* extension, const char* behavior) {
+                lineSync.syncToLine(line);
+                outputStream << "#extension " << extension << " : " << behavior;
+        });
+
+        parseContext.setLineCallback([&lineSync, &outputStream, &parseContext](
+            int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) {
+            // SourceNum is the number of the source-string that is being parsed.
+            lineSync.syncToLine(curLineNum);
+            outputStream << "#line " << newLineNum;
+            if (hasSource) {
+                outputStream << " ";
+                if (sourceName != nullptr) {
+                    outputStream << "\"" << sourceName << "\"";
+                } else {
+                    outputStream << sourceNum;
+                }
+            }
+            if (parseContext.lineDirectiveShouldSetNextLine()) {
+                // newLineNum is the new line number for the line following the #line
+                // directive. So the new line number for the current line is
+                newLineNum -= 1;
+            }
+            outputStream << std::endl;
+            // And we are at the next line of the #line directive now.
+            lineSync.setLineNum(newLineNum + 1);
+        });
+
+        parseContext.setVersionCallback(
+            [&lineSync, &outputStream](int line, int version, const char* str) {
+                lineSync.syncToLine(line);
+                outputStream << "#version " << version;
+                if (str) {
+                    outputStream << " " << str;
+                }
+            });
+
+        parseContext.setPragmaCallback([&lineSync, &outputStream](
+            int line, const glslang::TVector<glslang::TString>& ops) {
+                lineSync.syncToLine(line);
+                outputStream << "#pragma ";
+                for(size_t i = 0; i < ops.size(); ++i) {
+                    outputStream << ops[i];
+                }
+        });
+
+        parseContext.setErrorCallback([&lineSync, &outputStream](
+            int line, const char* errorMessage) {
+                lineSync.syncToLine(line);
+                outputStream << "#error " << errorMessage;
+        });
+
+        int lastToken = EndOfInput; // lastToken records the last token processed.
+        do {
+            int token = ppContext.tokenize(ppToken);
+            if (token == EndOfInput)
+                break;
+
+            bool isNewString = lineSync.syncToMostRecentString();
+            bool isNewLine = lineSync.syncToLine(ppToken.loc.line);
+
+            if (isNewLine) {
+                // Don't emit whitespace onto empty lines.
+                // Copy any whitespace characters at the start of a line
+                // from the input to the output.
+                outputStream << std::string(ppToken.loc.column - 1, ' ');
+            }
+
+            // Output a space in between tokens, but not at the start of a line,
+            // and also not around special tokens. This helps with readability
+            // and consistency.
+            if (!isNewString && !isNewLine && lastToken != EndOfInput &&
+                (unNeededSpaceTokens.find((char)token) == std::string::npos) &&
+                (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
+                (noSpaceBeforeTokens.find((char)token) == std::string::npos)) {
+                outputStream << " ";
+            }
+            lastToken = token;
+            outputStream << ppToken.name;
+        } while (true);
+        outputStream << std::endl;
+        *outputString = outputStream.str();
+
+        bool success = true;
+        if (parseContext.getNumErrors() > 0) {
+            success = false;
+            parseContext.infoSink.info.prefix(EPrefixError);
+            parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors.  No code generated.\n\n";
+        }
+        return success;
+    }
+    std::string* outputString;
+};
+
+// DoFullParse is a valid ProcessingConext template argument for fully
+// parsing the shader.  It populates the "intermediate" with the AST.
+struct DoFullParse{
+  bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
+                  TInputScanner& fullInput, bool versionWillBeError,
+                  TSymbolTable&, TIntermediate& intermediate,
+                  EShOptimizationLevel optLevel, EShMessages messages)
+    {
+        bool success = true;
+        // Parse the full shader.
+        if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
+            success = false;
+
+        if (success && intermediate.getTreeRoot()) {
+            if (optLevel == EShOptNoGeneration)
+                parseContext.infoSink.info.message(EPrefixNone, "No errors.  No code generation or linking was requested.");
+            else
+                success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage());
+        } else if (! success) {
+            parseContext.infoSink.info.prefix(EPrefixError);
+            parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors.  No code generated.\n\n";
+        }
+
+        if (messages & EShMsgAST)
+            intermediate.output(parseContext.infoSink, true);
+
+        return success;
+    }
+};
+
+// Take a single compilation unit, and run the preprocessor on it.
+// Return: True if there were no issues found in preprocessing,
+//         False if during preprocessing any unknown version, pragmas or
+//         extensions were found.
+bool PreprocessDeferred(
+    TCompiler* compiler,
+    const char* const shaderStrings[],
+    const int numStrings,
+    const int* inputLengths,
+    const char* const stringNames[],
+    const char* preamble,
+    const EShOptimizationLevel optLevel,
+    const TBuiltInResource* resources,
+    int defaultVersion,         // use 100 for ES environment, 110 for desktop
+    EProfile defaultProfile,
+    bool forceDefaultVersionAndProfile,
+    bool forwardCompatible,     // give errors for use of deprecated features
+    EShMessages messages,       // warnings/errors/AST; things to print out
+    TShader::Includer& includer,
+    TIntermediate& intermediate, // returned tree, etc.
+    std::string* outputString)
+{
+    DoPreprocessing parser(outputString);
+    return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
+                           preamble, optLevel, resources, defaultVersion,
+                           defaultProfile, forceDefaultVersionAndProfile,
+                           forwardCompatible, messages, intermediate, parser,
+                           false, includer);
+}
+
+//
+// do a partial compile on the given strings for a single compilation unit
+// for a potential deferred link into a single stage (and deferred full compile of that
+// stage through machine-dependent compilation).
+//
+// all preprocessing, parsing, semantic checks, etc. for a single compilation unit
+// are done here.
+//
+// return:  the tree and other information is filled into the intermediate argument,
+//          and true is returned by the function for success.
+//
+bool CompileDeferred(
+    TCompiler* compiler,
+    const char* const shaderStrings[],
+    const int numStrings,
+    const int* inputLengths,
+    const char* const stringNames[],
+    const char* preamble,
+    const EShOptimizationLevel optLevel,
+    const TBuiltInResource* resources,
+    int defaultVersion,         // use 100 for ES environment, 110 for desktop
+    EProfile defaultProfile,
+    bool forceDefaultVersionAndProfile,
+    bool forwardCompatible,     // give errors for use of deprecated features
+    EShMessages messages,       // warnings/errors/AST; things to print out
+    TIntermediate& intermediate,// returned tree, etc.
+    TShader::Includer& includer,
+    const std::string sourceEntryPointName = "")
+{
+    DoFullParse parser;
+    return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
+                           preamble, optLevel, resources, defaultVersion,
+                           defaultProfile, forceDefaultVersionAndProfile,
+                           forwardCompatible, messages, intermediate, parser,
+                           true, includer, sourceEntryPointName);
+}
+
+} // end anonymous namespace for local functions
+
+//
+// ShInitialize() should be called exactly once per process, not per thread.
+//
+int ShInitialize()
+{
+    glslang::InitGlobalLock();
+
+    if (! InitProcess())
+        return 0;
+
+    if (! PerProcessGPA)
+        PerProcessGPA = new TPoolAllocator();
+
+    glslang::TScanContext::fillInKeywordMap();
+#ifdef ENABLE_HLSL
+    glslang::HlslScanContext::fillInKeywordMap();
+#endif
+
+    return 1;
+}
+
+//
+// Driver calls these to create and destroy compiler/linker
+// objects.
+//
+
+ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions)
+{
+    if (!InitThread())
+        return 0;
+
+    TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, debugOptions));
+
+    return reinterpret_cast<void*>(base);
+}
+
+ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions)
+{
+    if (!InitThread())
+        return 0;
+
+    TShHandleBase* base = static_cast<TShHandleBase*>(ConstructLinker(executable, debugOptions));
+
+    return reinterpret_cast<void*>(base);
+}
+
+ShHandle ShConstructUniformMap()
+{
+    if (!InitThread())
+        return 0;
+
+    TShHandleBase* base = static_cast<TShHandleBase*>(ConstructUniformMap());
+
+    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());
+    else if (base->getAsLinker())
+        DeleteLinker(base->getAsLinker());
+    else if (base->getAsUniformMap())
+        DeleteUniformMap(base->getAsUniformMap());
+}
+
+//
+// Cleanup symbol tables
+//
+int __fastcall ShFinalize()
+{
+    for (int version = 0; version < VersionCount; ++version) {
+        for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
+            for (int p = 0; p < ProfileCount; ++p) {
+                for (int source = 0; source < SourceCount; ++source) {
+                    for (int stage = 0; stage < EShLangCount; ++stage) {
+                        delete SharedSymbolTables[version][spvVersion][p][source][stage];
+                        SharedSymbolTables[version][spvVersion][p][source][stage] = 0;
+                    }
+                }
+            }
+        }
+    }
+
+    for (int version = 0; version < VersionCount; ++version) {
+        for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
+            for (int p = 0; p < ProfileCount; ++p) {
+                for (int source = 0; source < SourceCount; ++source) {
+                    for (int pc = 0; pc < EPcCount; ++pc) {
+                        delete CommonSymbolTable[version][spvVersion][p][source][pc];
+                        CommonSymbolTable[version][spvVersion][p][source][pc] = 0;
+                    }
+                }
+            }
+        }
+    }
+
+    if (PerProcessGPA) {
+        PerProcessGPA->popAll();
+        delete PerProcessGPA;
+        PerProcessGPA = 0;
+    }
+
+    glslang::TScanContext::deleteKeywordMap();
+#ifdef ENABLE_HLSL
+    glslang::HlslScanContext::deleteKeywordMap();
+#endif
+
+    return 1;
+}
+
+//
+// Do a full compile on the given strings for a single compilation unit
+// forming a complete stage.  The result of the machine dependent compilation
+// is left in the provided compile object.
+//
+// Return:  The return value is really boolean, indicating
+// success (1) or failure (0).
+//
+int ShCompile(
+    const ShHandle handle,
+    const char* const shaderStrings[],
+    const int numStrings,
+    const int* inputLengths,
+    const EShOptimizationLevel optLevel,
+    const TBuiltInResource* resources,
+    int /*debugOptions*/,
+    int defaultVersion,        // use 100 for ES environment, 110 for desktop
+    bool forwardCompatible,    // give errors for use of deprecated features
+    EShMessages messages       // warnings/errors/AST; things to print out
+    )
+{
+    // Map the generic handle to the C++ object
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+    TCompiler* compiler = base->getAsCompiler();
+    if (compiler == 0)
+        return 0;
+
+    compiler->infoSink.info.erase();
+    compiler->infoSink.debug.erase();
+
+    TIntermediate intermediate(compiler->getLanguage());
+    TShader::ForbidIncluder includer;
+    bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
+                                   "", optLevel, resources, defaultVersion, ENoProfile, false,
+                                   forwardCompatible, messages, intermediate, includer);
+
+    //
+    // Call the machine dependent compiler
+    //
+    if (success && intermediate.getTreeRoot() && optLevel != EShOptNoGeneration)
+        success = compiler->compile(intermediate.getTreeRoot(), intermediate.getVersion(), intermediate.getProfile());
+
+    intermediate.removeTree();
+
+    // Throw away all the temporary memory used by the compilation process.
+    // The push was done in the CompileDeferred() call above.
+    GetThreadPoolAllocator().pop();
+
+    return success ? 1 : 0;
+}
+
+//
+// Link the given compile objects.
+//
+// Return:  The return value of is really boolean, indicating
+// success or failure.
+//
+int ShLinkExt(
+    const ShHandle linkHandle,
+    const ShHandle compHandles[],
+    const int numHandles)
+{
+    if (linkHandle == 0 || numHandles == 0)
+        return 0;
+
+    THandleList cObjects;
+
+    for (int i = 0; i < numHandles; ++i) {
+        if (compHandles[i] == 0)
+            return 0;
+        TShHandleBase* base = reinterpret_cast<TShHandleBase*>(compHandles[i]);
+        if (base->getAsLinker()) {
+            cObjects.push_back(base->getAsLinker());
+        }
+        if (base->getAsCompiler())
+            cObjects.push_back(base->getAsCompiler());
+
+        if (cObjects[i] == 0)
+            return 0;
+    }
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(linkHandle);
+    TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
+
+    if (linker == 0)
+        return 0;
+
+    linker->infoSink.info.erase();
+
+    for (int i = 0; i < numHandles; ++i) {
+        if (cObjects[i]->getAsCompiler()) {
+            if (! cObjects[i]->getAsCompiler()->linkable()) {
+                linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code.");
+                return 0;
+            }
+        }
+    }
+
+    bool ret = linker->link(cObjects);
+
+    return ret ? 1 : 0;
+}
+
+//
+// ShSetEncrpytionMethod is a place-holder for specifying
+// how source code is encrypted.
+//
+void ShSetEncryptionMethod(ShHandle handle)
+{
+    if (handle == 0)
+        return;
+}
+
+//
+// Return any compiler/linker/uniformmap log of messages for the application.
+//
+const char* ShGetInfoLog(const ShHandle handle)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+    TInfoSink* infoSink;
+
+    if (base->getAsCompiler())
+        infoSink = &(base->getAsCompiler()->getInfoSink());
+    else if (base->getAsLinker())
+        infoSink = &(base->getAsLinker()->getInfoSink());
+    else
+        return 0;
+
+    infoSink->info << infoSink->debug.c_str();
+    return infoSink->info.c_str();
+}
+
+//
+// Return the resulting binary code from the link process.  Structure
+// is machine dependent.
+//
+const void* ShGetExecutable(const ShHandle handle)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+
+    TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
+    if (linker == 0)
+        return 0;
+
+    return linker->getObjectCode();
+}
+
+//
+// Let the linker know where the application said it's attributes are bound.
+// The linker does not use these values, they are remapped by the ICD or
+// hardware.  It just needs them to know what's aliased.
+//
+// Return:  The return value of is really boolean, indicating
+// success or failure.
+//
+int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+    TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
+
+    if (linker == 0)
+        return 0;
+
+    linker->setAppAttributeBindings(table);
+
+    return 1;
+}
+
+//
+// Let the linker know where the predefined attributes have to live.
+//
+int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+    TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
+
+    if (linker == 0)
+        return 0;
+
+    linker->setFixedAttributeBindings(table);
+    return 1;
+}
+
+//
+// Some attribute locations are off-limits to the linker...
+//
+int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return 0;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+    TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
+    if (linker == 0)
+        return 0;
+
+    linker->setExcludedAttributes(attributes, count);
+
+    return 1;
+}
+
+//
+// Return the index for OpenGL to use for knowing where a uniform lives.
+//
+// Return:  The return value of is really boolean, indicating
+// success or failure.
+//
+int ShGetUniformLocation(const ShHandle handle, const char* name)
+{
+    if (!InitThread())
+        return 0;
+
+    if (handle == 0)
+        return -1;
+
+    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+    TUniformMap* uniformMap= base->getAsUniformMap();
+    if (uniformMap == 0)
+        return -1;
+
+    return uniformMap->getLocation(name);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Deferred-Lowering C++ Interface
+// -----------------------------------
+//
+// Below is a new alternate C++ interface that might potentially replace the above
+// opaque handle-based interface.
+//
+// See more detailed comment in ShaderLang.h
+//
+
+namespace glslang {
+
+#include "../Include/revision.h"
+
+const char* GetEsslVersionString()
+{
+    return "OpenGL ES GLSL 3.00 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
+}
+
+const char* GetGlslVersionString()
+{
+    return "4.20 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
+}
+
+int GetKhronosToolId()
+{
+    return 8;
+}
+
+bool InitializeProcess()
+{
+    return ShInitialize() != 0;
+}
+
+void FinalizeProcess()
+{
+    ShFinalize();
+}
+
+class TDeferredCompiler : public TCompiler {
+public:
+    TDeferredCompiler(EShLanguage s, TInfoSink& i) : TCompiler(s, i) { }
+    virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
+};
+
+TShader::TShader(EShLanguage s)
+    : pool(0), stage(s), lengths(nullptr), stringNames(nullptr), preamble("")
+{
+    infoSink = new TInfoSink;
+    compiler = new TDeferredCompiler(stage, *infoSink);
+    intermediate = new TIntermediate(s);
+}
+
+TShader::~TShader()
+{
+    delete infoSink;
+    delete compiler;
+    delete intermediate;
+    delete pool;
+}
+
+void TShader::setStrings(const char* const* s, int n)
+{
+    strings = s;
+    numStrings = n;
+    lengths = nullptr;
+}
+
+void TShader::setStringsWithLengths(const char* const* s, const int* l, int n)
+{
+    strings = s;
+    numStrings = n;
+    lengths = l;
+}
+
+void TShader::setStringsWithLengthsAndNames(
+    const char* const* s, const int* l, const char* const* names, int n)
+{
+    strings = s;
+    numStrings = n;
+    lengths = l;
+    stringNames = names;
+}
+
+void TShader::setEntryPoint(const char* entryPoint)
+{
+    intermediate->setEntryPointName(entryPoint);
+}
+
+void TShader::setSourceEntryPoint(const char* name)
+{
+    sourceEntryPointName = name;
+}
+
+void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
+void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
+void TShader::setShiftImageBinding(unsigned int base)   { intermediate->setShiftImageBinding(base); }
+void TShader::setShiftUboBinding(unsigned int base)     { intermediate->setShiftUboBinding(base); }
+void TShader::setAutoMapBindings(bool map)              { intermediate->setAutoMapBindings(map); }
+void TShader::setFlattenUniformArrays(bool flatten)     { intermediate->setFlattenUniformArrays(flatten); }
+void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
+
+//
+// Turn the shader strings into a parse tree in the TIntermediate.
+//
+// Returns true for success.
+//
+bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
+                    bool forwardCompatible, EShMessages messages, Includer& includer)
+{
+    if (! InitThread())
+        return false;
+
+    pool = new TPoolAllocator();
+    SetThreadPoolAllocator(*pool);
+    if (! preamble)
+        preamble = "";
+
+    return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
+                           preamble, EShOptNone, builtInResources, defaultVersion,
+                           defaultProfile, forceDefaultVersionAndProfile,
+                           forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
+}
+
+bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages)
+{
+    return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages);
+}
+
+// Fill in a string with the result of preprocessing ShaderStrings
+// Returns true if all extensions, pragmas and version strings were valid.
+bool TShader::preprocess(const TBuiltInResource* builtInResources,
+                         int defaultVersion, EProfile defaultProfile,
+                         bool forceDefaultVersionAndProfile,
+                         bool forwardCompatible, EShMessages message,
+                         std::string* output_string,
+                         Includer& includer)
+{
+    if (! InitThread())
+        return false;
+
+    pool = new TPoolAllocator();
+    SetThreadPoolAllocator(*pool);
+    if (! preamble)
+        preamble = "";
+
+    return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble,
+                              EShOptNone, builtInResources, defaultVersion,
+                              defaultProfile, forceDefaultVersionAndProfile,
+                              forwardCompatible, message, includer, *intermediate, output_string);
+}
+
+const char* TShader::getInfoLog()
+{
+    return infoSink->info.c_str();
+}
+
+const char* TShader::getInfoDebugLog()
+{
+    return infoSink->debug.c_str();
+}
+
+TProgram::TProgram() : pool(0), reflection(0), ioMapper(nullptr), linked(false)
+{
+    infoSink = new TInfoSink;
+    for (int s = 0; s < EShLangCount; ++s) {
+        intermediate[s] = 0;
+        newedIntermediate[s] = false;
+    }
+}
+
+TProgram::~TProgram()
+{
+    delete infoSink;
+    delete reflection;
+
+    for (int s = 0; s < EShLangCount; ++s)
+        if (newedIntermediate[s])
+            delete intermediate[s];
+
+    delete pool;
+}
+
+//
+// Merge the compilation units within each stage into a single TIntermediate.
+// All starting compilation units need to be the result of calling TShader::parse().
+//
+// Return true for success.
+//
+bool TProgram::link(EShMessages messages)
+{
+    if (linked)
+        return false;
+    linked = true;
+
+    bool error = false;
+
+    pool = new TPoolAllocator();
+    SetThreadPoolAllocator(*pool);
+
+    for (int s = 0; s < EShLangCount; ++s) {
+        if (! linkStage((EShLanguage)s, messages))
+            error = true;
+    }
+
+    // TODO: Link: cross-stage error checking
+
+    return ! error;
+}
+
+//
+// Merge the compilation units within the given stage into a single TIntermediate.
+//
+// Return true for success.
+//
+bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
+{
+    if (stages[stage].size() == 0)
+        return true;
+
+    int numEsShaders = 0, numNonEsShaders = 0;
+    for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) {
+        if ((*it)->intermediate->getProfile() == EEsProfile) {
+            numEsShaders++;
+        } else {
+            numNonEsShaders++;
+        }
+    }
+
+    if (numEsShaders > 0 && numNonEsShaders > 0) {
+        infoSink->info.message(EPrefixError, "Cannot mix ES profile with non-ES profile shaders");
+        return false;
+    } else if (numEsShaders > 1) {
+        infoSink->info.message(EPrefixError, "Cannot attach multiple ES shaders of the same type to a single program");
+        return false;
+    }
+
+    //
+    // Be efficient for the common single compilation unit per stage case,
+    // reusing it's TIntermediate instead of merging into a new one.
+    //
+    TIntermediate *firstIntermediate = stages[stage].front()->intermediate;
+    if (stages[stage].size() == 1)
+        intermediate[stage] = firstIntermediate;
+    else {
+        intermediate[stage] = new TIntermediate(stage,
+                                                firstIntermediate->getVersion(),
+                                                firstIntermediate->getProfile());
+        newedIntermediate[stage] = true;
+    }
+
+    if (messages & EShMsgAST)
+        infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
+
+    if (stages[stage].size() > 1) {
+        std::list<TShader*>::const_iterator it;
+        for (it = stages[stage].begin(); it != stages[stage].end(); ++it)
+            intermediate[stage]->merge(*infoSink, *(*it)->intermediate);
+    }
+
+    intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0);
+
+    if (messages & EShMsgAST)
+        intermediate[stage]->output(*infoSink, true);
+
+    return intermediate[stage]->getNumErrors() == 0;
+}
+
+const char* TProgram::getInfoLog()
+{
+    return infoSink->info.c_str();
+}
+
+const char* TProgram::getInfoDebugLog()
+{
+    return infoSink->debug.c_str();
+}
+
+//
+// Reflection implementation.
+//
+
+bool TProgram::buildReflection()
+{
+    if (! linked || reflection)
+        return false;
+
+    reflection = new TReflection;
+
+    for (int s = 0; s < EShLangCount; ++s) {
+        if (intermediate[s]) {
+            if (! reflection->addStage((EShLanguage)s, *intermediate[s]))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+int TProgram::getNumLiveUniformVariables() const             { return reflection->getNumUniforms(); }
+int TProgram::getNumLiveUniformBlocks() const                { return reflection->getNumUniformBlocks(); }
+const char* TProgram::getUniformName(int index) const        { return reflection->getUniform(index).name.c_str(); }
+const char* TProgram::getUniformBlockName(int index) const   { return reflection->getUniformBlock(index).name.c_str(); }
+int TProgram::getUniformBlockSize(int index) const           { return reflection->getUniformBlock(index).size; }
+int TProgram::getUniformIndex(const char* name) const        { return reflection->getIndex(name); }
+int TProgram::getUniformBlockIndex(int index) const          { return reflection->getUniform(index).index; }
+int TProgram::getUniformType(int index) const                { return reflection->getUniform(index).glDefineType; }
+int TProgram::getUniformBufferOffset(int index) const        { return reflection->getUniform(index).offset; }
+int TProgram::getUniformArraySize(int index) const           { return reflection->getUniform(index).size; }
+int TProgram::getNumLiveAttributes() const                   { return reflection->getNumAttributes(); }
+const char* TProgram::getAttributeName(int index) const      { return reflection->getAttribute(index).name.c_str(); }
+int TProgram::getAttributeType(int index) const              { return reflection->getAttribute(index).glDefineType; }
+const TType* TProgram::getAttributeTType(int index) const    { return reflection->getAttribute(index).getType(); }
+const TType* TProgram::getUniformTType(int index) const      { return reflection->getUniform(index).getType(); }
+const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
+
+void TProgram::dumpReflection()                      { reflection->dump(); }
+
+//
+// I/O mapping implementation.
+//
+bool TProgram::mapIO(TIoMapResolver* resolver)
+{
+    if (! linked || ioMapper)
+        return false;
+
+    ioMapper = new TIoMapper;
+
+    for (int s = 0; s < EShLangCount; ++s) {
+        if (intermediate[s]) {
+            if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, resolver))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+} // end namespace glslang

+ 355 - 0
src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp

@@ -0,0 +1,355 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Symbol table for parsing.  Most functionality and main ideas
+// are documented in the header file.
+//
+
+#include "SymbolTable.h"
+
+namespace glslang {
+
+//
+// TType helper function needs a place to live.
+//
+
+//
+// Recursively generate mangled names.
+//
+void TType::buildMangledName(TString& mangledName)
+{
+    if (isMatrix())
+        mangledName += 'm';
+    else if (isVector())
+        mangledName += 'v';
+
+    switch (basicType) {
+    case EbtFloat:              mangledName += 'f';      break;
+    case EbtDouble:             mangledName += 'd';      break;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:            mangledName += "f16";    break;
+#endif
+    case EbtInt:                mangledName += 'i';      break;
+    case EbtUint:               mangledName += 'u';      break;
+    case EbtInt64:              mangledName += "i64";    break;
+    case EbtUint64:             mangledName += "u64";    break;
+    case EbtBool:               mangledName += 'b';      break;
+    case EbtAtomicUint:         mangledName += "au";     break;
+    case EbtSampler:
+        switch (sampler.type) {
+        case EbtInt:   mangledName += "i"; break;
+        case EbtUint:  mangledName += "u"; break;
+        default: break; // some compilers want this
+        }
+        if (sampler.image)
+            mangledName += "I";  // a normal image
+        else if (sampler.sampler)
+            mangledName += "p";  // a "pure" sampler
+        else if (!sampler.combined)
+            mangledName += "t";  // a "pure" texture
+        else
+            mangledName += "s";  // traditional combined sampler
+        if (sampler.arrayed)
+            mangledName += "A";
+        if (sampler.shadow)
+            mangledName += "S";
+        if (sampler.external)
+            mangledName += "E";
+        switch (sampler.dim) {
+        case Esd1D:       mangledName += "1";  break;
+        case Esd2D:       mangledName += "2";  break;
+        case Esd3D:       mangledName += "3";  break;
+        case EsdCube:     mangledName += "C";  break;
+        case EsdRect:     mangledName += "R2"; break;
+        case EsdBuffer:   mangledName += "B";  break;
+        case EsdSubpass:  mangledName += "P";  break;
+        default: break; // some compilers want this
+        }
+        if (sampler.ms)
+            mangledName += "M";
+        break;
+    case EbtStruct:
+        mangledName += "struct-";
+        if (typeName)
+            mangledName += *typeName;
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            mangledName += '-';
+            (*structure)[i].type->buildMangledName(mangledName);
+        }
+    default:
+        break;
+    }
+
+    if (getVectorSize() > 0)
+        mangledName += static_cast<char>('0' + getVectorSize());
+    else {
+        mangledName += static_cast<char>('0' + getMatrixCols());
+        mangledName += static_cast<char>('0' + getMatrixRows());
+    }
+
+    if (arraySizes) {
+        const int maxSize = 11;
+        char buf[maxSize];
+        for (int i = 0; i < arraySizes->getNumDims(); ++i) {
+            if (arraySizes->getDimNode(i)) {
+                if (arraySizes->getDimNode(i)->getAsSymbolNode())
+                    snprintf(buf, maxSize, "s%d", arraySizes->getDimNode(i)->getAsSymbolNode()->getId());
+                else
+                    snprintf(buf, maxSize, "s%p", arraySizes->getDimNode(i));
+            } else
+                snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
+            mangledName += '[';
+            mangledName += buf;
+            mangledName += ']';
+        }
+    }
+}
+
+//
+// Dump functions.
+//
+
+void TVariable::dump(TInfoSink& infoSink) const
+{
+    infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicTypeString();
+    if (type.isArray()) {
+        infoSink.debug << "[0]";
+    }
+    infoSink.debug << "\n";
+}
+
+void TFunction::dump(TInfoSink& infoSink) const
+{
+    infoSink.debug << getName().c_str() << ": " <<  returnType.getBasicTypeString() << " " << getMangledName().c_str() << "\n";
+}
+
+void TAnonMember::dump(TInfoSink& TInfoSink) const
+{
+    TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().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)
+        delete (*it).second;
+
+    delete [] defaultPrecision;
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in operation.
+//
+void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
+{
+    tLevel::const_iterator candidate = level.lower_bound(name);
+    while (candidate != level.end()) {
+        const TString& candidateName = (*candidate).first;
+        TString::size_type parenAt = candidateName.find_first_of('(');
+        if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
+            TFunction* function = (*candidate).second->getAsFunction();
+            function->relateToOperator(op);
+        } else
+            break;
+        ++candidate;
+    }
+}
+
+// Make all function overloads of the given name require an extension(s).
+// Should only be used for a version/profile that actually needs the extension(s).
+void TSymbolTableLevel::setFunctionExtensions(const char* name, int num, const char* const extensions[])
+{
+    tLevel::const_iterator candidate = level.lower_bound(name);
+    while (candidate != level.end()) {
+        const TString& candidateName = (*candidate).first;
+        TString::size_type parenAt = candidateName.find_first_of('(');
+        if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
+            TSymbol* symbol = candidate->second;
+            symbol->setExtensions(num, extensions);
+        } else
+            break;
+        ++candidate;
+    }
+}
+
+//
+// Make all symbols in this table level read only.
+//
+void TSymbolTableLevel::readOnly()
+{
+    for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+        (*it).second->makeReadOnly();
+}
+
+//
+// Copy a symbol, but the copy is writable; call readOnly() afterward if that's not desired.
+//
+TSymbol::TSymbol(const TSymbol& copyOf)
+{
+    name = NewPoolTString(copyOf.name->c_str());
+    uniqueId = copyOf.uniqueId;
+    writable = true;
+}
+
+TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
+{
+    type.deepCopy(copyOf.type);
+    userType = copyOf.userType;
+    numExtensions = 0;
+    extensions = 0;
+    if (copyOf.numExtensions != 0)
+        setExtensions(copyOf.numExtensions, copyOf.extensions);
+
+    if (! copyOf.constArray.empty()) {
+        assert(! copyOf.type.isStruct());
+        TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
+        constArray = newArray;
+    }
+
+    // don't support specialization-constant subtrees in cloned tables
+    constSubtree = nullptr;
+}
+
+TVariable* TVariable::clone() const
+{
+    TVariable *variable = new TVariable(*this);
+
+    return variable;
+}
+
+TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
+{
+    for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
+        TParameter param;
+        parameters.push_back(param);
+        parameters.back().copyParam(copyOf.parameters[i]);
+    }
+
+    numExtensions = 0;
+    extensions = 0;
+    if (copyOf.extensions != 0)
+        setExtensions(copyOf.numExtensions, copyOf.extensions);
+    returnType.deepCopy(copyOf.returnType);
+    mangledName = copyOf.mangledName;
+    op = copyOf.op;
+    defined = copyOf.defined;
+    prototyped = copyOf.prototyped;
+    defaultParamCount = copyOf.defaultParamCount;
+}
+
+TFunction* TFunction::clone() const
+{
+    TFunction *function = new TFunction(*this);
+
+    return function;
+}
+
+TAnonMember* TAnonMember::clone() const
+{
+    // Anonymous members of a given block should be cloned at a higher level,
+    // where they can all be assured to still end up pointing to a single
+    // copy of the original container.
+    assert(0);
+
+    return 0;
+}
+
+TSymbolTableLevel* TSymbolTableLevel::clone() const
+{
+    TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
+    symTableLevel->anonId = anonId;
+    std::vector<bool> containerCopied(anonId, false);
+    tLevel::const_iterator iter;
+    for (iter = level.begin(); iter != level.end(); ++iter) {
+        const TAnonMember* anon = iter->second->getAsAnonMember();
+        if (anon) {
+            // Insert all the anonymous members of this same container at once,
+            // avoid inserting the other members in the future, once this has been done,
+            // allowing them to all be part of the same new container.
+            if (! containerCopied[anon->getAnonId()]) {
+                TVariable* container = anon->getAnonContainer().clone();
+                container->changeName(NewPoolTString(""));
+                // insert the whole container
+                symTableLevel->insert(*container, false);
+                containerCopied[anon->getAnonId()] = true;
+            }
+        } else
+            symTableLevel->insert(*iter->second->clone(), false);
+    }
+
+    return symTableLevel;
+}
+
+void TSymbolTable::copyTable(const TSymbolTable& copyOf)
+{
+    assert(adoptedLevels == copyOf.adoptedLevels);
+
+    uniqueId = copyOf.uniqueId;
+    noBuiltInRedeclarations = copyOf.noBuiltInRedeclarations;
+    separateNameSpaces = copyOf.separateNameSpaces;
+    for (unsigned int i = copyOf.adoptedLevels; i < copyOf.table.size(); ++i)
+        table.push_back(copyOf.table[i]->clone());
+}
+
+} // end namespace glslang

+ 728 - 0
src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h

@@ -0,0 +1,728 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#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.
+//
+// -->  This requires a copy mechanism, so initial pools used to create
+//   the shared information can be popped.  Done through "clone"
+//   methods.
+//
+// * 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 "../Include/Common.h"
+#include "../Include/intermediate.h"
+#include "../Include/InfoSink.h"
+
+namespace glslang {
+
+//
+// Symbol base class.  (Can build functions or variables out of these...)
+//
+
+class TVariable;
+class TFunction;
+class TAnonMember;
+
+class TSymbol {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    explicit TSymbol(const TString *n) :  name(n), numExtensions(0), extensions(0), writable(true) { }
+    virtual TSymbol* clone() const = 0;
+    virtual ~TSymbol() { }  // rely on all symbol owned memory coming from the pool
+
+    virtual const TString& getName() const { return *name; }
+    virtual void changeName(const TString* newName) { name = newName; }
+    virtual const TString& getMangledName() const { return getName(); }
+    virtual TFunction* getAsFunction() { return 0; }
+    virtual const TFunction* getAsFunction() const { return 0; }
+    virtual TVariable* getAsVariable() { return 0; }
+    virtual const TVariable* getAsVariable() const { return 0; }
+    virtual const TAnonMember* getAsAnonMember() const { return 0; }
+    virtual const TType& getType() const = 0;
+    virtual TType& getWritableType() = 0;
+    virtual void setUniqueId(int id) { uniqueId = id; }
+    virtual int getUniqueId() const { return uniqueId; }
+    virtual void setExtensions(int num, const char* const exts[])
+    {
+        assert(extensions == 0);
+        assert(num > 0);
+        numExtensions = num;
+        extensions = NewPoolObject(exts[0], num);
+        for (int e = 0; e < num; ++e)
+            extensions[e] = exts[e];
+    }
+    virtual int getNumExtensions() const { return numExtensions; }
+    virtual const char** getExtensions() const { return extensions; }
+    virtual void dump(TInfoSink &infoSink) const = 0;
+
+    virtual bool isReadOnly() const { return ! writable; }
+    virtual void makeReadOnly() { writable = false; }
+
+protected:
+    explicit TSymbol(const TSymbol&);
+    TSymbol& operator=(const TSymbol&);
+
+    const TString *name;
+    unsigned int uniqueId;      // For cross-scope comparing during code generation
+
+    // For tracking what extensions must be present
+    // (don't use if correct version/profile is present).
+    int numExtensions;
+    const char** extensions; // an array of pointers to existing constant char strings
+
+    //
+    // N.B.: Non-const functions that will be generally used should assert on this,
+    // to avoid overwriting shared symbol-table information.
+    //
+    bool writable;
+};
+
+//
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class hierarchy 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),
+          userType(uT),
+          constSubtree(nullptr),
+          anonId(-1) { type.shallowCopy(t); }
+    virtual TVariable* clone() const;
+    virtual ~TVariable() { }
+
+    virtual TVariable* getAsVariable() { return this; }
+    virtual const TVariable* getAsVariable() const { return this; }
+    virtual const TType& getType() const { return type; }
+    virtual TType& getWritableType() { assert(writable); return type; }
+    virtual bool isUserType() const { return userType; }
+    virtual const TConstUnionArray& getConstArray() const { return constArray; }
+    virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
+    virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
+    virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
+    virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
+    virtual void setAnonId(int i) { anonId = i; }
+    virtual int getAnonId() const { return anonId; }
+
+    virtual void dump(TInfoSink &infoSink) const;
+
+protected:
+    explicit TVariable(const TVariable&);
+    TVariable& operator=(const TVariable&);
+
+    TType type;
+    bool userType;
+    // we are assuming that Pool Allocator will free the memory allocated to unionArray
+    // when this object is destroyed
+
+    // TODO: these two should be a union
+    // A variable could be a compile-time constant, or a specialization
+    // constant, or neither, but never both.
+    TConstUnionArray constArray;  // for compile-time constant value
+    TIntermTyped* constSubtree;   // for specialization constant computation
+    int anonId;                   // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
+};
+
+//
+// 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;
+    TIntermTyped* defaultValue;
+    void copyParam(const TParameter& param)
+    {
+        if (param.name)
+            name = NewPoolTString(param.name->c_str());
+        else
+            name = 0;
+        type = param.type->clone();
+        defaultValue = param.defaultValue;
+    }
+};
+
+//
+// The function sub-class of a symbol.
+//
+class TFunction : public TSymbol {
+public:
+    explicit TFunction(TOperator o) :
+        TSymbol(0),
+        op(o),
+        defined(false), prototyped(false), defaultParamCount(0) { }
+    TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
+        TSymbol(name),
+        mangledName(*name + '('),
+        op(tOp),
+        defined(false), prototyped(false), defaultParamCount(0) { returnType.shallowCopy(retType); }
+    virtual TFunction* clone() const;
+    virtual ~TFunction();
+
+    virtual TFunction* getAsFunction() { return this; }
+    virtual const TFunction* getAsFunction() const { return this; }
+
+    virtual void addParameter(TParameter& p)
+    {
+        assert(writable);
+        parameters.push_back(p);
+        p.type->appendMangledName(mangledName);
+
+        if (p.defaultValue != nullptr)
+            defaultParamCount++;
+    }
+
+    virtual const TString& getMangledName() const { return mangledName; }
+    virtual const TType& getType() const { return returnType; }
+    virtual TType& getWritableType() { return returnType; }
+    virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
+    virtual TOperator getBuiltInOp() const { return op; }
+    virtual void setDefined() { assert(writable); defined = true; }
+    virtual bool isDefined() const { return defined; }
+    virtual void setPrototyped() { assert(writable); prototyped = true; }
+    virtual bool isPrototyped() const { return prototyped; }
+
+    // Return total number of parameters
+    virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
+    // Return number of parameters with default values.
+    virtual int getDefaultParamCount() const { return defaultParamCount; }
+    // Return number of fixed parameters (without default values)
+    virtual int getFixedParamCount() const { return getParamCount() - getDefaultParamCount(); }
+
+    virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
+    virtual const TParameter& operator[](int i) const { return parameters[i]; }
+
+    virtual void dump(TInfoSink &infoSink) const;
+
+protected:
+    explicit TFunction(const TFunction&);
+    TFunction& operator=(const TFunction&);
+
+    typedef TVector<TParameter> TParamList;
+    TParamList parameters;
+    TType returnType;
+    TString mangledName;
+    TOperator op;
+    bool defined;
+    bool prototyped;
+    int  defaultParamCount;
+};
+
+//
+// Members of anonymous blocks are a kind of TSymbol.  They are not hidden in
+// the symbol table behind a container; rather they are visible and point to
+// their anonymous container.  (The anonymous container is found through the
+// member, not the other way around.)
+//
+class TAnonMember : public TSymbol {
+public:
+    TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
+    virtual TAnonMember* clone() const;
+    virtual ~TAnonMember() { }
+
+    virtual const TAnonMember* getAsAnonMember() const { return this; }
+    virtual const TVariable& getAnonContainer() const { return anonContainer; }
+    virtual unsigned int getMemberNumber() const { return memberNumber; }
+
+    virtual const TType& getType() const
+    {
+        const TTypeList& types = *anonContainer.getType().getStruct();
+        return *types[memberNumber].type;
+    }
+
+    virtual TType& getWritableType()
+    {
+        assert(writable);
+        const TTypeList& types = *anonContainer.getType().getStruct();
+        return *types[memberNumber].type;
+    }
+
+    virtual int getAnonId() const { return anonId; }
+    virtual void dump(TInfoSink &infoSink) const;
+
+protected:
+    explicit TAnonMember(const TAnonMember&);
+    TAnonMember& operator=(const TAnonMember&);
+
+    const TVariable& anonContainer;
+    unsigned int memberNumber;
+    int anonId;
+};
+
+class TSymbolTableLevel {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    TSymbolTableLevel() : defaultPrecision(0), anonId(0) { }
+    ~TSymbolTableLevel();
+
+    bool insert(TSymbol& symbol, bool separateNameSpaces)
+    {
+        //
+        // returning true means symbol was added to the table with no semantic errors
+        //
+        const TString& name = symbol.getName();
+        if (name == "") {
+            symbol.getAsVariable()->setAnonId(anonId++);
+            // An empty name means an anonymous container, exposing its members to the external scope.
+            // Give it a name and insert its members in the symbol table, pointing to the container.
+            char buf[20];
+            snprintf(buf, 20, "%s%d", AnonymousPrefix, symbol.getAsVariable()->getAnonId());
+            symbol.changeName(NewPoolTString(buf));
+
+            return insertAnonymousMembers(symbol, 0);
+        } else {
+            // Check for redefinition errors:
+            // - STL itself will tell us if there is a direct name collision, with name mangling, at this level
+            // - additionally, check for function-redefining-variable name collisions
+            const TString& insertName = symbol.getMangledName();
+            if (symbol.getAsFunction()) {
+                // make sure there isn't a variable of this name
+                if (! separateNameSpaces && level.find(name) != level.end())
+                    return false;
+
+                // insert, and whatever happens is okay
+                level.insert(tLevelPair(insertName, &symbol));
+
+                return true;
+            } else
+                return level.insert(tLevelPair(insertName, &symbol)).second;
+        }
+    }
+
+    // Add more members to an already inserted aggregate object
+    bool amend(TSymbol& symbol, int firstNewMember)
+    {
+        // See insert() for comments on basic explanation of insert.
+        // This operates similarly, but more simply.
+        // Only supporting amend of anonymous blocks so far.
+        if (IsAnonymous(symbol.getName()))
+            return insertAnonymousMembers(symbol, firstNewMember);
+        else
+            return false;
+    }
+
+    bool insertAnonymousMembers(TSymbol& symbol, int firstMember)
+    {
+        const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
+        for (unsigned int m = firstMember; m < types.size(); ++m) {
+            TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), symbol.getAsVariable()->getAnonId());
+            if (! level.insert(tLevelPair(member->getMangledName(), member)).second)
+                return false;
+        }
+
+        return true;
+    }
+
+    TSymbol* find(const TString& name) const
+    {
+        tLevel::const_iterator it = level.find(name);
+        if (it == level.end())
+            return 0;
+        else
+            return (*it).second;
+    }
+
+    void findFunctionNameList(const TString& name, TVector<const TFunction*>& list)
+    {
+        size_t parenAt = name.find_first_of('(');
+        TString base(name, 0, parenAt + 1);
+
+        tLevel::const_iterator begin = level.lower_bound(base);
+        base[parenAt] = ')';  // assume ')' is lexically after '('
+        tLevel::const_iterator end = level.upper_bound(base);
+        for (tLevel::const_iterator it = begin; it != end; ++it)
+            list.push_back(it->second->getAsFunction());
+    }
+
+    // See if there is already a function in the table having the given non-function-style name.
+    bool hasFunctionName(const TString& name) const
+    {
+        tLevel::const_iterator candidate = level.lower_bound(name);
+        if (candidate != level.end()) {
+            const TString& candidateName = (*candidate).first;
+            TString::size_type parenAt = candidateName.find_first_of('(');
+            if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0)
+
+                return true;
+        }
+
+        return false;
+    }
+
+    // See if there is a variable at this level having the given non-function-style name.
+    // Return true if name is found, and set variable to true if the name was a variable.
+    bool findFunctionVariableName(const TString& name, bool& variable) const
+    {
+        tLevel::const_iterator candidate = level.lower_bound(name);
+        if (candidate != level.end()) {
+            const TString& candidateName = (*candidate).first;
+            TString::size_type parenAt = candidateName.find_first_of('(');
+            if (parenAt == candidateName.npos) {
+                // not a mangled name
+                if (candidateName == name) {
+                    // found a variable name match
+                    variable = true;
+                    return true;
+                }
+            } else {
+                // a mangled name
+                if (candidateName.compare(0, parenAt, name) == 0) {
+                    // found a function name match
+                    variable = false;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    // Use this to do a lazy 'push' of precision defaults the first time
+    // a precision statement is seen in a new scope.  Leave it at 0 for
+    // when no push was needed.  Thus, it is not the current defaults,
+    // it is what to restore the defaults to when popping a level.
+    void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
+    {
+        // can call multiple times at one scope, will only latch on first call,
+        // as we're tracking the previous scope's values, not the current values
+        if (defaultPrecision != 0)
+            return;
+
+        defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
+        for (int t = 0; t < EbtNumTypes; ++t)
+            defaultPrecision[t] = p[t];
+    }
+
+    void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
+    {
+        // can be called for table level pops that didn't set the
+        // defaults
+        if (defaultPrecision == 0 || p == 0)
+            return;
+
+        for (int t = 0; t < EbtNumTypes; ++t)
+            p[t] = defaultPrecision[t];
+    }
+
+    void relateToOperator(const char* name, TOperator op);
+    void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
+    void dump(TInfoSink &infoSink) const;
+    TSymbolTableLevel* clone() const;
+    void readOnly();
+
+protected:
+    explicit TSymbolTableLevel(TSymbolTableLevel&);
+    TSymbolTableLevel& operator=(TSymbolTableLevel&);
+
+    typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
+    typedef const tLevel::value_type tLevelPair;
+    typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+    tLevel level;  // named mappings
+    TPrecisionQualifier *defaultPrecision;
+    int anonId;
+};
+
+class TSymbolTable {
+public:
+    TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), separateNameSpaces(false), adoptedLevels(0)
+    {
+        //
+        // This symbol table cannot be used until push() is called.
+        //
+    }
+    ~TSymbolTable()
+    {
+        // this can be called explicitly; safest to code it so it can be called multiple times
+
+        // don't deallocate levels passed in from elsewhere
+        while (table.size() > adoptedLevels)
+            pop(0);
+    }
+
+    void adoptLevels(TSymbolTable& symTable)
+    {
+        for (unsigned int level = 0; level < symTable.table.size(); ++level) {
+            table.push_back(symTable.table[level]);
+            ++adoptedLevels;
+        }
+        uniqueId = symTable.uniqueId;
+        noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
+        separateNameSpaces = symTable.separateNameSpaces;
+    }
+
+    //
+    // While level adopting is generic, the methods below enact a the following
+    // convention for levels:
+    //   0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
+    //   1: per-stage built-ins, shared across all compiles, but a different copy per stage
+    //   2: built-ins specific to a compile, like resources that are context-dependent, or redeclared built-ins
+    //   3: user-shader globals
+    //
+protected:
+    static const int globalLevel = 3;
+    bool isSharedLevel(int level)  { return level <= 1; }              // exclude all per-compile levels
+    bool isBuiltInLevel(int level) { return level <= 2; }              // exclude user globals
+    bool isGlobalLevel(int level)  { return level <= globalLevel; }    // include user globals
+public:
+    bool isEmpty() { return table.size() == 0; }
+    bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
+    bool atGlobalLevel()  { return isGlobalLevel(currentLevel()); }
+
+    void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
+    void setSeparateNameSpaces() { separateNameSpaces = true; }
+
+    void push()
+    {
+        table.push_back(new TSymbolTableLevel);
+    }
+
+    void pop(TPrecisionQualifier *p)
+    {
+        table[currentLevel()]->getPreviousDefaultPrecisions(p);
+        delete table.back();
+        table.pop_back();
+    }
+
+    //
+    // Insert a visible symbol into the symbol table so it can
+    // be found later by name.
+    //
+    // Returns false if the was a name collision.
+    //
+    bool insert(TSymbol& symbol)
+    {
+        symbol.setUniqueId(++uniqueId);
+
+        // make sure there isn't a function of this variable name
+        if (! separateNameSpaces && ! symbol.getAsFunction() && table[currentLevel()]->hasFunctionName(symbol.getName()))
+            return false;
+
+        // check for not overloading or redefining a built-in function
+        if (noBuiltInRedeclarations) {
+            if (atGlobalLevel() && currentLevel() > 0) {
+                if (table[0]->hasFunctionName(symbol.getName()))
+                    return false;
+                if (currentLevel() > 1 && table[1]->hasFunctionName(symbol.getName()))
+                    return false;
+            }
+        }
+
+        return table[currentLevel()]->insert(symbol, separateNameSpaces);
+    }
+
+    // Add more members to an already inserted aggregate object
+    bool amend(TSymbol& symbol, int firstNewMember)
+    {
+        // See insert() for comments on basic explanation of insert.
+        // This operates similarly, but more simply.
+        return table[currentLevel()]->amend(symbol, firstNewMember);
+    }
+
+    //
+    // To allocate an internal temporary, which will need to be uniquely
+    // identified by the consumer of the AST, but never need to
+    // found by doing a symbol table search by name, hence allowed an
+    // arbitrary name in the symbol with no worry of collision.
+    //
+    void makeInternalVariable(TSymbol& symbol)
+    {
+        symbol.setUniqueId(++uniqueId);
+    }
+
+    //
+    // Copy a variable or anonymous member's structure from a shared level so that
+    // it can be added (soon after return) to the symbol table where it can be
+    // modified without impacting other users of the shared table.
+    //
+    TSymbol* copyUpDeferredInsert(TSymbol* shared)
+    {
+        if (shared->getAsVariable()) {
+            TSymbol* copy = shared->clone();
+            copy->setUniqueId(shared->getUniqueId());
+            return copy;
+        } else {
+            const TAnonMember* anon = shared->getAsAnonMember();
+            assert(anon);
+            TVariable* container = anon->getAnonContainer().clone();
+            container->changeName(NewPoolTString(""));
+            container->setUniqueId(anon->getAnonContainer().getUniqueId());
+            return container;
+        }
+    }
+
+    TSymbol* copyUp(TSymbol* shared)
+    {
+        TSymbol* copy = copyUpDeferredInsert(shared);
+        table[globalLevel]->insert(*copy, separateNameSpaces);
+        if (shared->getAsVariable())
+            return copy;
+        else {
+            // return the copy of the anonymous member
+            return table[globalLevel]->find(shared->getName());
+        }
+    }
+
+    TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)
+    {
+        int level = currentLevel();
+        TSymbol* symbol;
+        do {
+            symbol = table[level]->find(name);
+            --level;
+        } while (symbol == 0 && level >= 0);
+        level++;
+        if (builtIn)
+            *builtIn = isBuiltInLevel(level);
+        if (currentScope)
+            *currentScope = isGlobalLevel(currentLevel()) || level == currentLevel();  // consider shared levels as "current scope" WRT user globals
+
+        return symbol;
+    }
+
+    bool isFunctionNameVariable(const TString& name) const
+    {
+        if (separateNameSpaces)
+            return false;
+
+        int level = currentLevel();
+        do {
+            bool variable;
+            bool found = table[level]->findFunctionVariableName(name, variable);
+            if (found)
+                return variable;
+            --level;
+        } while (level >= 0);
+
+        return false;
+    }
+
+    void findFunctionNameList(const TString& name, TVector<const TFunction*>& list, bool& builtIn)
+    {
+        // For user levels, return the set found in the first scope with a match
+        builtIn = false;
+        int level = currentLevel();
+        do {
+            table[level]->findFunctionNameList(name, list);
+            --level;
+        } while (list.empty() && level >= globalLevel);
+
+        if (! list.empty())
+            return;
+
+        // Gather across all built-in levels; they don't hide each other
+        builtIn = true;
+        do {
+            table[level]->findFunctionNameList(name, list);
+            --level;
+        } while (level >= 0);
+    }
+
+    void relateToOperator(const char* name, TOperator op)
+    {
+        for (unsigned int level = 0; level < table.size(); ++level)
+            table[level]->relateToOperator(name, op);
+    }
+
+    void setFunctionExtensions(const char* name, int num, const char* const extensions[])
+    {
+        for (unsigned int level = 0; level < table.size(); ++level)
+            table[level]->setFunctionExtensions(name, num, extensions);
+    }
+
+    void setVariableExtensions(const char* name, int num, const char* const extensions[])
+    {
+        TSymbol* symbol = find(TString(name));
+        if (symbol)
+            symbol->setExtensions(num, extensions);
+    }
+
+    int getMaxSymbolId() { return uniqueId; }
+    void dump(TInfoSink &infoSink) const;
+    void copyTable(const TSymbolTable& copyOf);
+
+    void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
+
+    void readOnly()
+    {
+        for (unsigned int level = 0; level < table.size(); ++level)
+            table[level]->readOnly();
+    }
+
+protected:
+    TSymbolTable(TSymbolTable&);
+    TSymbolTable& operator=(TSymbolTableLevel&);
+
+    int currentLevel() const { return static_cast<int>(table.size()) - 1; }
+
+    std::vector<TSymbolTableLevel*> table;
+    int uniqueId;     // for unique identification in code generation
+    bool noBuiltInRedeclarations;
+    bool separateNameSpaces;
+    unsigned int adoptedLevels;
+};
+
+} // end namespace glslang
+
+#endif // _SYMBOL_TABLE_INCLUDED_

+ 734 - 0
src/libraries/glslang/glslang/MachineIndependent/Versions.cpp

@@ -0,0 +1,734 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Help manage multiple profiles, versions, extensions etc.
+//
+// These don't return error codes, as the presumption is parsing will
+// always continue as if the tested feature were enabled, and thus there
+// is no error recovery needed.
+//
+
+//
+// HOW TO add a feature enabled by an extension.
+//
+// To add a new hypothetical "Feature F" to the front end, where an extension
+// "XXX_extension_X" can be used to enable the feature, do the following.
+//
+// OVERVIEW: Specific features are what are error-checked for, not
+//    extensions:  A specific Feature F might be enabled by an extension, or a
+//    particular version in a particular profile, or a stage, or combinations, etc.
+//
+//    The basic mechanism is to use the following to "declare" all the things that
+//    enable/disable Feature F, in a code path that implements Feature F:
+//
+//        requireProfile()
+//        profileRequires()
+//        requireStage()
+//        checkDeprecated()
+//        requireNotRemoved()
+//        requireExtensions()
+//
+//    Typically, only the first two calls are needed.  They go into a code path that
+//    implements Feature F, and will log the proper error/warning messages.  Parsing
+//    will then always continue as if the tested feature was enabled.
+//
+//    There is typically no if-testing or conditional parsing, just insertion of the calls above.
+//    However, if symbols specific to the extension are added (step 5), they will
+//    only be added under tests that the minimum version and profile are present.
+//
+// 1) Add a symbol name for the extension string at the bottom of Versions.h:
+//
+//     const char* const XXX_extension_X = "XXX_extension_X";
+//
+// 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(),
+//    the first function below:
+//
+//     extensionBehavior[XXX_extension_X] = EBhDisable;
+//
+// 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble():
+//
+//           "#define XXX_extension_X 1\n"
+//
+//    The new-line is important, as that ends preprocess tokens.
+//
+// 4) Insert a profile check in the feature's path (unless all profiles support the feature,
+//    for some version level).  That is, call requireProfile() to constrain the profiles, e.g.:
+//
+//         // ... in a path specific to Feature F...
+//         requireProfile(loc,
+//                        ECoreProfile | ECompatibilityProfile,
+//                        "Feature F");
+//
+// 5) For each profile that supports the feature, insert version/extension checks:
+//
+//    The mostly likely scenario is that Feature F can only be used with a
+//    particular profile if XXX_extension_X is present or the version is
+//    high enough that the core specification already incorporated it.
+//
+//        // following the requireProfile() call...
+//        profileRequires(loc,
+//                        ECoreProfile | ECompatibilityProfile,
+//                        420,             // 0 if no version incorporated the feature into the core spec.
+//                        XXX_extension_X, // can be a list of extensions that all add the feature
+//                        "Feature F Description");
+//
+//    This allows the feature if either A) one of the extensions is enabled or
+//    B) the version is high enough.  If no version yet incorporates the feature
+//    into core, pass in 0.
+//
+//    This can be called multiple times, if different profiles support the
+//    feature starting at different version numbers or with different
+//    extensions.
+//
+//    This must be called for each profile allowed by the initial call to requireProfile().
+//
+//    Profiles are all masks, which can be "or"-ed together.
+//
+//        ENoProfile
+//        ECoreProfile
+//        ECompatibilityProfile
+//        EEsProfile
+//
+//    The ENoProfile profile is only for desktop, before profiles showed up in version 150;
+//    All other #version with no profile default to either es or core, and so have profiles.
+//
+//    You can select all but a particular profile using ~.  The following basically means "desktop":
+//
+//        ~EEsProfile
+//
+// 6) If built-in symbols are added by the extension, add them in Initialize.cpp:  Their use
+//    will be automatically error checked against the extensions enabled at that moment.
+//    see the comment at the top of Initialize.cpp for where to put them.  Establish them at
+//    the earliest release that supports the extension.  Then, tag them with the
+//    set of extensions that both enable them and are necessary, given the version of the symbol
+//    table. (There is a different symbol table for each version.)
+//
+
+#include "parseVersions.h"
+#include "localintermediate.h"
+
+namespace glslang {
+
+//
+// Initialize all extensions, almost always to 'disable', as once their features
+// are incorporated into a core version, their features are supported through allowing that
+// core version, not through a pseudo-enablement of the extension.
+//
+void TParseVersions::initializeExtensionBehavior()
+{
+    extensionBehavior[E_GL_OES_texture_3D]                   = EBhDisable;
+    extensionBehavior[E_GL_OES_standard_derivatives]         = EBhDisable;
+    extensionBehavior[E_GL_EXT_frag_depth]                   = EBhDisable;
+    extensionBehavior[E_GL_OES_EGL_image_external]           = EBhDisable;
+    extensionBehavior[E_GL_EXT_shader_texture_lod]           = EBhDisable;
+
+    extensionBehavior[E_GL_ARB_texture_rectangle]            = EBhDisable;
+    extensionBehavior[E_GL_3DL_array_objects]                = EBhDisable;
+    extensionBehavior[E_GL_ARB_shading_language_420pack]     = EBhDisable;
+    extensionBehavior[E_GL_ARB_texture_gather]               = EBhDisable;
+    extensionBehavior[E_GL_ARB_gpu_shader5]                  = EBhDisablePartial;
+    extensionBehavior[E_GL_ARB_separate_shader_objects]      = EBhDisable;
+    extensionBehavior[E_GL_ARB_compute_shader]               = EBhDisable;
+    extensionBehavior[E_GL_ARB_tessellation_shader]          = EBhDisable;
+    extensionBehavior[E_GL_ARB_enhanced_layouts]             = EBhDisable;
+    extensionBehavior[E_GL_ARB_texture_cube_map_array]       = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_texture_lod]           = EBhDisable;
+    extensionBehavior[E_GL_ARB_explicit_attrib_location]     = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_image_load_store]      = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_atomic_counters]       = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_draw_parameters]       = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_group_vote]            = EBhDisable;
+    extensionBehavior[E_GL_ARB_derivative_control]           = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_texture_image_samples] = EBhDisable;
+    extensionBehavior[E_GL_ARB_viewport_array]               = EBhDisable;
+    extensionBehavior[E_GL_ARB_gpu_shader_int64]             = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_ballot]                = EBhDisable;
+    extensionBehavior[E_GL_ARB_sparse_texture2]              = EBhDisable;
+    extensionBehavior[E_GL_ARB_sparse_texture_clamp]         = EBhDisable;
+//    extensionBehavior[E_GL_ARB_cull_distance]                = EBhDisable;    // present for 4.5, but need extension control over block members
+
+    extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
+
+    // #line and #include
+    extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive]          = EBhDisable;
+    extensionBehavior[E_GL_GOOGLE_include_directive]                 = EBhDisable;
+
+#ifdef AMD_EXTENSIONS
+    extensionBehavior[E_GL_AMD_shader_ballot]                        = EBhDisable;
+    extensionBehavior[E_GL_AMD_shader_trinary_minmax]                = EBhDisable;
+    extensionBehavior[E_GL_AMD_shader_explicit_vertex_parameter]     = EBhDisable;
+    extensionBehavior[E_GL_AMD_gcn_shader]                           = EBhDisable;
+    extensionBehavior[E_GL_AMD_gpu_shader_half_float]                = EBhDisable;
+#endif
+
+#ifdef NV_EXTENSIONS
+    extensionBehavior[E_GL_NV_sample_mask_override_coverage]         = EBhDisable;
+    extensionBehavior[E_SPV_NV_geometry_shader_passthrough]          = EBhDisable;
+    extensionBehavior[E_GL_ARB_shader_viewport_layer_array]          = EBhDisable;
+    extensionBehavior[E_GL_NV_viewport_array2]                       = EBhDisable;
+    extensionBehavior[E_GL_NV_stereo_view_rendering]                 = EBhDisable;
+#endif
+
+    // AEP
+    extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
+    extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
+    extensionBehavior[E_GL_OES_sample_variables]                     = EBhDisable;
+    extensionBehavior[E_GL_OES_shader_image_atomic]                  = EBhDisable;
+    extensionBehavior[E_GL_OES_shader_multisample_interpolation]     = EBhDisable;
+    extensionBehavior[E_GL_OES_texture_storage_multisample_2d_array] = EBhDisable;
+    extensionBehavior[E_GL_EXT_geometry_shader]                      = EBhDisable;
+    extensionBehavior[E_GL_EXT_geometry_point_size]                  = EBhDisable;
+    extensionBehavior[E_GL_EXT_gpu_shader5]                          = EBhDisable;
+    extensionBehavior[E_GL_EXT_primitive_bounding_box]               = EBhDisable;
+    extensionBehavior[E_GL_EXT_shader_io_blocks]                     = EBhDisable;
+    extensionBehavior[E_GL_EXT_tessellation_shader]                  = EBhDisable;
+    extensionBehavior[E_GL_EXT_tessellation_point_size]              = EBhDisable;
+    extensionBehavior[E_GL_EXT_texture_buffer]                       = EBhDisable;
+    extensionBehavior[E_GL_EXT_texture_cube_map_array]               = EBhDisable;
+
+    // OES matching AEP
+    extensionBehavior[E_GL_OES_geometry_shader]          = EBhDisable;
+    extensionBehavior[E_GL_OES_geometry_point_size]      = EBhDisable;
+    extensionBehavior[E_GL_OES_gpu_shader5]              = EBhDisable;
+    extensionBehavior[E_GL_OES_primitive_bounding_box]   = EBhDisable;
+    extensionBehavior[E_GL_OES_shader_io_blocks]         = EBhDisable;
+    extensionBehavior[E_GL_OES_tessellation_shader]      = EBhDisable;
+    extensionBehavior[E_GL_OES_tessellation_point_size]  = EBhDisable;
+    extensionBehavior[E_GL_OES_texture_buffer]           = EBhDisable;
+    extensionBehavior[E_GL_OES_texture_cube_map_array]   = EBhDisable;
+}
+
+// Get code that is not part of a shared symbol table, is specific to this shader,
+// or needed by the preprocessor (which does not use a shared symbol table).
+void TParseVersions::getPreamble(std::string& preamble)
+{
+    if (profile == EEsProfile) {
+        preamble =
+            "#define GL_ES 1\n"
+            "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
+            "#define GL_OES_texture_3D 1\n"
+            "#define GL_OES_standard_derivatives 1\n"
+            "#define GL_EXT_frag_depth 1\n"
+            "#define GL_OES_EGL_image_external 1\n"
+            "#define GL_EXT_shader_texture_lod 1\n"
+
+            // AEP
+            "#define GL_ANDROID_extension_pack_es31a 1\n"
+            "#define GL_KHR_blend_equation_advanced 1\n"
+            "#define GL_OES_sample_variables 1\n"
+            "#define GL_OES_shader_image_atomic 1\n"
+            "#define GL_OES_shader_multisample_interpolation 1\n"
+            "#define GL_OES_texture_storage_multisample_2d_array 1\n"
+            "#define GL_EXT_geometry_shader 1\n"
+            "#define GL_EXT_geometry_point_size 1\n"
+            "#define GL_EXT_gpu_shader5 1\n"
+            "#define GL_EXT_primitive_bounding_box 1\n"
+            "#define GL_EXT_shader_io_blocks 1\n"
+            "#define GL_EXT_tessellation_shader 1\n"
+            "#define GL_EXT_tessellation_point_size 1\n"
+            "#define GL_EXT_texture_buffer 1\n"
+            "#define GL_EXT_texture_cube_map_array 1\n"
+
+            // OES matching AEP
+            "#define GL_OES_geometry_shader 1\n"
+            "#define GL_OES_geometry_point_size 1\n"
+            "#define GL_OES_gpu_shader5 1\n"
+            "#define GL_OES_primitive_bounding_box 1\n"
+            "#define GL_OES_shader_io_blocks 1\n"
+            "#define GL_OES_tessellation_shader 1\n"
+            "#define GL_OES_tessellation_point_size 1\n"
+            "#define GL_OES_texture_buffer 1\n"
+            "#define GL_OES_texture_cube_map_array 1\n"
+            "#define GL_EXT_shader_non_constant_global_initializers 1\n"
+            ;
+    } else {
+        preamble =
+            "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
+            "#define GL_ARB_texture_rectangle 1\n"
+            "#define GL_ARB_shading_language_420pack 1\n"
+            "#define GL_ARB_texture_gather 1\n"
+            "#define GL_ARB_gpu_shader5 1\n"
+            "#define GL_ARB_separate_shader_objects 1\n"
+            "#define GL_ARB_compute_shader 1\n"
+            "#define GL_ARB_tessellation_shader 1\n"
+            "#define GL_ARB_enhanced_layouts 1\n"
+            "#define GL_ARB_texture_cube_map_array 1\n"
+            "#define GL_ARB_shader_texture_lod 1\n"
+            "#define GL_ARB_explicit_attrib_location 1\n"
+            "#define GL_ARB_shader_image_load_store 1\n"
+            "#define GL_ARB_shader_atomic_counters 1\n"
+            "#define GL_ARB_shader_draw_parameters 1\n"
+            "#define GL_ARB_shader_group_vote 1\n"
+            "#define GL_ARB_derivative_control 1\n"
+            "#define GL_ARB_shader_texture_image_samples 1\n"
+            "#define GL_ARB_viewport_array 1\n"
+            "#define GL_ARB_gpu_shader_int64 1\n"
+            "#define GL_ARB_shader_ballot 1\n"
+            "#define GL_ARB_sparse_texture2 1\n"
+            "#define GL_ARB_sparse_texture_clamp 1\n"
+//            "#define GL_ARB_cull_distance 1\n"    // present for 4.5, but need extension control over block members
+            "#define GL_EXT_shader_non_constant_global_initializers 1\n"
+
+#ifdef AMD_EXTENSIONS
+            "#define GL_AMD_shader_ballot 1\n"
+            "#define GL_AMD_shader_trinary_minmax 1\n"
+            "#define GL_AMD_shader_explicit_vertex_parameter 1\n"
+            "#define GL_AMD_gcn_shader 1\n"
+            "#define GL_AMD_gpu_shader_half_float 1\n"
+#endif
+
+#ifdef NV_EXTENSIONS
+            "#define GL_NV_sample_mask_override_coverage 1\n"
+            "#define GL_NV_geometry_shader_passthrough 1\n"
+            "#define GL_NV_viewport_array2 1\n"
+#endif
+            ;
+    }
+
+    // #line and #include
+    preamble +=
+            "#define GL_GOOGLE_cpp_style_line_directive 1\n"
+            "#define GL_GOOGLE_include_directive 1\n"
+            ;
+
+    // #define VULKAN XXXX
+    const int numberBufSize = 12;
+    char numberBuf[numberBufSize];
+    if (spvVersion.vulkan > 0) {
+        preamble += "#define VULKAN ";
+        snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan);
+        preamble += numberBuf;
+        preamble += "\n";
+    }
+    // #define GL_SPIRV XXXX
+    if (spvVersion.openGl > 0) {
+        preamble += "#define GL_SPIRV ";
+        snprintf(numberBuf, numberBufSize, "%d", spvVersion.openGl);
+        preamble += numberBuf;
+        preamble += "\n";
+    }
+
+}
+
+//
+// When to use requireProfile():
+//
+//     Use if only some profiles support a feature.  However, if within a profile the feature
+//     is version or extension specific, follow this call with calls to profileRequires().
+//
+// Operation:  If the current profile is not one of the profileMask,
+// give an error message.
+//
+void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc)
+{
+    if (! (profile & profileMask))
+        error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
+}
+
+//
+// Map from stage enum to externally readable text name.
+//
+const char* StageName(EShLanguage stage)
+{
+    switch(stage) {
+    case EShLangVertex:         return "vertex";
+    case EShLangTessControl:    return "tessellation control";
+    case EShLangTessEvaluation: return "tessellation evaluation";
+    case EShLangGeometry:       return "geometry";
+    case EShLangFragment:       return "fragment";
+    case EShLangCompute:        return "compute";
+    default:                    return "unknown stage";
+    }
+}
+
+//
+// When to use profileRequires():
+//
+//     If a set of profiles have the same requirements for what version or extensions
+//     are needed to support a feature.
+//
+//     It must be called for each profile that needs protection.  Use requireProfile() first
+//     to reduce that set of profiles.
+//
+// Operation: Will issue warnings/errors based on the current profile, version, and extension
+// behaviors.  It only checks extensions when the current profile is one of the profileMask.
+//
+// A minVersion of 0 means no version of the profileMask support this in core,
+// the extension must be present.
+//
+
+// entry point that takes multiple extensions
+void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc)
+{
+    if (profile & profileMask) {
+        bool okay = false;
+        if (minVersion > 0 && version >= minVersion)
+            okay = true;
+        for (int i = 0; i < numExtensions; ++i) {
+            switch (getExtensionBehavior(extensions[i])) {
+            case EBhWarn:
+                infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
+                // fall through
+            case EBhRequire:
+            case EBhEnable:
+                okay = true;
+                break;
+            default: break; // some compilers want this
+            }
+        }
+
+        if (! okay)
+            error(loc, "not supported for this version or the enabled extensions", featureDesc, "");
+    }
+}
+
+// entry point for the above that takes a single extension
+void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc)
+{
+    profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc);
+}
+
+//
+// When to use requireStage()
+//
+//     If only some stages support a feature.
+//
+// Operation: If the current stage is not present, give an error message.
+//
+void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc)
+{
+    if (((1 << language) & languageMask) == 0)
+        error(loc, "not supported in this stage:", featureDesc, StageName(language));
+}
+
+// If only one stage supports a feature, this can be called.  But, all supporting stages
+// must be specified with one call.
+void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc)
+{
+    requireStage(loc, static_cast<EShLanguageMask>(1 << stage), featureDesc);
+}
+
+//
+// Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether
+// a future compatibility context is being use.
+//
+void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc)
+{
+    if (profile & profileMask) {
+        if (version >= depVersion) {
+            if (forwardCompatible)
+                error(loc, "deprecated, may be removed in future release", featureDesc, "");
+            else if (! suppressWarnings())
+                infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " +
+                                                       String(depVersion) + "; may be removed in future release").c_str(), loc);
+        }
+    }
+}
+
+//
+// Within a set of profiles, see if a feature has now been removed and if so, give an error.
+// The version argument is the first version no longer having the feature.
+//
+void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc)
+{
+    if (profile & profileMask) {
+        if (version >= removedVersion) {
+            const int maxSize = 60;
+            char buf[maxSize];
+            snprintf(buf, maxSize, "%s profile; removed in version %d", ProfileName(profile), removedVersion);
+            error(loc, "no longer supported in", featureDesc, buf);
+        }
+    }
+}
+
+// Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false.
+// Warns appropriately if the requested behavior of an extension is "warn".
+bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+{
+    // First, see if any of the extensions are enabled
+    for (int i = 0; i < numExtensions; ++i) {
+        TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
+        if (behavior == EBhEnable || behavior == EBhRequire)
+            return true;
+    }
+
+    // See if any extensions want to give a warning on use; give warnings for all such extensions
+    bool warned = false;
+    for (int i = 0; i < numExtensions; ++i) {
+        TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
+        if (behavior == EBhDisable && relaxedErrors()) {
+            infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
+            behavior = EBhWarn;
+        }
+        if (behavior == EBhWarn) {
+            infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
+            warned = true;
+        }
+    }
+    if (warned)
+        return true;
+    return false;
+}
+
+//
+// Use when there are no profile/version to check, it's just an error if one of the
+// extensions is not present.
+//
+void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+{
+    if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
+
+    // If we get this far, give errors explaining what extensions are needed
+    if (numExtensions == 1)
+        error(loc, "required extension not requested:", featureDesc, extensions[0]);
+    else {
+        error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
+        for (int i = 0; i < numExtensions; ++i)
+            infoSink.info.message(EPrefixNone, extensions[i]);
+    }
+}
+
+//
+// Use by preprocessor when there are no profile/version to check, it's just an error if one of the
+// extensions is not present.
+//
+void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+{
+    if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
+
+    // If we get this far, give errors explaining what extensions are needed
+    if (numExtensions == 1)
+        ppError(loc, "required extension not requested:", featureDesc, extensions[0]);
+    else {
+        ppError(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
+        for (int i = 0; i < numExtensions; ++i)
+            infoSink.info.message(EPrefixNone, extensions[i]);
+    }
+}
+
+TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension)
+{
+    auto iter = extensionBehavior.find(TString(extension));
+    if (iter == extensionBehavior.end())
+        return EBhMissing;
+    else
+        return iter->second;
+}
+
+// Returns true if the given extension is set to enable, require, or warn.
+bool TParseVersions::extensionTurnedOn(const char* const extension)
+{
+      switch (getExtensionBehavior(extension)) {
+      case EBhEnable:
+      case EBhRequire:
+      case EBhWarn:
+          return true;
+      default:
+          break;
+      }
+      return false;
+}
+// See if any of the extensions are set to enable, require, or warn.
+bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[])
+{
+    for (int i = 0; i < numExtensions; ++i) {
+        if (extensionTurnedOn(extensions[i])) return true;
+    }
+    return false;
+}
+
+//
+// Change the current state of an extension's behavior.
+//
+void TParseVersions::updateExtensionBehavior(int line, const char* extension, const char* behaviorString)
+{
+    // Translate from text string of extension's behavior to an enum.
+    TExtensionBehavior behavior = EBhDisable;
+    if (! strcmp("require", behaviorString))
+        behavior = EBhRequire;
+    else if (! strcmp("enable", behaviorString))
+        behavior = EBhEnable;
+    else if (! strcmp("disable", behaviorString))
+        behavior = EBhDisable;
+    else if (! strcmp("warn", behaviorString))
+        behavior = EBhWarn;
+    else {
+        error(getCurrentLoc(), "behavior not supported:", "#extension", behaviorString);
+        return;
+    }
+
+    // update the requested extension
+    updateExtensionBehavior(extension, behavior);
+
+    // see if need to propagate to implicitly modified things
+    if (strcmp(extension, "GL_ANDROID_extension_pack_es31a") == 0) {
+        // to everything in AEP
+        updateExtensionBehavior(line, "GL_KHR_blend_equation_advanced", behaviorString);
+        updateExtensionBehavior(line, "GL_OES_sample_variables", behaviorString);
+        updateExtensionBehavior(line, "GL_OES_shader_image_atomic", behaviorString);
+        updateExtensionBehavior(line, "GL_OES_shader_multisample_interpolation", behaviorString);
+        updateExtensionBehavior(line, "GL_OES_texture_storage_multisample_2d_array", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_geometry_shader", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_gpu_shader5", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_primitive_bounding_box", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_tessellation_shader", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_texture_buffer", behaviorString);
+        updateExtensionBehavior(line, "GL_EXT_texture_cube_map_array", behaviorString);
+    }
+    // geometry to io_blocks
+    else if (strcmp(extension, "GL_EXT_geometry_shader") == 0)
+        updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
+    else if (strcmp(extension, "GL_OES_geometry_shader") == 0)
+        updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
+    // tessellation to io_blocks
+    else if (strcmp(extension, "GL_EXT_tessellation_shader") == 0)
+        updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
+    else if (strcmp(extension, "GL_OES_tessellation_shader") == 0)
+        updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
+    else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
+        updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
+}
+
+void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
+{
+    // Update the current behavior
+    if (strcmp(extension, "all") == 0) {
+        // special case for the 'all' extension; apply it to every extension present
+        if (behavior == EBhRequire || behavior == EBhEnable) {
+            error(getCurrentLoc(), "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
+            return;
+        } else {
+            for (auto iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
+                iter->second = behavior;
+        }
+    } else {
+        // Do the update for this single extension
+        auto iter = extensionBehavior.find(TString(extension));
+        if (iter == extensionBehavior.end()) {
+            switch (behavior) {
+            case EBhRequire:
+                error(getCurrentLoc(), "extension not supported:", "#extension", extension);
+                break;
+            case EBhEnable:
+            case EBhWarn:
+            case EBhDisable:
+                warn(getCurrentLoc(), "extension not supported:", "#extension", extension);
+                break;
+            default:
+                assert(0 && "unexpected behavior");
+            }
+
+            return;
+        } else {
+            if (iter->second == EBhDisablePartial)
+                warn(getCurrentLoc(), "extension is only partially supported:", "#extension", extension);
+            if (behavior == EBhEnable || behavior == EBhRequire)
+                intermediate.addRequestedExtension(extension);
+            iter->second = behavior;
+        }
+    }
+}
+
+// Call for any operation needing full GLSL integer data-type support.
+void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op)
+{
+    profileRequires(loc, ENoProfile, 130, nullptr, op);
+    profileRequires(loc, EEsProfile, 300, nullptr, op);
+}
+
+// Call for any operation needing GLSL double data-type support.
+void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op)
+{
+    requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
+    profileRequires(loc, ECoreProfile, 400, nullptr, op);
+    profileRequires(loc, ECompatibilityProfile, 400, nullptr, op);
+}
+
+#ifdef AMD_EXTENSIONS
+// Call for any operation needing GLSL float16 data-type support.
+void TParseVersions::float16Check(const TSourceLoc& loc, const char* op, bool builtIn)
+{
+    if (!builtIn) {
+        requireExtensions(loc, 1, &E_GL_AMD_gpu_shader_half_float, "shader half float");
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
+        profileRequires(loc, ECoreProfile, 450, nullptr, op);
+        profileRequires(loc, ECompatibilityProfile, 450, nullptr, op);
+    }
+}
+#endif
+
+// Call for any operation needing GLSL 64-bit integer data-type support.
+void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn)
+{
+    if (! builtIn) {
+        requireExtensions(loc, 1, &E_GL_ARB_gpu_shader_int64, "shader int64");
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
+        profileRequires(loc, ECoreProfile, 450, nullptr, op);
+        profileRequires(loc, ECompatibilityProfile, 450, nullptr, op);
+    }
+}
+
+// Call for any operation removed because SPIR-V is in use.
+void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
+{
+    if (spvVersion.spv != 0)
+        error(loc, "not allowed when generating SPIR-V", op, "");
+}
+
+// Call for any operation removed because Vulkan SPIR-V is being generated.
+void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op)
+{
+    if (spvVersion.vulkan >= 100)
+        error(loc, "not allowed when using GLSL for Vulkan", op, "");
+}
+
+// Call for any operation that requires Vulkan.
+void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op)
+{
+    if (spvVersion.vulkan == 0)
+        error(loc, "only allowed when using GLSL for Vulkan", op, "");
+}
+
+// Call for any operation that requires SPIR-V.
+void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op)
+{
+    if (spvVersion.spv == 0)
+        error(loc, "only allowed when generating SPIR-V", op, "");
+}
+
+} // end namespace glslang

+ 218 - 0
src/libraries/glslang/glslang/MachineIndependent/Versions.h

@@ -0,0 +1,218 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef _VERSIONS_INCLUDED_
+#define _VERSIONS_INCLUDED_
+
+//
+// Help manage multiple profiles, versions, extensions etc.
+//
+
+//
+// Profiles are set up for masking operations, so queries can be done on multiple
+// profiles at the same time.
+//
+// Don't maintain an ordinal set of enums (0,1,2,3...) to avoid all possible
+// defects from mixing the two different forms.
+//
+typedef enum {
+    EBadProfile           = 0,
+    ENoProfile            = (1 << 0), // only for desktop, before profiles showed up
+    ECoreProfile          = (1 << 1),
+    ECompatibilityProfile = (1 << 2),
+    EEsProfile            = (1 << 3)
+} EProfile;
+
+namespace glslang {
+
+//
+// Map from profile enum to externally readable text name.
+//
+inline const char* ProfileName(EProfile profile)
+{
+    switch (profile) {
+    case ENoProfile:             return "none";
+    case ECoreProfile:           return "core";
+    case ECompatibilityProfile:  return "compatibility";
+    case EEsProfile:             return "es";
+    default:                     return "unknown profile";
+    }
+}
+
+//
+// SPIR-V has versions for multiple things; tie them together.
+// 0 means a target or rule set is not enabled.
+//
+struct SpvVersion {
+    SpvVersion() : spv(0), vulkan(0), openGl(0) {}
+    unsigned int spv; // the version of the targeted SPIR-V, as defined by SPIR-V in word 1 of the SPIR-V binary header
+    int vulkan;       // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN"
+    int openGl;       // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV"
+};
+
+//
+// The behaviors from the GLSL "#extension extension_name : behavior"
+//
+typedef enum {
+    EBhMissing = 0,
+    EBhRequire,
+    EBhEnable,
+    EBhWarn,
+    EBhDisable,
+    EBhDisablePartial    // use as initial state of an extension that is only partially implemented
+} TExtensionBehavior;
+
+//
+// Symbolic names for extensions.  Strings may be directly used when calling the
+// functions, but better to have the compiler do spelling checks.
+//
+const char* const E_GL_OES_texture_3D                   = "GL_OES_texture_3D";
+const char* const E_GL_OES_standard_derivatives         = "GL_OES_standard_derivatives";
+const char* const E_GL_EXT_frag_depth                   = "GL_EXT_frag_depth";
+const char* const E_GL_OES_EGL_image_external           = "GL_OES_EGL_image_external";
+const char* const E_GL_EXT_shader_texture_lod           = "GL_EXT_shader_texture_lod";
+
+const char* const E_GL_ARB_texture_rectangle            = "GL_ARB_texture_rectangle";
+const char* const E_GL_3DL_array_objects                = "GL_3DL_array_objects";
+const char* const E_GL_ARB_shading_language_420pack     = "GL_ARB_shading_language_420pack";
+const char* const E_GL_ARB_texture_gather               = "GL_ARB_texture_gather";
+const char* const E_GL_ARB_gpu_shader5                  = "GL_ARB_gpu_shader5";
+const char* const E_GL_ARB_separate_shader_objects      = "GL_ARB_separate_shader_objects";
+const char* const E_GL_ARB_compute_shader               = "GL_ARB_compute_shader";
+const char* const E_GL_ARB_tessellation_shader          = "GL_ARB_tessellation_shader";
+const char* const E_GL_ARB_enhanced_layouts             = "GL_ARB_enhanced_layouts";
+const char* const E_GL_ARB_texture_cube_map_array       = "GL_ARB_texture_cube_map_array";
+const char* const E_GL_ARB_shader_texture_lod           = "GL_ARB_shader_texture_lod";
+const char* const E_GL_ARB_explicit_attrib_location     = "GL_ARB_explicit_attrib_location";
+const char* const E_GL_ARB_shader_image_load_store      = "GL_ARB_shader_image_load_store";
+const char* const E_GL_ARB_shader_atomic_counters       = "GL_ARB_shader_atomic_counters";
+const char* const E_GL_ARB_shader_draw_parameters       = "GL_ARB_shader_draw_parameters";
+const char* const E_GL_ARB_shader_group_vote            = "GL_ARB_shader_group_vote";
+const char* const E_GL_ARB_derivative_control           = "GL_ARB_derivative_control";
+const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture_image_samples";
+const char* const E_GL_ARB_viewport_array               = "GL_ARB_viewport_array";
+const char* const E_GL_ARB_gpu_shader_int64             = "GL_ARB_gpu_shader_int64";
+const char* const E_GL_ARB_shader_ballot                = "GL_ARB_shader_ballot";
+const char* const E_GL_ARB_sparse_texture2              = "GL_ARB_sparse_texture2";
+const char* const E_GL_ARB_sparse_texture_clamp         = "GL_ARB_sparse_texture_clamp";
+// const char* const E_GL_ARB_cull_distance            = "GL_ARB_cull_distance";  // present for 4.5, but need extension control over block members
+
+const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_shader_non_constant_global_initializers";
+
+// #line and #include
+const char* const E_GL_GOOGLE_cpp_style_line_directive          = "GL_GOOGLE_cpp_style_line_directive";
+const char* const E_GL_GOOGLE_include_directive                 = "GL_GOOGLE_include_directive";
+
+#ifdef AMD_EXTENSIONS
+const char* const E_GL_AMD_shader_ballot                        = "GL_AMD_shader_ballot";
+const char* const E_GL_AMD_shader_trinary_minmax                = "GL_AMD_shader_trinary_minmax";
+const char* const E_GL_AMD_shader_explicit_vertex_parameter     = "GL_AMD_shader_explicit_vertex_parameter";
+const char* const E_GL_AMD_gcn_shader                           = "GL_AMD_gcn_shader";
+const char* const E_GL_AMD_gpu_shader_half_float                = "GL_AMD_gpu_shader_half_float";
+#endif
+#ifdef NV_EXTENSIONS
+
+const char* const E_GL_NV_sample_mask_override_coverage         = "GL_NV_sample_mask_override_coverage";
+const char* const E_SPV_NV_geometry_shader_passthrough          = "GL_NV_geometry_shader_passthrough";
+const char* const E_GL_ARB_shader_viewport_layer_array          = "GL_ARB_shader_viewport_layer_array";
+const char* const E_GL_NV_viewport_array2                       = "GL_NV_viewport_array2";
+const char* const E_GL_NV_stereo_view_rendering                 = "GL_NV_stereo_view_rendering";
+
+// Arrays of extensions for the above viewportEXTs duplications
+
+const char* const viewportEXTs[] = { E_GL_ARB_shader_viewport_layer_array, E_GL_NV_viewport_array2 };
+const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]);
+#endif
+
+// AEP
+const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
+const char* const E_GL_KHR_blend_equation_advanced              = "GL_KHR_blend_equation_advanced";
+const char* const E_GL_OES_sample_variables                     = "GL_OES_sample_variables";
+const char* const E_GL_OES_shader_image_atomic                  = "GL_OES_shader_image_atomic";
+const char* const E_GL_OES_shader_multisample_interpolation     = "GL_OES_shader_multisample_interpolation";
+const char* const E_GL_OES_texture_storage_multisample_2d_array = "GL_OES_texture_storage_multisample_2d_array";
+const char* const E_GL_EXT_geometry_shader                      = "GL_EXT_geometry_shader";
+const char* const E_GL_EXT_geometry_point_size                  = "GL_EXT_geometry_point_size";
+const char* const E_GL_EXT_gpu_shader5                          = "GL_EXT_gpu_shader5";
+const char* const E_GL_EXT_primitive_bounding_box               = "GL_EXT_primitive_bounding_box";
+const char* const E_GL_EXT_shader_io_blocks                     = "GL_EXT_shader_io_blocks";
+const char* const E_GL_EXT_tessellation_shader                  = "GL_EXT_tessellation_shader";
+const char* const E_GL_EXT_tessellation_point_size              = "GL_EXT_tessellation_point_size";
+const char* const E_GL_EXT_texture_buffer                       = "GL_EXT_texture_buffer";
+const char* const E_GL_EXT_texture_cube_map_array               = "GL_EXT_texture_cube_map_array";
+
+// OES matching AEP
+const char* const E_GL_OES_geometry_shader                      = "GL_OES_geometry_shader";
+const char* const E_GL_OES_geometry_point_size                  = "GL_OES_geometry_point_size";
+const char* const E_GL_OES_gpu_shader5                          = "GL_OES_gpu_shader5";
+const char* const E_GL_OES_primitive_bounding_box               = "GL_OES_primitive_bounding_box";
+const char* const E_GL_OES_shader_io_blocks                     = "GL_OES_shader_io_blocks";
+const char* const E_GL_OES_tessellation_shader                  = "GL_OES_tessellation_shader";
+const char* const E_GL_OES_tessellation_point_size              = "GL_OES_tessellation_point_size";
+const char* const E_GL_OES_texture_buffer                       = "GL_OES_texture_buffer";
+const char* const E_GL_OES_texture_cube_map_array               = "GL_OES_texture_cube_map_array";
+
+// Arrays of extensions for the above AEP duplications
+
+const char* const AEP_geometry_shader[] = { E_GL_EXT_geometry_shader, E_GL_OES_geometry_shader };
+const int Num_AEP_geometry_shader = sizeof(AEP_geometry_shader)/sizeof(AEP_geometry_shader[0]);
+
+const char* const AEP_geometry_point_size[] = { E_GL_EXT_geometry_point_size, E_GL_OES_geometry_point_size };
+const int Num_AEP_geometry_point_size = sizeof(AEP_geometry_point_size)/sizeof(AEP_geometry_point_size[0]);
+
+const char* const AEP_gpu_shader5[] = { E_GL_EXT_gpu_shader5, E_GL_OES_gpu_shader5 };
+const int Num_AEP_gpu_shader5 = sizeof(AEP_gpu_shader5)/sizeof(AEP_gpu_shader5[0]);
+
+const char* const AEP_primitive_bounding_box[] = { E_GL_EXT_primitive_bounding_box, E_GL_OES_primitive_bounding_box };
+const int Num_AEP_primitive_bounding_box = sizeof(AEP_primitive_bounding_box)/sizeof(AEP_primitive_bounding_box[0]);
+
+const char* const AEP_shader_io_blocks[] = { E_GL_EXT_shader_io_blocks, E_GL_OES_shader_io_blocks };
+const int Num_AEP_shader_io_blocks = sizeof(AEP_shader_io_blocks)/sizeof(AEP_shader_io_blocks[0]);
+
+const char* const AEP_tessellation_shader[] = { E_GL_EXT_tessellation_shader, E_GL_OES_tessellation_shader };
+const int Num_AEP_tessellation_shader = sizeof(AEP_tessellation_shader)/sizeof(AEP_tessellation_shader[0]);
+
+const char* const AEP_tessellation_point_size[] = { E_GL_EXT_tessellation_point_size, E_GL_OES_tessellation_point_size };
+const int Num_AEP_tessellation_point_size = sizeof(AEP_tessellation_point_size)/sizeof(AEP_tessellation_point_size[0]);
+
+const char* const AEP_texture_buffer[] = { E_GL_EXT_texture_buffer, E_GL_OES_texture_buffer };
+const int Num_AEP_texture_buffer = sizeof(AEP_texture_buffer)/sizeof(AEP_texture_buffer[0]);
+
+const char* const AEP_texture_cube_map_array[] = { E_GL_EXT_texture_cube_map_array, E_GL_OES_texture_cube_map_array };
+const int Num_AEP_texture_cube_map_array = sizeof(AEP_texture_cube_map_array)/sizeof(AEP_texture_cube_map_array[0]);
+
+} // end namespace glslang
+
+#endif // _VERSIONS_INCLUDED_

+ 178 - 0
src/libraries/glslang/glslang/MachineIndependent/gl_types.h

@@ -0,0 +1,178 @@
+/*
+** Copyright (c) 2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#define GL_FLOAT                          0x1406
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+
+#define GL_DOUBLE                         0x140A
+#define GL_DOUBLE_VEC2                    0x8FFC
+#define GL_DOUBLE_VEC3                    0x8FFD
+#define GL_DOUBLE_VEC4                    0x8FFE
+
+#define GL_INT                            0x1404
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+
+#define GL_UNSIGNED_INT                   0x1405
+#define GL_UNSIGNED_INT_VEC2              0x8DC6
+#define GL_UNSIGNED_INT_VEC3              0x8DC7
+#define GL_UNSIGNED_INT_VEC4              0x8DC8
+
+#define GL_INT64_ARB                      0x140E
+#define GL_INT64_VEC2_ARB                 0x8FE9
+#define GL_INT64_VEC3_ARB                 0x8FEA
+#define GL_INT64_VEC4_ARB                 0x8FEB
+
+#define GL_UNSIGNED_INT64_ARB             0x140F
+#define GL_UNSIGNED_INT64_VEC2_ARB        0x8FE5
+#define GL_UNSIGNED_INT64_VEC3_ARB        0x8FE6
+#define GL_UNSIGNED_INT64_VEC4_ARB        0x8FE7
+
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_FLOAT_MAT2x3                   0x8B65
+#define GL_FLOAT_MAT2x4                   0x8B66
+#define GL_FLOAT_MAT3x2                   0x8B67
+#define GL_FLOAT_MAT3x4                   0x8B68
+#define GL_FLOAT_MAT4x2                   0x8B69
+#define GL_FLOAT_MAT4x3                   0x8B6A
+
+#define GL_DOUBLE_MAT2                    0x8F46
+#define GL_DOUBLE_MAT3                    0x8F47
+#define GL_DOUBLE_MAT4                    0x8F48
+#define GL_DOUBLE_MAT2x3                  0x8F49
+#define GL_DOUBLE_MAT2x4                  0x8F4A
+#define GL_DOUBLE_MAT3x2                  0x8F4B
+#define GL_DOUBLE_MAT3x4                  0x8F4C
+#define GL_DOUBLE_MAT4x2                  0x8F4D
+#define GL_DOUBLE_MAT4x3                  0x8F4E
+
+#ifdef AMD_EXTENSIONS
+// Those constants are borrowed from extension NV_gpu_shader5
+#define GL_FLOAT16_NV                     0x8FF8
+#define GL_FLOAT16_VEC2_NV                0x8FF9
+#define GL_FLOAT16_VEC3_NV                0x8FFA
+#define GL_FLOAT16_VEC4_NV                0x8FFB
+
+#define GL_FLOAT16_MAT2_AMD               0x91C5
+#define GL_FLOAT16_MAT3_AMD               0x91C6
+#define GL_FLOAT16_MAT4_AMD               0x91C7
+#define GL_FLOAT16_MAT2x3_AMD             0x91C8
+#define GL_FLOAT16_MAT2x4_AMD             0x91C9
+#define GL_FLOAT16_MAT3x2_AMD             0x91CA
+#define GL_FLOAT16_MAT3x4_AMD             0x91CB
+#define GL_FLOAT16_MAT4x2_AMD             0x91CC
+#define GL_FLOAT16_MAT4x3_AMD             0x91CD
+#endif
+
+#define GL_SAMPLER_1D                     0x8B5D
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_3D                     0x8B5F
+#define GL_SAMPLER_CUBE                   0x8B60
+#define GL_SAMPLER_BUFFER                 0x8DC2
+#define GL_SAMPLER_1D_ARRAY               0x8DC0
+#define GL_SAMPLER_2D_ARRAY               0x8DC1
+#define GL_SAMPLER_1D_ARRAY_SHADOW        0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW        0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW            0x8DC5
+#define GL_SAMPLER_1D_SHADOW              0x8B61
+#define GL_SAMPLER_2D_SHADOW              0x8B62
+#define GL_SAMPLER_2D_RECT                0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW         0x8B64
+#define GL_SAMPLER_2D_MULTISAMPLE         0x9108
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY   0x910B
+#define GL_SAMPLER_CUBE_MAP_ARRAY         0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW  0x900D
+#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB     0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D
+
+#define GL_INT_SAMPLER_1D                 0x8DC9
+#define GL_INT_SAMPLER_2D                 0x8DCA
+#define GL_INT_SAMPLER_3D                 0x8DCB
+#define GL_INT_SAMPLER_CUBE               0x8DCC
+#define GL_INT_SAMPLER_1D_ARRAY           0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY           0x8DCF
+#define GL_INT_SAMPLER_2D_RECT            0x8DCD
+#define GL_INT_SAMPLER_BUFFER             0x8DD0
+#define GL_INT_SAMPLER_2D_MULTISAMPLE     0x9109
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY     0x900E
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E
+
+#define GL_UNSIGNED_INT_SAMPLER_1D        0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D        0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D        0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE      0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY  0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY  0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT   0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER    0x8DD8
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+
+#define GL_IMAGE_1D                       0x904C
+#define GL_IMAGE_2D                       0x904D
+#define GL_IMAGE_3D                       0x904E
+#define GL_IMAGE_2D_RECT                  0x904F
+#define GL_IMAGE_CUBE                     0x9050
+#define GL_IMAGE_BUFFER                   0x9051
+#define GL_IMAGE_1D_ARRAY                 0x9052
+#define GL_IMAGE_2D_ARRAY                 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY           0x9054
+#define GL_IMAGE_2D_MULTISAMPLE           0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY     0x9056
+#define GL_INT_IMAGE_1D                   0x9057
+#define GL_INT_IMAGE_2D                   0x9058
+#define GL_INT_IMAGE_3D                   0x9059
+#define GL_INT_IMAGE_2D_RECT              0x905A
+#define GL_INT_IMAGE_CUBE                 0x905B
+#define GL_INT_IMAGE_BUFFER               0x905C
+#define GL_INT_IMAGE_1D_ARRAY             0x905D
+#define GL_INT_IMAGE_2D_ARRAY             0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY       0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE       0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D          0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D          0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D          0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT     0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE        0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER      0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY    0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY    0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER    0x92DB

+ 8320 - 0
src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp

@@ -0,0 +1,8320 @@
+/* A Bison parser, made by GNU Bison 2.7.  */
+
+/* Bison implementation for Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989-1990, 2000-2012 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 "2.7"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations.  */
+/* Line 371 of yacc.c  */
+#line 41 "glslang.y"
+
+
+/* Based on:
+ANSI C Yacc grammar
+
+In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a
+matching Lex specification) for the April 30, 1985 draft version of the
+ANSI C standard.  Tom Stockfisch reposted it to net.sources in 1987; that
+original, as mentioned in the answer to question 17.25 of the comp.lang.c
+FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z.
+
+I intend to keep this version as close to the current C Standard grammar as
+possible; please let me know if you discover discrepancies.
+
+Jutta Degener, 1995
+*/
+
+#include "SymbolTable.h"
+#include "ParseHelper.h"
+#include "../Public/ShaderLang.h"
+
+using namespace glslang;
+
+
+/* Line 371 of yacc.c  */
+#line 93 "glslang_tab.cpp"
+
+# ifndef YY_NULL
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULL nullptr
+#  else
+#   define YY_NULL 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.cpp.h".  */
+#ifndef YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ATTRIBUTE = 258,
+     VARYING = 259,
+     CONST = 260,
+     BOOL = 261,
+     FLOAT = 262,
+     DOUBLE = 263,
+     INT = 264,
+     UINT = 265,
+     INT64_T = 266,
+     UINT64_T = 267,
+     FLOAT16_T = 268,
+     BREAK = 269,
+     CONTINUE = 270,
+     DO = 271,
+     ELSE = 272,
+     FOR = 273,
+     IF = 274,
+     DISCARD = 275,
+     RETURN = 276,
+     SWITCH = 277,
+     CASE = 278,
+     DEFAULT = 279,
+     SUBROUTINE = 280,
+     BVEC2 = 281,
+     BVEC3 = 282,
+     BVEC4 = 283,
+     IVEC2 = 284,
+     IVEC3 = 285,
+     IVEC4 = 286,
+     I64VEC2 = 287,
+     I64VEC3 = 288,
+     I64VEC4 = 289,
+     UVEC2 = 290,
+     UVEC3 = 291,
+     UVEC4 = 292,
+     U64VEC2 = 293,
+     U64VEC3 = 294,
+     U64VEC4 = 295,
+     VEC2 = 296,
+     VEC3 = 297,
+     VEC4 = 298,
+     MAT2 = 299,
+     MAT3 = 300,
+     MAT4 = 301,
+     CENTROID = 302,
+     IN = 303,
+     OUT = 304,
+     INOUT = 305,
+     UNIFORM = 306,
+     PATCH = 307,
+     SAMPLE = 308,
+     BUFFER = 309,
+     SHARED = 310,
+     COHERENT = 311,
+     VOLATILE = 312,
+     RESTRICT = 313,
+     READONLY = 314,
+     WRITEONLY = 315,
+     DVEC2 = 316,
+     DVEC3 = 317,
+     DVEC4 = 318,
+     DMAT2 = 319,
+     DMAT3 = 320,
+     DMAT4 = 321,
+     F16VEC2 = 322,
+     F16VEC3 = 323,
+     F16VEC4 = 324,
+     F16MAT2 = 325,
+     F16MAT3 = 326,
+     F16MAT4 = 327,
+     NOPERSPECTIVE = 328,
+     FLAT = 329,
+     SMOOTH = 330,
+     LAYOUT = 331,
+     __EXPLICITINTERPAMD = 332,
+     MAT2X2 = 333,
+     MAT2X3 = 334,
+     MAT2X4 = 335,
+     MAT3X2 = 336,
+     MAT3X3 = 337,
+     MAT3X4 = 338,
+     MAT4X2 = 339,
+     MAT4X3 = 340,
+     MAT4X4 = 341,
+     DMAT2X2 = 342,
+     DMAT2X3 = 343,
+     DMAT2X4 = 344,
+     DMAT3X2 = 345,
+     DMAT3X3 = 346,
+     DMAT3X4 = 347,
+     DMAT4X2 = 348,
+     DMAT4X3 = 349,
+     DMAT4X4 = 350,
+     F16MAT2X2 = 351,
+     F16MAT2X3 = 352,
+     F16MAT2X4 = 353,
+     F16MAT3X2 = 354,
+     F16MAT3X3 = 355,
+     F16MAT3X4 = 356,
+     F16MAT4X2 = 357,
+     F16MAT4X3 = 358,
+     F16MAT4X4 = 359,
+     ATOMIC_UINT = 360,
+     SAMPLER1D = 361,
+     SAMPLER2D = 362,
+     SAMPLER3D = 363,
+     SAMPLERCUBE = 364,
+     SAMPLER1DSHADOW = 365,
+     SAMPLER2DSHADOW = 366,
+     SAMPLERCUBESHADOW = 367,
+     SAMPLER1DARRAY = 368,
+     SAMPLER2DARRAY = 369,
+     SAMPLER1DARRAYSHADOW = 370,
+     SAMPLER2DARRAYSHADOW = 371,
+     ISAMPLER1D = 372,
+     ISAMPLER2D = 373,
+     ISAMPLER3D = 374,
+     ISAMPLERCUBE = 375,
+     ISAMPLER1DARRAY = 376,
+     ISAMPLER2DARRAY = 377,
+     USAMPLER1D = 378,
+     USAMPLER2D = 379,
+     USAMPLER3D = 380,
+     USAMPLERCUBE = 381,
+     USAMPLER1DARRAY = 382,
+     USAMPLER2DARRAY = 383,
+     SAMPLER2DRECT = 384,
+     SAMPLER2DRECTSHADOW = 385,
+     ISAMPLER2DRECT = 386,
+     USAMPLER2DRECT = 387,
+     SAMPLERBUFFER = 388,
+     ISAMPLERBUFFER = 389,
+     USAMPLERBUFFER = 390,
+     SAMPLERCUBEARRAY = 391,
+     SAMPLERCUBEARRAYSHADOW = 392,
+     ISAMPLERCUBEARRAY = 393,
+     USAMPLERCUBEARRAY = 394,
+     SAMPLER2DMS = 395,
+     ISAMPLER2DMS = 396,
+     USAMPLER2DMS = 397,
+     SAMPLER2DMSARRAY = 398,
+     ISAMPLER2DMSARRAY = 399,
+     USAMPLER2DMSARRAY = 400,
+     SAMPLEREXTERNALOES = 401,
+     SAMPLER = 402,
+     SAMPLERSHADOW = 403,
+     TEXTURE1D = 404,
+     TEXTURE2D = 405,
+     TEXTURE3D = 406,
+     TEXTURECUBE = 407,
+     TEXTURE1DARRAY = 408,
+     TEXTURE2DARRAY = 409,
+     ITEXTURE1D = 410,
+     ITEXTURE2D = 411,
+     ITEXTURE3D = 412,
+     ITEXTURECUBE = 413,
+     ITEXTURE1DARRAY = 414,
+     ITEXTURE2DARRAY = 415,
+     UTEXTURE1D = 416,
+     UTEXTURE2D = 417,
+     UTEXTURE3D = 418,
+     UTEXTURECUBE = 419,
+     UTEXTURE1DARRAY = 420,
+     UTEXTURE2DARRAY = 421,
+     TEXTURE2DRECT = 422,
+     ITEXTURE2DRECT = 423,
+     UTEXTURE2DRECT = 424,
+     TEXTUREBUFFER = 425,
+     ITEXTUREBUFFER = 426,
+     UTEXTUREBUFFER = 427,
+     TEXTURECUBEARRAY = 428,
+     ITEXTURECUBEARRAY = 429,
+     UTEXTURECUBEARRAY = 430,
+     TEXTURE2DMS = 431,
+     ITEXTURE2DMS = 432,
+     UTEXTURE2DMS = 433,
+     TEXTURE2DMSARRAY = 434,
+     ITEXTURE2DMSARRAY = 435,
+     UTEXTURE2DMSARRAY = 436,
+     SUBPASSINPUT = 437,
+     SUBPASSINPUTMS = 438,
+     ISUBPASSINPUT = 439,
+     ISUBPASSINPUTMS = 440,
+     USUBPASSINPUT = 441,
+     USUBPASSINPUTMS = 442,
+     IMAGE1D = 443,
+     IIMAGE1D = 444,
+     UIMAGE1D = 445,
+     IMAGE2D = 446,
+     IIMAGE2D = 447,
+     UIMAGE2D = 448,
+     IMAGE3D = 449,
+     IIMAGE3D = 450,
+     UIMAGE3D = 451,
+     IMAGE2DRECT = 452,
+     IIMAGE2DRECT = 453,
+     UIMAGE2DRECT = 454,
+     IMAGECUBE = 455,
+     IIMAGECUBE = 456,
+     UIMAGECUBE = 457,
+     IMAGEBUFFER = 458,
+     IIMAGEBUFFER = 459,
+     UIMAGEBUFFER = 460,
+     IMAGE1DARRAY = 461,
+     IIMAGE1DARRAY = 462,
+     UIMAGE1DARRAY = 463,
+     IMAGE2DARRAY = 464,
+     IIMAGE2DARRAY = 465,
+     UIMAGE2DARRAY = 466,
+     IMAGECUBEARRAY = 467,
+     IIMAGECUBEARRAY = 468,
+     UIMAGECUBEARRAY = 469,
+     IMAGE2DMS = 470,
+     IIMAGE2DMS = 471,
+     UIMAGE2DMS = 472,
+     IMAGE2DMSARRAY = 473,
+     IIMAGE2DMSARRAY = 474,
+     UIMAGE2DMSARRAY = 475,
+     STRUCT = 476,
+     VOID = 477,
+     WHILE = 478,
+     IDENTIFIER = 479,
+     TYPE_NAME = 480,
+     FLOATCONSTANT = 481,
+     DOUBLECONSTANT = 482,
+     INTCONSTANT = 483,
+     UINTCONSTANT = 484,
+     INT64CONSTANT = 485,
+     UINT64CONSTANT = 486,
+     BOOLCONSTANT = 487,
+     FLOAT16CONSTANT = 488,
+     LEFT_OP = 489,
+     RIGHT_OP = 490,
+     INC_OP = 491,
+     DEC_OP = 492,
+     LE_OP = 493,
+     GE_OP = 494,
+     EQ_OP = 495,
+     NE_OP = 496,
+     AND_OP = 497,
+     OR_OP = 498,
+     XOR_OP = 499,
+     MUL_ASSIGN = 500,
+     DIV_ASSIGN = 501,
+     ADD_ASSIGN = 502,
+     MOD_ASSIGN = 503,
+     LEFT_ASSIGN = 504,
+     RIGHT_ASSIGN = 505,
+     AND_ASSIGN = 506,
+     XOR_ASSIGN = 507,
+     OR_ASSIGN = 508,
+     SUB_ASSIGN = 509,
+     LEFT_PAREN = 510,
+     RIGHT_PAREN = 511,
+     LEFT_BRACKET = 512,
+     RIGHT_BRACKET = 513,
+     LEFT_BRACE = 514,
+     RIGHT_BRACE = 515,
+     DOT = 516,
+     COMMA = 517,
+     COLON = 518,
+     EQUAL = 519,
+     SEMICOLON = 520,
+     BANG = 521,
+     DASH = 522,
+     TILDE = 523,
+     PLUS = 524,
+     STAR = 525,
+     SLASH = 526,
+     PERCENT = 527,
+     LEFT_ANGLE = 528,
+     RIGHT_ANGLE = 529,
+     VERTICAL_BAR = 530,
+     CARET = 531,
+     AMPERSAND = 532,
+     QUESTION = 533,
+     INVARIANT = 534,
+     PRECISE = 535,
+     HIGH_PRECISION = 536,
+     MEDIUM_PRECISION = 537,
+     LOW_PRECISION = 538,
+     PRECISION = 539,
+     PACKED = 540,
+     RESOURCE = 541,
+     SUPERP = 542
+   };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 387 of yacc.c  */
+#line 66 "glslang.y"
+
+    struct {
+        glslang::TSourceLoc loc;
+        union {
+            glslang::TString *string;
+            int i;
+            unsigned int u;
+            long long i64;
+            unsigned long long u64;
+            bool b;
+            double d;
+        };
+        glslang::TSymbol* symbol;
+    } lex;
+    struct {
+        glslang::TSourceLoc loc;
+        glslang::TOperator op;
+        union {
+            TIntermNode* intermNode;
+            glslang::TIntermNodePair nodePair;
+            glslang::TIntermTyped* intermTypedNode;
+        };
+        union {
+            glslang::TPublicType type;
+            glslang::TFunction* function;
+            glslang::TParameter param;
+            glslang::TTypeLoc typeLine;
+            glslang::TTypeList* typeList;
+            glslang::TArraySizes* arraySizes;
+            glslang::TIdentifierList* identifierList;
+        };
+    } interm;
+
+
+/* Line 387 of yacc.c  */
+#line 458 "glslang_tab.cpp"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (glslang::TParseContext* pParseContext);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_CPP_H_INCLUDED  */
+
+/* Copy the second part of user declarations.  */
+/* Line 390 of yacc.c  */
+#line 100 "glslang.y"
+
+
+/* windows only pragma */
+#ifdef _MSC_VER
+    #pragma warning(disable : 4065)
+    #pragma warning(disable : 4127)
+    #pragma warning(disable : 4244)
+#endif
+
+#define parseContext (*pParseContext)
+#define yyerror(context, msg) context->parserError(msg)
+
+extern int yylex(YYSTYPE*, TParseContext&);
+
+
+/* Line 390 of yacc.c  */
+#line 501 "glslang_tab.cpp"
+
+#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;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int 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 && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  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
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#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 && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     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 (YYID (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 && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (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;
+};
+
+/* 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)) \
+      + 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 (YYID (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 (YYID (0))
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  265
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   6373
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  288
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  100
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  439
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  571
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   542
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint16 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
+     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+     145,   146,   147,   148,   149,   150,   151,   152,   153,   154,
+     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   172,   173,   174,
+     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
+     205,   206,   207,   208,   209,   210,   211,   212,   213,   214,
+     215,   216,   217,   218,   219,   220,   221,   222,   223,   224,
+     225,   226,   227,   228,   229,   230,   231,   232,   233,   234,
+     235,   236,   237,   238,   239,   240,   241,   242,   243,   244,
+     245,   246,   247,   248,   249,   250,   251,   252,   253,   254,
+     255,   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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     5,     7,     9,    11,    13,    15,    17,
+      19,    21,    23,    27,    29,    34,    36,    40,    43,    46,
+      48,    50,    52,    55,    58,    61,    63,    66,    70,    73,
+      75,    77,    79,    82,    85,    88,    90,    92,    94,    96,
+      98,   102,   106,   110,   112,   116,   120,   122,   126,   130,
+     132,   136,   140,   144,   148,   150,   154,   158,   160,   164,
+     166,   170,   172,   176,   178,   182,   184,   188,   190,   194,
+     196,   197,   204,   206,   210,   212,   214,   216,   218,   220,
+     222,   224,   226,   228,   230,   232,   234,   238,   240,   243,
+     246,   251,   254,   258,   263,   266,   270,   275,   276,   283,
+     286,   290,   293,   295,   297,   300,   304,   308,   311,   315,
+     318,   320,   323,   325,   327,   329,   333,   338,   345,   351,
+     353,   356,   360,   366,   371,   373,   376,   378,   380,   382,
+     384,   386,   391,   393,   397,   399,   403,   405,   407,   409,
+     412,   414,   416,   418,   420,   422,   424,   426,   428,   430,
+     432,   434,   436,   438,   440,   442,   444,   446,   448,   450,
+     452,   454,   456,   458,   460,   465,   467,   471,   473,   476,
+     479,   483,   487,   492,   494,   496,   498,   500,   502,   504,
+     506,   508,   510,   512,   514,   516,   518,   520,   522,   524,
+     526,   528,   530,   532,   534,   536,   538,   540,   542,   544,
+     546,   548,   550,   552,   554,   556,   558,   560,   562,   564,
+     566,   568,   570,   572,   574,   576,   578,   580,   582,   584,
+     586,   588,   590,   592,   594,   596,   598,   600,   602,   604,
+     606,   608,   610,   612,   614,   616,   618,   620,   622,   624,
+     626,   628,   630,   632,   634,   636,   638,   640,   642,   644,
+     646,   648,   650,   652,   654,   656,   658,   660,   662,   664,
+     666,   668,   670,   672,   674,   676,   678,   680,   682,   684,
+     686,   688,   690,   692,   694,   696,   698,   700,   702,   704,
+     706,   708,   710,   712,   714,   716,   718,   720,   722,   724,
+     726,   728,   730,   732,   734,   736,   738,   740,   742,   744,
+     746,   748,   750,   752,   754,   756,   758,   760,   762,   764,
+     766,   768,   770,   772,   774,   776,   778,   780,   782,   784,
+     786,   788,   790,   792,   794,   796,   798,   800,   802,   804,
+     806,   808,   810,   812,   814,   816,   818,   820,   822,   824,
+     826,   828,   830,   832,   834,   836,   838,   840,   842,   844,
+     846,   848,   850,   852,   854,   856,   858,   860,   862,   864,
+     866,   868,   870,   872,   873,   880,   881,   887,   889,   892,
+     896,   901,   903,   907,   909,   912,   914,   918,   923,   925,
+     929,   931,   933,   935,   937,   939,   941,   943,   945,   947,
+     949,   952,   953,   954,   960,   962,   964,   965,   968,   969,
+     972,   975,   979,   981,   984,   986,   989,   995,   999,  1001,
+    1003,  1008,  1009,  1018,  1019,  1021,  1025,  1028,  1029,  1036,
+    1037,  1046,  1047,  1055,  1057,  1059,  1061,  1062,  1065,  1069,
+    1072,  1075,  1078,  1082,  1085,  1087,  1090,  1092,  1094,  1095
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int16 yyrhs[] =
+{
+     384,     0,    -1,   224,    -1,   289,    -1,   228,    -1,   229,
+      -1,   230,    -1,   231,    -1,   226,    -1,   227,    -1,   233,
+      -1,   232,    -1,   255,   317,   256,    -1,   290,    -1,   291,
+     257,   292,   258,    -1,   293,    -1,   291,   261,   224,    -1,
+     291,   236,    -1,   291,   237,    -1,   317,    -1,   294,    -1,
+     295,    -1,   297,   256,    -1,   296,   256,    -1,   298,   222,
+      -1,   298,    -1,   298,   315,    -1,   297,   262,   315,    -1,
+     299,   255,    -1,   343,    -1,   291,    -1,   291,    -1,   236,
+     300,    -1,   237,   300,    -1,   301,   300,    -1,   269,    -1,
+     267,    -1,   266,    -1,   268,    -1,   300,    -1,   302,   270,
+     300,    -1,   302,   271,   300,    -1,   302,   272,   300,    -1,
+     302,    -1,   303,   269,   302,    -1,   303,   267,   302,    -1,
+     303,    -1,   304,   234,   303,    -1,   304,   235,   303,    -1,
+     304,    -1,   305,   273,   304,    -1,   305,   274,   304,    -1,
+     305,   238,   304,    -1,   305,   239,   304,    -1,   305,    -1,
+     306,   240,   305,    -1,   306,   241,   305,    -1,   306,    -1,
+     307,   277,   306,    -1,   307,    -1,   308,   276,   307,    -1,
+     308,    -1,   309,   275,   308,    -1,   309,    -1,   310,   242,
+     309,    -1,   310,    -1,   311,   244,   310,    -1,   311,    -1,
+     312,   243,   311,    -1,   312,    -1,    -1,   312,   278,   314,
+     317,   263,   315,    -1,   313,    -1,   300,   316,   315,    -1,
+     264,    -1,   245,    -1,   246,    -1,   248,    -1,   247,    -1,
+     254,    -1,   249,    -1,   250,    -1,   251,    -1,   252,    -1,
+     253,    -1,   315,    -1,   317,   262,   315,    -1,   313,    -1,
+     323,   265,    -1,   330,   265,    -1,   284,   346,   343,   265,
+      -1,   320,   265,    -1,   320,   224,   265,    -1,   320,   224,
+     344,   265,    -1,   339,   265,    -1,   339,   224,   265,    -1,
+     339,   224,   322,   265,    -1,    -1,   339,   224,   259,   321,
+     350,   260,    -1,   262,   224,    -1,   322,   262,   224,    -1,
+     324,   256,    -1,   326,    -1,   325,    -1,   326,   328,    -1,
+     325,   262,   328,    -1,   332,   224,   255,    -1,   343,   224,
+      -1,   343,   224,   344,    -1,   339,   327,    -1,   327,    -1,
+     339,   329,    -1,   329,    -1,   343,    -1,   331,    -1,   330,
+     262,   224,    -1,   330,   262,   224,   344,    -1,   330,   262,
+     224,   344,   264,   354,    -1,   330,   262,   224,   264,   354,
+      -1,   332,    -1,   332,   224,    -1,   332,   224,   344,    -1,
+     332,   224,   344,   264,   354,    -1,   332,   224,   264,   354,
+      -1,   343,    -1,   339,   343,    -1,   279,    -1,    75,    -1,
+      74,    -1,    73,    -1,    77,    -1,    76,   255,   336,   256,
+      -1,   337,    -1,   336,   262,   337,    -1,   224,    -1,   224,
+     264,   318,    -1,    55,    -1,   280,    -1,   340,    -1,   339,
+     340,    -1,   341,    -1,   335,    -1,   346,    -1,   334,    -1,
+     333,    -1,   338,    -1,     5,    -1,     3,    -1,     4,    -1,
+      50,    -1,    48,    -1,    49,    -1,    47,    -1,    52,    -1,
+      53,    -1,    51,    -1,    54,    -1,    55,    -1,    56,    -1,
+      57,    -1,    58,    -1,    59,    -1,    60,    -1,    25,    -1,
+      25,   255,   342,   256,    -1,   225,    -1,   342,   262,   225,
+      -1,   345,    -1,   345,   344,    -1,   257,   258,    -1,   257,
+     313,   258,    -1,   344,   257,   258,    -1,   344,   257,   313,
+     258,    -1,   222,    -1,     7,    -1,     8,    -1,    13,    -1,
+       9,    -1,    10,    -1,    11,    -1,    12,    -1,     6,    -1,
+      41,    -1,    42,    -1,    43,    -1,    61,    -1,    62,    -1,
+      63,    -1,    67,    -1,    68,    -1,    69,    -1,    26,    -1,
+      27,    -1,    28,    -1,    29,    -1,    30,    -1,    31,    -1,
+      32,    -1,    33,    -1,    34,    -1,    35,    -1,    36,    -1,
+      37,    -1,    38,    -1,    39,    -1,    40,    -1,    44,    -1,
+      45,    -1,    46,    -1,    78,    -1,    79,    -1,    80,    -1,
+      81,    -1,    82,    -1,    83,    -1,    84,    -1,    85,    -1,
+      86,    -1,    64,    -1,    65,    -1,    66,    -1,    87,    -1,
+      88,    -1,    89,    -1,    90,    -1,    91,    -1,    92,    -1,
+      93,    -1,    94,    -1,    95,    -1,    70,    -1,    71,    -1,
+      72,    -1,    96,    -1,    97,    -1,    98,    -1,    99,    -1,
+     100,    -1,   101,    -1,   102,    -1,   103,    -1,   104,    -1,
+     105,    -1,   106,    -1,   107,    -1,   108,    -1,   109,    -1,
+     110,    -1,   111,    -1,   112,    -1,   113,    -1,   114,    -1,
+     115,    -1,   116,    -1,   136,    -1,   137,    -1,   117,    -1,
+     118,    -1,   119,    -1,   120,    -1,   121,    -1,   122,    -1,
+     138,    -1,   123,    -1,   124,    -1,   125,    -1,   126,    -1,
+     127,    -1,   128,    -1,   139,    -1,   129,    -1,   130,    -1,
+     131,    -1,   132,    -1,   133,    -1,   134,    -1,   135,    -1,
+     140,    -1,   141,    -1,   142,    -1,   143,    -1,   144,    -1,
+     145,    -1,   147,    -1,   148,    -1,   149,    -1,   150,    -1,
+     151,    -1,   152,    -1,   153,    -1,   154,    -1,   173,    -1,
+     155,    -1,   156,    -1,   157,    -1,   158,    -1,   159,    -1,
+     160,    -1,   174,    -1,   161,    -1,   162,    -1,   163,    -1,
+     164,    -1,   165,    -1,   166,    -1,   175,    -1,   167,    -1,
+     168,    -1,   169,    -1,   170,    -1,   171,    -1,   172,    -1,
+     176,    -1,   177,    -1,   178,    -1,   179,    -1,   180,    -1,
+     181,    -1,   188,    -1,   189,    -1,   190,    -1,   191,    -1,
+     192,    -1,   193,    -1,   194,    -1,   195,    -1,   196,    -1,
+     197,    -1,   198,    -1,   199,    -1,   200,    -1,   201,    -1,
+     202,    -1,   203,    -1,   204,    -1,   205,    -1,   206,    -1,
+     207,    -1,   208,    -1,   209,    -1,   210,    -1,   211,    -1,
+     212,    -1,   213,    -1,   214,    -1,   215,    -1,   216,    -1,
+     217,    -1,   218,    -1,   219,    -1,   220,    -1,   146,    -1,
+     182,    -1,   183,    -1,   184,    -1,   185,    -1,   186,    -1,
+     187,    -1,   347,    -1,   225,    -1,   281,    -1,   282,    -1,
+     283,    -1,    -1,   221,   224,   259,   348,   350,   260,    -1,
+      -1,   221,   259,   349,   350,   260,    -1,   351,    -1,   350,
+     351,    -1,   343,   352,   265,    -1,   339,   343,   352,   265,
+      -1,   353,    -1,   352,   262,   353,    -1,   224,    -1,   224,
+     344,    -1,   315,    -1,   259,   355,   260,    -1,   259,   355,
+     262,   260,    -1,   354,    -1,   355,   262,   354,    -1,   319,
+      -1,   359,    -1,   358,    -1,   356,    -1,   368,    -1,   369,
+      -1,   372,    -1,   375,    -1,   376,    -1,   383,    -1,   259,
+     260,    -1,    -1,    -1,   259,   360,   367,   361,   260,    -1,
+     366,    -1,   358,    -1,    -1,   364,   359,    -1,    -1,   365,
+     358,    -1,   259,   260,    -1,   259,   367,   260,    -1,   357,
+      -1,   367,   357,    -1,   265,    -1,   317,   265,    -1,    19,
+     255,   317,   256,   370,    -1,   363,    17,   363,    -1,   363,
+      -1,   317,    -1,   332,   224,   264,   354,    -1,    -1,    22,
+     255,   317,   256,   373,   259,   374,   260,    -1,    -1,   367,
+      -1,    23,   317,   263,    -1,    24,   263,    -1,    -1,   223,
+     255,   377,   371,   256,   362,    -1,    -1,    16,   378,   357,
+     223,   255,   317,   256,   265,    -1,    -1,    18,   255,   379,
+     380,   382,   256,   362,    -1,   368,    -1,   356,    -1,   371,
+      -1,    -1,   381,   265,    -1,   381,   265,   317,    -1,    15,
+     265,    -1,    14,   265,    -1,    21,   265,    -1,    21,   317,
+     265,    -1,    20,   265,    -1,   385,    -1,   384,   385,    -1,
+     386,    -1,   319,    -1,    -1,   323,   387,   366,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   250,   250,   256,   259,   262,   266,   270,   274,   277,
+     281,   287,   290,   298,   301,   304,   307,   310,   315,   323,
+     330,   337,   343,   347,   354,   357,   363,   370,   380,   388,
+     393,   423,   429,   433,   437,   457,   458,   459,   460,   466,
+     467,   472,   477,   486,   487,   492,   500,   501,   507,   516,
+     517,   522,   527,   532,   540,   541,   549,   560,   561,   570,
+     571,   580,   581,   590,   591,   599,   600,   608,   609,   617,
+     618,   618,   636,   637,   652,   656,   660,   664,   669,   673,
+     677,   681,   685,   689,   693,   700,   703,   714,   721,   726,
+     731,   739,   743,   747,   751,   756,   761,   770,   770,   781,
+     785,   792,   799,   802,   809,   817,   837,   855,   870,   893,
+     904,   914,   924,   934,   943,   946,   950,   954,   959,   967,
+     972,   977,   982,   987,   996,  1007,  1034,  1043,  1050,  1057,
+    1064,  1076,  1082,  1085,  1092,  1096,  1100,  1108,  1117,  1120,
+    1131,  1134,  1137,  1141,  1145,  1149,  1156,  1160,  1172,  1186,
+    1191,  1197,  1203,  1210,  1216,  1221,  1226,  1231,  1238,  1242,
+    1246,  1250,  1254,  1258,  1264,  1276,  1279,  1284,  1288,  1297,
+    1302,  1310,  1314,  1324,  1328,  1332,  1337,  1344,  1348,  1353,
+    1358,  1363,  1367,  1372,  1377,  1382,  1388,  1394,  1400,  1408,
+    1416,  1424,  1429,  1434,  1439,  1444,  1449,  1454,  1460,  1466,
+    1472,  1478,  1484,  1490,  1496,  1502,  1508,  1513,  1518,  1523,
+    1528,  1533,  1538,  1543,  1548,  1553,  1558,  1563,  1568,  1574,
+    1580,  1586,  1592,  1598,  1604,  1610,  1616,  1622,  1628,  1634,
+    1640,  1648,  1656,  1664,  1672,  1680,  1688,  1696,  1704,  1712,
+    1720,  1728,  1736,  1741,  1746,  1751,  1756,  1761,  1766,  1771,
+    1776,  1781,  1786,  1791,  1796,  1801,  1806,  1811,  1816,  1821,
+    1826,  1831,  1836,  1841,  1846,  1851,  1856,  1861,  1866,  1871,
+    1876,  1881,  1886,  1891,  1896,  1901,  1906,  1911,  1916,  1921,
+    1926,  1931,  1936,  1941,  1946,  1951,  1956,  1961,  1966,  1971,
+    1976,  1981,  1986,  1991,  1996,  2001,  2006,  2011,  2016,  2021,
+    2026,  2031,  2036,  2041,  2046,  2051,  2056,  2061,  2066,  2071,
+    2076,  2081,  2086,  2091,  2096,  2101,  2106,  2111,  2116,  2121,
+    2126,  2131,  2136,  2141,  2146,  2151,  2156,  2161,  2166,  2171,
+    2176,  2181,  2186,  2191,  2196,  2201,  2206,  2211,  2216,  2221,
+    2226,  2231,  2236,  2241,  2246,  2251,  2256,  2261,  2266,  2271,
+    2276,  2281,  2287,  2293,  2299,  2305,  2311,  2317,  2323,  2328,
+    2344,  2349,  2354,  2362,  2362,  2373,  2373,  2383,  2386,  2399,
+    2417,  2441,  2445,  2451,  2456,  2467,  2470,  2476,  2485,  2488,
+    2494,  2498,  2499,  2505,  2506,  2507,  2508,  2509,  2510,  2511,
+    2515,  2516,  2520,  2516,  2532,  2533,  2537,  2537,  2544,  2544,
+    2558,  2561,  2569,  2577,  2588,  2589,  2593,  2600,  2604,  2612,
+    2616,  2629,  2629,  2649,  2652,  2658,  2670,  2682,  2682,  2697,
+    2697,  2713,  2713,  2734,  2737,  2743,  2746,  2752,  2756,  2763,
+    2768,  2773,  2780,  2783,  2792,  2796,  2803,  2806,  2812,  2812
+};
+#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", "ATTRIBUTE", "VARYING", "CONST", "BOOL",
+  "FLOAT", "DOUBLE", "INT", "UINT", "INT64_T", "UINT64_T", "FLOAT16_T",
+  "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN",
+  "SWITCH", "CASE", "DEFAULT", "SUBROUTINE", "BVEC2", "BVEC3", "BVEC4",
+  "IVEC2", "IVEC3", "IVEC4", "I64VEC2", "I64VEC3", "I64VEC4", "UVEC2",
+  "UVEC3", "UVEC4", "U64VEC2", "U64VEC3", "U64VEC4", "VEC2", "VEC3",
+  "VEC4", "MAT2", "MAT3", "MAT4", "CENTROID", "IN", "OUT", "INOUT",
+  "UNIFORM", "PATCH", "SAMPLE", "BUFFER", "SHARED", "COHERENT", "VOLATILE",
+  "RESTRICT", "READONLY", "WRITEONLY", "DVEC2", "DVEC3", "DVEC4", "DMAT2",
+  "DMAT3", "DMAT4", "F16VEC2", "F16VEC3", "F16VEC4", "F16MAT2", "F16MAT3",
+  "F16MAT4", "NOPERSPECTIVE", "FLAT", "SMOOTH", "LAYOUT",
+  "__EXPLICITINTERPAMD", "MAT2X2", "MAT2X3", "MAT2X4", "MAT3X2", "MAT3X3",
+  "MAT3X4", "MAT4X2", "MAT4X3", "MAT4X4", "DMAT2X2", "DMAT2X3", "DMAT2X4",
+  "DMAT3X2", "DMAT3X3", "DMAT3X4", "DMAT4X2", "DMAT4X3", "DMAT4X4",
+  "F16MAT2X2", "F16MAT2X3", "F16MAT2X4", "F16MAT3X2", "F16MAT3X3",
+  "F16MAT3X4", "F16MAT4X2", "F16MAT4X3", "F16MAT4X4", "ATOMIC_UINT",
+  "SAMPLER1D", "SAMPLER2D", "SAMPLER3D", "SAMPLERCUBE", "SAMPLER1DSHADOW",
+  "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", "SAMPLER1DARRAY",
+  "SAMPLER2DARRAY", "SAMPLER1DARRAYSHADOW", "SAMPLER2DARRAYSHADOW",
+  "ISAMPLER1D", "ISAMPLER2D", "ISAMPLER3D", "ISAMPLERCUBE",
+  "ISAMPLER1DARRAY", "ISAMPLER2DARRAY", "USAMPLER1D", "USAMPLER2D",
+  "USAMPLER3D", "USAMPLERCUBE", "USAMPLER1DARRAY", "USAMPLER2DARRAY",
+  "SAMPLER2DRECT", "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT",
+  "USAMPLER2DRECT", "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER",
+  "SAMPLERCUBEARRAY", "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY",
+  "USAMPLERCUBEARRAY", "SAMPLER2DMS", "ISAMPLER2DMS", "USAMPLER2DMS",
+  "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", "USAMPLER2DMSARRAY",
+  "SAMPLEREXTERNALOES", "SAMPLER", "SAMPLERSHADOW", "TEXTURE1D",
+  "TEXTURE2D", "TEXTURE3D", "TEXTURECUBE", "TEXTURE1DARRAY",
+  "TEXTURE2DARRAY", "ITEXTURE1D", "ITEXTURE2D", "ITEXTURE3D",
+  "ITEXTURECUBE", "ITEXTURE1DARRAY", "ITEXTURE2DARRAY", "UTEXTURE1D",
+  "UTEXTURE2D", "UTEXTURE3D", "UTEXTURECUBE", "UTEXTURE1DARRAY",
+  "UTEXTURE2DARRAY", "TEXTURE2DRECT", "ITEXTURE2DRECT", "UTEXTURE2DRECT",
+  "TEXTUREBUFFER", "ITEXTUREBUFFER", "UTEXTUREBUFFER", "TEXTURECUBEARRAY",
+  "ITEXTURECUBEARRAY", "UTEXTURECUBEARRAY", "TEXTURE2DMS", "ITEXTURE2DMS",
+  "UTEXTURE2DMS", "TEXTURE2DMSARRAY", "ITEXTURE2DMSARRAY",
+  "UTEXTURE2DMSARRAY", "SUBPASSINPUT", "SUBPASSINPUTMS", "ISUBPASSINPUT",
+  "ISUBPASSINPUTMS", "USUBPASSINPUT", "USUBPASSINPUTMS", "IMAGE1D",
+  "IIMAGE1D", "UIMAGE1D", "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D",
+  "IIMAGE3D", "UIMAGE3D", "IMAGE2DRECT", "IIMAGE2DRECT", "UIMAGE2DRECT",
+  "IMAGECUBE", "IIMAGECUBE", "UIMAGECUBE", "IMAGEBUFFER", "IIMAGEBUFFER",
+  "UIMAGEBUFFER", "IMAGE1DARRAY", "IIMAGE1DARRAY", "UIMAGE1DARRAY",
+  "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBEARRAY",
+  "IIMAGECUBEARRAY", "UIMAGECUBEARRAY", "IMAGE2DMS", "IIMAGE2DMS",
+  "UIMAGE2DMS", "IMAGE2DMSARRAY", "IIMAGE2DMSARRAY", "UIMAGE2DMSARRAY",
+  "STRUCT", "VOID", "WHILE", "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT",
+  "DOUBLECONSTANT", "INTCONSTANT", "UINTCONSTANT", "INT64CONSTANT",
+  "UINT64CONSTANT", "BOOLCONSTANT", "FLOAT16CONSTANT", "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", "INVARIANT", "PRECISE", "HIGH_PRECISION",
+  "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "PACKED", "RESOURCE",
+  "SUPERP", "$accept", "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", "$@1",
+  "assignment_expression", "assignment_operator", "expression",
+  "constant_expression", "declaration", "block_structure", "$@2",
+  "identifier_list", "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", "invariant_qualifier", "interpolation_qualifier",
+  "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id",
+  "precise_qualifier", "type_qualifier", "single_type_qualifier",
+  "storage_qualifier", "type_name_list", "type_specifier",
+  "array_specifier", "type_specifier_nonarray", "precision_qualifier",
+  "struct_specifier", "$@3", "$@4", "struct_declaration_list",
+  "struct_declaration", "struct_declarator_list", "struct_declarator",
+  "initializer", "initializer_list", "declaration_statement", "statement",
+  "simple_statement", "compound_statement", "$@5", "$@6",
+  "statement_no_new_scope", "statement_scoped", "$@7", "$@8",
+  "compound_statement_no_new_scope", "statement_list",
+  "expression_statement", "selection_statement",
+  "selection_rest_statement", "condition", "switch_statement", "$@9",
+  "switch_statement_list", "case_label", "iteration_statement", "$@10",
+  "$@11", "$@12", "for_init_statement", "conditionopt",
+  "for_rest_statement", "jump_statement", "translation_unit",
+  "external_declaration", "function_definition", "$@13", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
+     315,   316,   317,   318,   319,   320,   321,   322,   323,   324,
+     325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
+     335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
+     345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
+     355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
+     365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
+     375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
+     395,   396,   397,   398,   399,   400,   401,   402,   403,   404,
+     405,   406,   407,   408,   409,   410,   411,   412,   413,   414,
+     415,   416,   417,   418,   419,   420,   421,   422,   423,   424,
+     425,   426,   427,   428,   429,   430,   431,   432,   433,   434,
+     435,   436,   437,   438,   439,   440,   441,   442,   443,   444,
+     445,   446,   447,   448,   449,   450,   451,   452,   453,   454,
+     455,   456,   457,   458,   459,   460,   461,   462,   463,   464,
+     465,   466,   467,   468,   469,   470,   471,   472,   473,   474,
+     475,   476,   477,   478,   479,   480,   481,   482,   483,   484,
+     485,   486,   487,   488,   489,   490,   491,   492,   493,   494,
+     495,   496,   497,   498,   499,   500,   501,   502,   503,   504,
+     505,   506,   507,   508,   509,   510,   511,   512,   513,   514,
+     515,   516,   517,   518,   519,   520,   521,   522,   523,   524,
+     525,   526,   527,   528,   529,   530,   531,   532,   533,   534,
+     535,   536,   537,   538,   539,   540,   541,   542
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint16 yyr1[] =
+{
+       0,   288,   289,   290,   290,   290,   290,   290,   290,   290,
+     290,   290,   290,   291,   291,   291,   291,   291,   291,   292,
+     293,   294,   295,   295,   296,   296,   297,   297,   298,   299,
+     299,   300,   300,   300,   300,   301,   301,   301,   301,   302,
+     302,   302,   302,   303,   303,   303,   304,   304,   304,   305,
+     305,   305,   305,   305,   306,   306,   306,   307,   307,   308,
+     308,   309,   309,   310,   310,   311,   311,   312,   312,   313,
+     314,   313,   315,   315,   316,   316,   316,   316,   316,   316,
+     316,   316,   316,   316,   316,   317,   317,   318,   319,   319,
+     319,   319,   319,   319,   319,   319,   319,   321,   320,   322,
+     322,   323,   324,   324,   325,   325,   326,   327,   327,   328,
+     328,   328,   328,   329,   330,   330,   330,   330,   330,   331,
+     331,   331,   331,   331,   332,   332,   333,   334,   334,   334,
+     334,   335,   336,   336,   337,   337,   337,   338,   339,   339,
+     340,   340,   340,   340,   340,   340,   341,   341,   341,   341,
+     341,   341,   341,   341,   341,   341,   341,   341,   341,   341,
+     341,   341,   341,   341,   341,   342,   342,   343,   343,   344,
+     344,   344,   344,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     345,   345,   345,   345,   345,   345,   345,   345,   345,   345,
+     346,   346,   346,   348,   347,   349,   347,   350,   350,   351,
+     351,   352,   352,   353,   353,   354,   354,   354,   355,   355,
+     356,   357,   357,   358,   358,   358,   358,   358,   358,   358,
+     359,   360,   361,   359,   362,   362,   364,   363,   365,   363,
+     366,   366,   367,   367,   368,   368,   369,   370,   370,   371,
+     371,   373,   372,   374,   374,   375,   375,   377,   376,   378,
+     376,   379,   376,   380,   380,   381,   381,   382,   382,   383,
+     383,   383,   383,   383,   384,   384,   385,   385,   387,   386
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     3,     1,     4,     1,     3,     2,     2,     1,
+       1,     1,     2,     2,     2,     1,     2,     3,     2,     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,
+       0,     6,     1,     3,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     3,     1,     2,     2,
+       4,     2,     3,     4,     2,     3,     4,     0,     6,     2,
+       3,     2,     1,     1,     2,     3,     3,     2,     3,     2,
+       1,     2,     1,     1,     1,     3,     4,     6,     5,     1,
+       2,     3,     5,     4,     1,     2,     1,     1,     1,     1,
+       1,     4,     1,     3,     1,     3,     1,     1,     1,     2,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     4,     1,     3,     1,     2,     2,
+       3,     3,     4,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     0,     6,     0,     5,     1,     2,     3,
+       4,     1,     3,     1,     2,     1,     3,     4,     1,     3,
+       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,     1,
+       4,     0,     8,     0,     1,     3,     2,     0,     6,     0,
+       8,     0,     7,     1,     1,     1,     0,     2,     3,     2,
+       2,     2,     3,     2,     1,     2,     1,     1,     0,     3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint16 yydefact[] =
+{
+       0,   147,   148,   146,   181,   174,   175,   177,   178,   179,
+     180,   176,   163,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   182,   183,
+     184,   206,   207,   208,   152,   150,   151,   149,   155,   153,
+     154,   156,   157,   158,   159,   160,   161,   162,   185,   186,
+     187,   218,   219,   220,   188,   189,   190,   230,   231,   232,
+     129,   128,   127,     0,   130,   209,   210,   211,   212,   213,
+     214,   215,   216,   217,   221,   222,   223,   224,   225,   226,
+     227,   228,   229,   233,   234,   235,   236,   237,   238,   239,
+     240,   241,   242,   243,   244,   245,   246,   247,   248,   249,
+     250,   251,   252,   253,   256,   257,   258,   259,   260,   261,
+     263,   264,   265,   266,   267,   268,   270,   271,   272,   273,
+     274,   275,   276,   254,   255,   262,   269,   277,   278,   279,
+     280,   281,   282,   351,   283,   284,   285,   286,   287,   288,
+     289,   290,   292,   293,   294,   295,   296,   297,   299,   300,
+     301,   302,   303,   304,   306,   307,   308,   309,   310,   311,
+     291,   298,   305,   312,   313,   314,   315,   316,   317,   352,
+     353,   354,   355,   356,   357,   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,     0,   173,
+     359,   126,   137,   360,   361,   362,     0,   437,     0,   438,
+       0,   103,   102,     0,   114,   119,   144,   143,   141,   145,
+       0,   138,   140,   124,   167,   142,   358,     0,   434,   436,
+       0,     0,     0,   365,     0,     0,    91,    88,     0,   101,
+       0,   110,   104,   112,     0,   113,     0,    89,   120,     0,
+      94,   139,   125,     0,   168,     1,   435,   165,     0,   136,
+     134,     0,   132,   363,     0,     0,    92,     0,     0,   439,
+     105,   109,   111,   107,   115,   106,     0,   121,    97,     0,
+      95,     0,     2,     8,     9,     4,     5,     6,     7,    11,
+      10,     0,     0,     0,   169,    37,    36,    38,    35,     3,
+      13,    31,    15,    20,    21,     0,     0,    25,     0,    39,
+       0,    43,    46,    49,    54,    57,    59,    61,    63,    65,
+      67,    69,     0,    29,     0,   164,     0,     0,   131,     0,
+       0,     0,     0,     0,   367,    90,    93,     0,     0,   419,
+       0,     0,     0,     0,     0,     0,     0,     0,   391,   400,
+     404,    39,    72,    85,     0,   380,     0,   124,   383,   402,
+     382,   381,     0,   384,   385,   386,   387,   388,   389,   108,
+       0,   116,     0,   375,   123,     0,     0,    99,     0,    96,
+      32,    33,     0,    17,    18,     0,     0,    23,    22,     0,
+     173,    26,    28,    34,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    70,   170,   171,     0,   166,    87,   135,
+     133,     0,     0,   373,     0,   371,   366,   368,   430,   429,
+       0,   421,     0,   433,   431,     0,     0,     0,   416,   417,
+     390,     0,    75,    76,    78,    77,    80,    81,    82,    83,
+      84,    79,    74,     0,     0,   405,   401,   403,   118,     0,
+     378,     0,   122,     0,   100,    12,     0,    19,    16,    27,
+      40,    41,    42,    45,    44,    47,    48,    52,    53,    50,
+      51,    55,    56,    58,    60,    62,    64,    66,    68,     0,
+     172,   364,     0,   374,     0,   369,     0,     0,     0,   432,
+       0,   415,     0,   392,    73,    86,   117,   376,     0,    98,
+      14,     0,   370,   372,     0,   424,   423,   426,   398,   411,
+     409,     0,     0,     0,     0,   377,   379,     0,     0,   425,
+       0,     0,   408,     0,     0,   406,     0,     0,     0,   393,
+      71,     0,   427,     0,   398,   397,   399,   413,     0,   395,
+     418,   394,     0,   428,   422,   407,   414,     0,   410,   420,
+     412
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,   309,   310,   311,   476,   312,   313,   314,   315,   316,
+     317,   318,   361,   320,   321,   322,   323,   324,   325,   326,
+     327,   328,   329,   330,   331,   362,   499,   363,   463,   364,
+     429,   365,   218,   386,   291,   366,   220,   221,   222,   251,
+     252,   253,   223,   224,   225,   226,   227,   228,   271,   272,
+     229,   230,   231,   232,   268,   333,   264,   234,   235,   236,
+     340,   274,   343,   344,   434,   435,   384,   471,   368,   369,
+     370,   371,   451,   534,   560,   542,   543,   544,   561,   372,
+     373,   374,   545,   533,   375,   546,   567,   376,   377,   512,
+     440,   507,   527,   540,   541,   378,   237,   238,   239,   248
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -512
+static const yytype_int16 yypact[] =
+{
+    2538,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -235,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -201,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -203,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -153,  -512,  -210,  -220,
+    -152,  -189,  4119,  -160,  -512,  -128,  -512,  -512,  -512,  -512,
+    3079,  -512,  -512,  -512,  -122,  -512,  -512,   564,  -512,  -512,
+     -72,   -46,  -105,  -512,  6148,  -216,  -512,  -512,  -102,  -512,
+    4119,  -512,  -512,  -512,  4119,   -68,   -66,  -512,  -225,  -187,
+    -512,  -512,  -512,  4606,   -98,  -512,  -512,  -512,  -179,  -512,
+    -104,  -172,  -512,  -512,  4119,  -101,  -512,  -186,   846,  -512,
+    -512,  -512,  -512,  -122,  -233,  -512,  4870,  -217,  -512,   -63,
+    -512,  -151,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  5648,  5648,  5648,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -209,  -512,  -512,  -512,   -94,  -170,  5898,   -92,  -512,
+    5648,  -139,  -133,  -109,  -223,  -103,  -111,  -108,  -106,   -71,
+     -74,  -218,   -86,  -512,  5134,  -512,   -52,  5648,  -512,   -46,
+    4119,  4119,   -50,  3342,  -512,  -512,  -512,   -90,   -89,  -512,
+     -78,   -76,   -85,  5398,   -70,  5648,   -80,   -69,   -64,  -512,
+    -512,  -184,  -512,  -512,  -150,  -512,  -220,   -67,  -512,  -512,
+    -512,  -512,  1128,  -512,  -512,  -512,  -512,  -512,  -512,   -98,
+    4870,  -183,  4870,  -512,  -512,  4870,  4119,  -512,   -40,  -512,
+    -512,  -512,  -169,  -512,  -512,  5648,   -35,  -512,  -512,  5648,
+     -65,  -512,  -512,  -512,  5648,  5648,  5648,  5648,  5648,  5648,
+    5648,  5648,  5648,  5648,  5648,  5648,  5648,  5648,  5648,  5648,
+    5648,  5648,  5648,  -512,  -512,  -512,   -61,  -512,  -512,  -512,
+    -512,  3601,   -50,  -122,  -144,  -512,  -512,  -512,  -512,  -512,
+    1410,  -512,  5648,  -512,  -512,  -142,  5648,  -123,  -512,  -512,
+    -512,  1410,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  5648,  5648,  -512,  -512,  -512,  -512,  4870,
+    -512,  -226,  -512,  3860,  -512,  -512,   -60,   -62,  -512,  -512,
+    -512,  -512,  -512,  -139,  -139,  -133,  -133,  -109,  -109,  -109,
+    -109,  -223,  -223,  -103,  -111,  -108,  -106,   -71,   -74,  5648,
+    -512,  -512,  -138,   -98,   -50,  -512,   -33,  2256,  -168,  -512,
+    -167,  -512,  2798,  1410,  -512,  -512,  -512,  -512,  4342,  -512,
+    -512,  -121,  -512,  -512,   -56,  -512,  -512,  2798,   -58,  -512,
+     -62,   -32,  4119,   -49,   -51,  -512,  -512,  5648,  5648,  -512,
+     -57,   -45,   177,   -55,  1974,  -512,   -47,   -44,  1692,  -512,
+    -512,  -165,  5648,  1692,   -58,  -512,  -512,  1410,  4870,  -512,
+    -512,  -512,   -48,   -62,  -512,  -512,  1410,   -42,  -512,  -512,
+    -512
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,   -96,  -512,  -263,  -262,  -304,  -264,  -204,  -199,
+    -205,  -197,  -206,  -196,  -512,  -252,  -512,  -282,  -512,  -296,
+    -512,     3,  -512,  -512,  -512,     6,  -512,  -512,  -512,   -29,
+     -23,   -26,  -512,  -512,  -489,  -512,  -512,  -512,  -512,  -118,
+    -512,  -221,  -228,  -512,  -512,     0,  -240,  -512,    13,  -512,
+    -512,  -512,  -328,  -330,  -200,  -271,  -363,  -512,  -273,  -364,
+    -511,  -308,  -512,  -512,  -314,  -309,  -512,  -512,    -2,  -441,
+    -260,  -512,  -512,  -279,  -512,  -512,  -512,  -512,  -512,  -512,
+    -512,  -512,  -512,  -512,  -512,  -512,  -512,    12,  -512,  -512
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -397
+static const yytype_int16 yytable[] =
+{
+     233,   254,   261,   217,   383,   277,   219,   392,   467,   269,
+     513,   332,   431,   437,   245,   411,   412,   468,   287,   470,
+     240,   242,   472,   531,   263,   422,   261,   393,   394,   254,
+     285,   380,   263,   556,   517,   401,   518,   559,   531,   286,
+     334,   263,   559,   379,   381,   247,   -30,   385,   395,   276,
+     413,   414,   396,   341,   241,   246,   243,   445,   473,   447,
+     423,   452,   453,   454,   455,   456,   457,   458,   459,   460,
+     461,   334,   288,   250,   334,   289,   506,   335,   290,   346,
+     462,   469,   426,   336,   338,   428,   398,   475,   528,   529,
+     339,   562,   399,   464,   464,   464,   258,   464,   383,   477,
+     383,   437,   256,   383,   249,   257,   516,   487,   488,   489,
+     490,   388,   464,   261,   389,   465,   566,   479,   504,   341,
+     464,   505,   341,   509,   504,   409,   410,   522,   213,   214,
+     215,   404,   405,   406,   407,   263,   408,   415,   416,   464,
+     511,   464,   537,   437,   483,   484,   508,   485,   486,   467,
+     510,   491,   492,   267,   273,   536,   283,   278,   284,   334,
+     337,   387,   397,   402,   345,   341,   417,   319,   418,   419,
+     421,   420,   424,   427,   433,   438,   439,   441,   270,   442,
+     443,   514,   515,   448,   474,   446,   449,   383,   -29,   478,
+     524,   -24,   547,   503,   554,   568,   450,   500,   520,   538,
+     464,  -396,   467,   521,   358,   390,   391,   548,   552,   549,
+     341,   553,   557,   493,   495,   497,   530,   569,   570,   494,
+     558,   430,   255,   496,   403,   281,   498,   280,   282,   244,
+     262,   530,   502,   523,   525,   555,   383,   233,   319,   564,
+     217,   319,   551,   219,   275,   565,   279,   526,   539,   266,
+     255,     0,   341,     0,   255,   550,   563,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   342,     0,   383,     0,   367,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   532,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   261,     0,   532,     0,   480,   481,
+     482,   319,   319,   319,   319,   319,   319,   319,   319,   319,
+     319,   319,   319,   319,   319,   319,   319,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     342,   432,     0,   342,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   367,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   342,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   342,     0,     0,     0,     0,     0,     0,     0,     0,
+     367,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   367,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   342,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   367,     0,     0,
+       0,     0,   367,   367,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   367,     0,     0,
+       0,     0,   262,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   367,     0,     0,     0,   367,     0,
+       0,     0,     0,   367,     0,     0,     0,   367,     0,     0,
+       0,     0,     0,     0,   265,     0,   367,     1,     2,     3,
+       4,     5,     6,     7,     8,     9,    10,    11,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    40,    41,    42,
+      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    97,    98,    99,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   130,   131,   132,
+     133,   134,   135,   136,   137,   138,   139,   140,   141,   142,
+     143,   144,   145,   146,   147,   148,   149,   150,   151,   152,
+     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   172,
+     173,   174,   175,   176,   177,   178,   179,   180,   181,   182,
+     183,   184,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   199,   200,   201,   202,
+     203,   204,   205,   206,   207,   208,   209,     0,     0,   210,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   211,   212,   213,   214,   215,   216,     1,
+       2,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+     347,   348,   349,     0,   350,   351,   352,   353,   354,   355,
+     356,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+      61,    62,    63,    64,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   144,   145,   146,   147,   148,   149,   150,
+     151,   152,   153,   154,   155,   156,   157,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   199,   200,
+     201,   202,   203,   204,   205,   206,   207,   208,   209,   357,
+     292,   210,   293,   294,   295,   296,   297,   298,   299,   300,
+       0,     0,   301,   302,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   303,     0,     0,     0,   358,   359,     0,     0,     0,
+       0,   360,   305,   306,   307,   308,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   211,   212,   213,   214,   215,
+     216,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,   347,   348,   349,     0,   350,   351,   352,   353,
+     354,   355,   356,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,   357,   292,   210,   293,   294,   295,   296,   297,   298,
+     299,   300,     0,     0,   301,   302,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   303,     0,     0,     0,   358,   466,     0,
+       0,     0,     0,   360,   305,   306,   307,   308,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   211,   212,   213,
+     214,   215,   216,     1,     2,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,   347,   348,   349,     0,   350,   351,
+     352,   353,   354,   355,   356,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,    74,    75,    76,
+      77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+      87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   104,   105,   106,
+     107,   108,   109,   110,   111,   112,   113,   114,   115,   116,
+     117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
+     127,   128,   129,   130,   131,   132,   133,   134,   135,   136,
+     137,   138,   139,   140,   141,   142,   143,   144,   145,   146,
+     147,   148,   149,   150,   151,   152,   153,   154,   155,   156,
+     157,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,   172,   173,   174,   175,   176,
+     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
+     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,   199,   200,   201,   202,   203,   204,   205,   206,
+     207,   208,   209,   357,   292,   210,   293,   294,   295,   296,
+     297,   298,   299,   300,     0,     0,   301,   302,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   303,     0,     0,     0,   358,
+       0,     0,     0,     0,     0,   360,   305,   306,   307,   308,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   211,
+     212,   213,   214,   215,   216,     1,     2,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,   347,   348,   349,     0,
+     350,   351,   352,   353,   354,   355,   356,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
+     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+     145,   146,   147,   148,   149,   150,   151,   152,   153,   154,
+     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   172,   173,   174,
+     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
+     205,   206,   207,   208,   209,   357,   292,   210,   293,   294,
+     295,   296,   297,   298,   299,   300,     0,     0,   301,   302,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   303,     0,     0,
+       0,   278,     0,     0,     0,     0,     0,   360,   305,   306,
+     307,   308,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   211,   212,   213,   214,   215,   216,     1,     2,     3,
+       4,     5,     6,     7,     8,     9,    10,    11,   347,   348,
+     349,     0,   350,   351,   352,   353,   354,   355,   356,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    40,    41,    42,
+      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    97,    98,    99,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   130,   131,   132,
+     133,   134,   135,   136,   137,   138,   139,   140,   141,   142,
+     143,   144,   145,   146,   147,   148,   149,   150,   151,   152,
+     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   172,
+     173,   174,   175,   176,   177,   178,   179,   180,   181,   182,
+     183,   184,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   199,   200,   201,   202,
+     203,   204,   205,   206,   207,   208,   209,   357,   292,   210,
+     293,   294,   295,   296,   297,   298,   299,   300,     0,     0,
+     301,   302,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   303,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   360,
+     305,   306,   307,   308,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   211,   212,   213,   214,   215,   216,     1,
+       2,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+      61,    62,    63,    64,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   144,   145,   146,   147,   148,   149,   150,
+     151,   152,   153,   154,   155,   156,   157,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   199,   200,
+     201,   202,   203,   204,   205,   206,   207,   208,   209,     0,
+     292,   210,   293,   294,   295,   296,   297,   298,   299,   300,
+       0,     0,   301,   302,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   303,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   360,   305,   306,   307,   308,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   211,   212,   213,   214,   215,
+     216,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,     0,     0,   210,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     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,     2,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,   211,   212,   213,
+     214,   215,   216,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,     0,   292,   210,   293,   294,   295,   296,   297,   298,
+     299,   300,     0,     0,   301,   302,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   303,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   305,   306,   307,   308,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   211,   212,   213,
+     214,   215,     1,     2,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    12,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    73,    74,    75,    76,    77,
+      78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   209,     0,   259,   210,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   260,     1,     2,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,     0,     0,   211,   212,
+     213,   214,   215,     0,     0,     0,     0,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
+     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+     145,   146,   147,   148,   149,   150,   151,   152,   153,   154,
+     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   172,   173,   174,
+     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
+     205,   206,   207,   208,   209,     0,     0,   210,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   436,     0,     1,     2,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,     0,     0,     0,     0,     0,
+       0,   211,   212,   213,   214,   215,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    73,    74,    75,
+      76,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+      86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
+      96,    97,    98,    99,   100,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,   111,   112,   113,   114,   115,
+     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,
+     126,   127,   128,   129,   130,   131,   132,   133,   134,   135,
+     136,   137,   138,   139,   140,   141,   142,   143,   144,   145,
+     146,   147,   148,   149,   150,   151,   152,   153,   154,   155,
+     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
+     196,   197,   198,   199,   200,   201,   202,   203,   204,   205,
+     206,   207,   208,   209,     0,     0,   210,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   501,     0,     1,     2,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,     0,     0,     0,     0,     0,     0,
+     211,   212,   213,   214,   215,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,    74,    75,    76,
+      77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+      87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   104,   105,   106,
+     107,   108,   109,   110,   111,   112,   113,   114,   115,   116,
+     117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
+     127,   128,   129,   130,   131,   132,   133,   134,   135,   136,
+     137,   138,   139,   140,   141,   142,   143,   144,   145,   146,
+     147,   148,   149,   150,   151,   152,   153,   154,   155,   156,
+     157,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,   172,   173,   174,   175,   176,
+     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
+     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,   199,   200,   201,   202,   203,   204,   205,   206,
+     207,   208,   209,     0,     0,   210,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     519,     0,     1,     2,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,     0,     0,     0,     0,     0,     0,   211,
+     212,   213,   214,   215,    12,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    73,    74,    75,    76,    77,
+      78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   209,     0,     0,   210,     0,     0,     0,     4,     5,
+       6,     7,     8,     9,    10,    11,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   211,   212,
+     213,   214,   215,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,     0,     0,     0,     0,     0,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
+     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+     145,   146,   147,   148,   149,   150,   151,   152,   153,   154,
+     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   172,   173,   174,
+     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
+     205,   206,   207,   208,   209,     0,   292,   210,   293,   294,
+     295,   296,   297,   298,   299,   300,     0,     0,   301,   302,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   303,     0,     0,
+       0,   382,   535,     0,     0,     0,     0,     0,   305,   306,
+     307,   308,     4,     5,     6,     7,     8,     9,    10,    11,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,     0,
+       0,     0,     0,     0,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   144,   145,   146,   147,   148,   149,   150,
+     151,   152,   153,   154,   155,   156,   157,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   199,   200,
+     201,   202,   203,   204,   205,   206,   207,   208,   209,     0,
+     292,   210,   293,   294,   295,   296,   297,   298,   299,   300,
+       0,     0,   301,   302,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   303,     0,     0,   304,     0,     0,     0,     0,     0,
+       0,     0,   305,   306,   307,   308,     4,     5,     6,     7,
+       8,     9,    10,    11,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+      57,    58,    59,     0,     0,     0,     0,     0,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,    74,    75,    76,
+      77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+      87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   104,   105,   106,
+     107,   108,   109,   110,   111,   112,   113,   114,   115,   116,
+     117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
+     127,   128,   129,   130,   131,   132,   133,   134,   135,   136,
+     137,   138,   139,   140,   141,   142,   143,   144,   145,   146,
+     147,   148,   149,   150,   151,   152,   153,   154,   155,   156,
+     157,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,   172,   173,   174,   175,   176,
+     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
+     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,   199,   200,   201,   202,   203,   204,   205,   206,
+     207,   208,   209,     0,   292,   210,   293,   294,   295,   296,
+     297,   298,   299,   300,     0,     0,   301,   302,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   303,     0,     0,     0,   382,
+       0,     0,     0,     0,     0,     0,   305,   306,   307,   308,
+       4,     5,     6,     7,     8,     9,    10,    11,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,    48,    49,    50,    51,    52,
+      53,    54,    55,    56,    57,    58,    59,     0,     0,     0,
+       0,     0,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    97,    98,    99,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   130,   131,   132,
+     133,   134,   135,   136,   137,   138,   139,   140,   141,   142,
+     143,   144,   145,   146,   147,   148,   149,   150,   151,   152,
+     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   172,
+     173,   174,   175,   176,   177,   178,   179,   180,   181,   182,
+     183,   184,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   199,   200,   201,   202,
+     203,   204,   205,   206,   207,   208,   209,     0,   292,   210,
+     293,   294,   295,   296,   297,   298,   299,   300,     0,     0,
+     301,   302,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   303,
+       0,     0,   425,     0,     0,     0,     0,     0,     0,     0,
+     305,   306,   307,   308,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,     0,     0,     0,     0,     0,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,     0,   292,   210,   293,   294,   295,   296,   297,   298,
+     299,   300,     0,     0,   301,   302,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   303,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,   444,   305,   306,   307,   308,     0,     0,
+       0,     0,     0,     0,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,     0,     0,     0,     0,     0,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,     0,   292,   210,   293,   294,   295,   296,   297,   298,
+     299,   300,     0,     0,   301,   302,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   303,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,   305,   306,   307,   308,     0,     0,
+       0,     0,     0,     0,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,     0,     0,     0,     0,     0,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     400,     0,   292,   210,   293,   294,   295,   296,   297,   298,
+     299,   300,     0,     0,   301,   302,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   303,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,   305,   306,   307,   308,     0,     0,
+       0,     0,     0,     0,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,     0,     0,     0,     0,     0,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,     0,     0,   210
+};
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-512)))
+
+#define yytable_value_is_error(Yytable_value) \
+  YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+       0,   222,   230,     0,   286,   245,     0,   303,   372,    55,
+     451,   263,   340,   343,   224,   238,   239,   380,   258,   382,
+     255,   224,   385,   512,   257,   243,   254,   236,   237,   250,
+     255,   264,   257,   544,   260,   317,   262,   548,   527,   264,
+     257,   257,   553,   283,   284,   265,   255,   264,   257,   265,
+     273,   274,   261,   274,   255,   265,   259,   353,   386,   355,
+     278,   245,   246,   247,   248,   249,   250,   251,   252,   253,
+     254,   257,   259,   262,   257,   262,   440,   256,   265,   265,
+     264,   264,   334,   262,   256,   337,   256,   256,   256,   256,
+     262,   256,   262,   262,   262,   262,   224,   262,   380,   395,
+     382,   431,   262,   385,   256,   265,   469,   411,   412,   413,
+     414,   262,   262,   341,   265,   265,   557,   399,   262,   340,
+     262,   265,   343,   265,   262,   234,   235,   265,   281,   282,
+     283,   270,   271,   272,   267,   257,   269,   240,   241,   262,
+     263,   262,   263,   473,   407,   408,   442,   409,   410,   513,
+     446,   415,   416,   225,   259,   518,   224,   259,   224,   257,
+     264,   224,   256,   255,   265,   386,   277,   263,   276,   275,
+     244,   242,   258,   225,   224,   265,   265,   255,   224,   255,
+     265,   463,   464,   263,   224,   255,   255,   469,   255,   224,
+     223,   256,   224,   433,    17,   558,   260,   258,   258,   255,
+     262,   259,   566,   499,   259,   301,   302,   256,   265,   260,
+     431,   256,   259,   417,   419,   421,   512,   265,   260,   418,
+     264,   339,   222,   420,   320,   254,   422,   250,   254,   216,
+     230,   527,   432,   504,   507,   543,   518,   237,   334,   553,
+     237,   337,   538,   237,   244,   554,   248,   507,   527,   237,
+     250,    -1,   473,    -1,   254,   537,   552,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   274,    -1,   558,    -1,   278,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   512,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   532,    -1,   527,    -1,   404,   405,
+     406,   407,   408,   409,   410,   411,   412,   413,   414,   415,
+     416,   417,   418,   419,   420,   421,   422,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     340,   341,    -1,   343,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   372,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   386,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   431,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     440,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   451,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   473,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   507,    -1,    -1,
+      -1,    -1,   512,   513,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   527,    -1,    -1,
+      -1,    -1,   532,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   544,    -1,    -1,    -1,   548,    -1,
+      -1,    -1,    -1,   553,    -1,    -1,    -1,   557,    -1,    -1,
+      -1,    -1,    -1,    -1,     0,    -1,   566,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    73,    74,    75,
+      76,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+      86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
+      96,    97,    98,    99,   100,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,   111,   112,   113,   114,   115,
+     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,
+     126,   127,   128,   129,   130,   131,   132,   133,   134,   135,
+     136,   137,   138,   139,   140,   141,   142,   143,   144,   145,
+     146,   147,   148,   149,   150,   151,   152,   153,   154,   155,
+     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
+     196,   197,   198,   199,   200,   201,   202,   203,   204,   205,
+     206,   207,   208,   209,   210,   211,   212,   213,   214,   215,
+     216,   217,   218,   219,   220,   221,   222,    -1,    -1,   225,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   279,   280,   281,   282,   283,   284,     3,
+       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    15,    16,    -1,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,    38,    39,    40,    41,    42,    43,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      54,    55,    56,    57,    58,    59,    60,    61,    62,    63,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    73,
+      74,    75,    76,    77,    78,    79,    80,    81,    82,    83,
+      84,    85,    86,    87,    88,    89,    90,    91,    92,    93,
+      94,    95,    96,    97,    98,    99,   100,   101,   102,   103,
+     104,   105,   106,   107,   108,   109,   110,   111,   112,   113,
+     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
+     124,   125,   126,   127,   128,   129,   130,   131,   132,   133,
+     134,   135,   136,   137,   138,   139,   140,   141,   142,   143,
+     144,   145,   146,   147,   148,   149,   150,   151,   152,   153,
+     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   172,   173,
+     174,   175,   176,   177,   178,   179,   180,   181,   182,   183,
+     184,   185,   186,   187,   188,   189,   190,   191,   192,   193,
+     194,   195,   196,   197,   198,   199,   200,   201,   202,   203,
+     204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
+     214,   215,   216,   217,   218,   219,   220,   221,   222,   223,
+     224,   225,   226,   227,   228,   229,   230,   231,   232,   233,
+      -1,    -1,   236,   237,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   255,    -1,    -1,    -1,   259,   260,    -1,    -1,    -1,
+      -1,   265,   266,   267,   268,   269,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   279,   280,   281,   282,   283,
+     284,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    14,    15,    16,    -1,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,   223,   224,   225,   226,   227,   228,   229,   230,   231,
+     232,   233,    -1,    -1,   236,   237,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   255,    -1,    -1,    -1,   259,   260,    -1,
+      -1,    -1,    -1,   265,   266,   267,   268,   269,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   279,   280,   281,
+     282,   283,   284,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,    13,    14,    15,    16,    -1,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
+      80,    81,    82,    83,    84,    85,    86,    87,    88,    89,
+      90,    91,    92,    93,    94,    95,    96,    97,    98,    99,
+     100,   101,   102,   103,   104,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+     130,   131,   132,   133,   134,   135,   136,   137,   138,   139,
+     140,   141,   142,   143,   144,   145,   146,   147,   148,   149,
+     150,   151,   152,   153,   154,   155,   156,   157,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,   172,   173,   174,   175,   176,   177,   178,   179,
+     180,   181,   182,   183,   184,   185,   186,   187,   188,   189,
+     190,   191,   192,   193,   194,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   205,   206,   207,   208,   209,
+     210,   211,   212,   213,   214,   215,   216,   217,   218,   219,
+     220,   221,   222,   223,   224,   225,   226,   227,   228,   229,
+     230,   231,   232,   233,    -1,    -1,   236,   237,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   255,    -1,    -1,    -1,   259,
+      -1,    -1,    -1,    -1,    -1,   265,   266,   267,   268,   269,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   279,
+     280,   281,   282,   283,   284,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    13,    14,    15,    16,    -1,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    73,    74,    75,    76,    77,
+      78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   209,   210,   211,   212,   213,   214,   215,   216,   217,
+     218,   219,   220,   221,   222,   223,   224,   225,   226,   227,
+     228,   229,   230,   231,   232,   233,    -1,    -1,   236,   237,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   255,    -1,    -1,
+      -1,   259,    -1,    -1,    -1,    -1,    -1,   265,   266,   267,
+     268,   269,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   279,   280,   281,   282,   283,   284,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    -1,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    73,    74,    75,
+      76,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+      86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
+      96,    97,    98,    99,   100,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,   111,   112,   113,   114,   115,
+     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,
+     126,   127,   128,   129,   130,   131,   132,   133,   134,   135,
+     136,   137,   138,   139,   140,   141,   142,   143,   144,   145,
+     146,   147,   148,   149,   150,   151,   152,   153,   154,   155,
+     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
+     196,   197,   198,   199,   200,   201,   202,   203,   204,   205,
+     206,   207,   208,   209,   210,   211,   212,   213,   214,   215,
+     216,   217,   218,   219,   220,   221,   222,   223,   224,   225,
+     226,   227,   228,   229,   230,   231,   232,   233,    -1,    -1,
+     236,   237,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   255,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   265,
+     266,   267,   268,   269,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   279,   280,   281,   282,   283,   284,     3,
+       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,    38,    39,    40,    41,    42,    43,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      54,    55,    56,    57,    58,    59,    60,    61,    62,    63,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    73,
+      74,    75,    76,    77,    78,    79,    80,    81,    82,    83,
+      84,    85,    86,    87,    88,    89,    90,    91,    92,    93,
+      94,    95,    96,    97,    98,    99,   100,   101,   102,   103,
+     104,   105,   106,   107,   108,   109,   110,   111,   112,   113,
+     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
+     124,   125,   126,   127,   128,   129,   130,   131,   132,   133,
+     134,   135,   136,   137,   138,   139,   140,   141,   142,   143,
+     144,   145,   146,   147,   148,   149,   150,   151,   152,   153,
+     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   172,   173,
+     174,   175,   176,   177,   178,   179,   180,   181,   182,   183,
+     184,   185,   186,   187,   188,   189,   190,   191,   192,   193,
+     194,   195,   196,   197,   198,   199,   200,   201,   202,   203,
+     204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
+     214,   215,   216,   217,   218,   219,   220,   221,   222,    -1,
+     224,   225,   226,   227,   228,   229,   230,   231,   232,   233,
+      -1,    -1,   236,   237,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   255,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   265,   266,   267,   268,   269,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   279,   280,   281,   282,   283,
+     284,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,    -1,   225,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -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,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,    -1,    -1,    -1,    -1,   279,   280,   281,
+     282,   283,   284,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,   224,   225,   226,   227,   228,   229,   230,   231,
+     232,   233,    -1,    -1,   236,   237,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   255,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   266,   267,   268,   269,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   279,   280,   281,
+     282,   283,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+      61,    62,    63,    64,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   144,   145,   146,   147,   148,   149,   150,
+     151,   152,   153,   154,   155,   156,   157,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   199,   200,
+     201,   202,   203,   204,   205,   206,   207,   208,   209,   210,
+     211,   212,   213,   214,   215,   216,   217,   218,   219,   220,
+     221,   222,    -1,   224,   225,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   265,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    13,    -1,    -1,   279,   280,
+     281,   282,   283,    -1,    -1,    -1,    -1,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    73,    74,    75,    76,    77,
+      78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   209,   210,   211,   212,   213,   214,   215,   216,   217,
+     218,   219,   220,   221,   222,    -1,    -1,   225,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   260,    -1,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,
+      -1,   279,   280,   281,   282,   283,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   130,   131,   132,   133,   134,   135,   136,   137,   138,
+     139,   140,   141,   142,   143,   144,   145,   146,   147,   148,
+     149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
+     209,   210,   211,   212,   213,   214,   215,   216,   217,   218,
+     219,   220,   221,   222,    -1,    -1,   225,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   260,    -1,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,
+     279,   280,   281,   282,   283,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
+      80,    81,    82,    83,    84,    85,    86,    87,    88,    89,
+      90,    91,    92,    93,    94,    95,    96,    97,    98,    99,
+     100,   101,   102,   103,   104,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+     130,   131,   132,   133,   134,   135,   136,   137,   138,   139,
+     140,   141,   142,   143,   144,   145,   146,   147,   148,   149,
+     150,   151,   152,   153,   154,   155,   156,   157,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,   172,   173,   174,   175,   176,   177,   178,   179,
+     180,   181,   182,   183,   184,   185,   186,   187,   188,   189,
+     190,   191,   192,   193,   194,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   205,   206,   207,   208,   209,
+     210,   211,   212,   213,   214,   215,   216,   217,   218,   219,
+     220,   221,   222,    -1,    -1,   225,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     260,    -1,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,   279,
+     280,   281,   282,   283,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+      61,    62,    63,    64,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   144,   145,   146,   147,   148,   149,   150,
+     151,   152,   153,   154,   155,   156,   157,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   199,   200,
+     201,   202,   203,   204,   205,   206,   207,   208,   209,   210,
+     211,   212,   213,   214,   215,   216,   217,   218,   219,   220,
+     221,   222,    -1,    -1,   225,    -1,    -1,    -1,     6,     7,
+       8,     9,    10,    11,    12,    13,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   279,   280,
+     281,   282,   283,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    -1,    -1,    -1,    -1,    -1,
+      78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   209,   210,   211,   212,   213,   214,   215,   216,   217,
+     218,   219,   220,   221,   222,    -1,   224,   225,   226,   227,
+     228,   229,   230,   231,   232,   233,    -1,    -1,   236,   237,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   255,    -1,    -1,
+      -1,   259,   260,    -1,    -1,    -1,    -1,    -1,   266,   267,
+     268,   269,     6,     7,     8,     9,    10,    11,    12,    13,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,    38,    39,    40,    41,    42,    43,
+      44,    45,    46,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    61,    62,    63,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    -1,
+      -1,    -1,    -1,    -1,    78,    79,    80,    81,    82,    83,
+      84,    85,    86,    87,    88,    89,    90,    91,    92,    93,
+      94,    95,    96,    97,    98,    99,   100,   101,   102,   103,
+     104,   105,   106,   107,   108,   109,   110,   111,   112,   113,
+     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
+     124,   125,   126,   127,   128,   129,   130,   131,   132,   133,
+     134,   135,   136,   137,   138,   139,   140,   141,   142,   143,
+     144,   145,   146,   147,   148,   149,   150,   151,   152,   153,
+     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   172,   173,
+     174,   175,   176,   177,   178,   179,   180,   181,   182,   183,
+     184,   185,   186,   187,   188,   189,   190,   191,   192,   193,
+     194,   195,   196,   197,   198,   199,   200,   201,   202,   203,
+     204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
+     214,   215,   216,   217,   218,   219,   220,   221,   222,    -1,
+     224,   225,   226,   227,   228,   229,   230,   231,   232,   233,
+      -1,    -1,   236,   237,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   255,    -1,    -1,   258,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   266,   267,   268,   269,     6,     7,     8,     9,
+      10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+      40,    41,    42,    43,    44,    45,    46,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    -1,    -1,    -1,    -1,    -1,    78,    79,
+      80,    81,    82,    83,    84,    85,    86,    87,    88,    89,
+      90,    91,    92,    93,    94,    95,    96,    97,    98,    99,
+     100,   101,   102,   103,   104,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+     130,   131,   132,   133,   134,   135,   136,   137,   138,   139,
+     140,   141,   142,   143,   144,   145,   146,   147,   148,   149,
+     150,   151,   152,   153,   154,   155,   156,   157,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,   172,   173,   174,   175,   176,   177,   178,   179,
+     180,   181,   182,   183,   184,   185,   186,   187,   188,   189,
+     190,   191,   192,   193,   194,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   205,   206,   207,   208,   209,
+     210,   211,   212,   213,   214,   215,   216,   217,   218,   219,
+     220,   221,   222,    -1,   224,   225,   226,   227,   228,   229,
+     230,   231,   232,   233,    -1,    -1,   236,   237,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   255,    -1,    -1,    -1,   259,
+      -1,    -1,    -1,    -1,    -1,    -1,   266,   267,   268,   269,
+       6,     7,     8,     9,    10,    11,    12,    13,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    -1,    -1,    -1,
+      -1,    -1,    78,    79,    80,    81,    82,    83,    84,    85,
+      86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
+      96,    97,    98,    99,   100,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,   111,   112,   113,   114,   115,
+     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,
+     126,   127,   128,   129,   130,   131,   132,   133,   134,   135,
+     136,   137,   138,   139,   140,   141,   142,   143,   144,   145,
+     146,   147,   148,   149,   150,   151,   152,   153,   154,   155,
+     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
+     196,   197,   198,   199,   200,   201,   202,   203,   204,   205,
+     206,   207,   208,   209,   210,   211,   212,   213,   214,   215,
+     216,   217,   218,   219,   220,   221,   222,    -1,   224,   225,
+     226,   227,   228,   229,   230,   231,   232,   233,    -1,    -1,
+     236,   237,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   255,
+      -1,    -1,   258,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     266,   267,   268,   269,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    -1,    -1,    -1,    -1,    -1,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,   224,   225,   226,   227,   228,   229,   230,   231,
+     232,   233,    -1,    -1,   236,   237,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   255,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,   265,   266,   267,   268,   269,    -1,    -1,
+      -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    -1,    -1,    -1,    -1,    -1,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,   224,   225,   226,   227,   228,   229,   230,   231,
+     232,   233,    -1,    -1,   236,   237,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   255,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,    -1,   266,   267,   268,   269,    -1,    -1,
+      -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    -1,    -1,    -1,    -1,    -1,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,   224,   225,   226,   227,   228,   229,   230,   231,
+     232,   233,    -1,    -1,   236,   237,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   255,     6,     7,     8,     9,    10,    11,
+      12,    13,    -1,    -1,   266,   267,   268,   269,    -1,    -1,
+      -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    -1,    -1,    -1,    -1,    -1,    78,    79,    80,    81,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,   144,   145,   146,   147,   148,   149,   150,   151,
+     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,   199,   200,   201,
+     202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   218,   219,   220,   221,
+     222,    -1,    -1,   225
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint16 yystos[] =
+{
+       0,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    40,    41,    42,
+      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    97,    98,    99,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   130,   131,   132,
+     133,   134,   135,   136,   137,   138,   139,   140,   141,   142,
+     143,   144,   145,   146,   147,   148,   149,   150,   151,   152,
+     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   172,
+     173,   174,   175,   176,   177,   178,   179,   180,   181,   182,
+     183,   184,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   199,   200,   201,   202,
+     203,   204,   205,   206,   207,   208,   209,   210,   211,   212,
+     213,   214,   215,   216,   217,   218,   219,   220,   221,   222,
+     225,   279,   280,   281,   282,   283,   284,   319,   320,   323,
+     324,   325,   326,   330,   331,   332,   333,   334,   335,   338,
+     339,   340,   341,   343,   345,   346,   347,   384,   385,   386,
+     255,   255,   224,   259,   346,   224,   265,   265,   387,   256,
+     262,   327,   328,   329,   339,   343,   262,   265,   224,   224,
+     265,   340,   343,   257,   344,     0,   385,   225,   342,    55,
+     224,   336,   337,   259,   349,   343,   265,   344,   259,   366,
+     328,   327,   329,   224,   224,   255,   264,   344,   259,   262,
+     265,   322,   224,   226,   227,   228,   229,   230,   231,   232,
+     233,   236,   237,   255,   258,   266,   267,   268,   269,   289,
+     290,   291,   293,   294,   295,   296,   297,   298,   299,   300,
+     301,   302,   303,   304,   305,   306,   307,   308,   309,   310,
+     311,   312,   313,   343,   257,   256,   262,   264,   256,   262,
+     348,   339,   343,   350,   351,   265,   265,    14,    15,    16,
+      18,    19,    20,    21,    22,    23,    24,   223,   259,   260,
+     265,   300,   313,   315,   317,   319,   323,   343,   356,   357,
+     358,   359,   367,   368,   369,   372,   375,   376,   383,   344,
+     264,   344,   259,   315,   354,   264,   321,   224,   262,   265,
+     300,   300,   317,   236,   237,   257,   261,   256,   256,   262,
+     222,   315,   255,   300,   270,   271,   272,   267,   269,   234,
+     235,   238,   239,   273,   274,   240,   241,   277,   276,   275,
+     242,   244,   243,   278,   258,   258,   313,   225,   313,   318,
+     337,   350,   343,   224,   352,   353,   260,   351,   265,   265,
+     378,   255,   255,   265,   265,   317,   255,   317,   263,   255,
+     260,   360,   245,   246,   247,   248,   249,   250,   251,   252,
+     253,   254,   264,   316,   262,   265,   260,   357,   354,   264,
+     354,   355,   354,   350,   224,   256,   292,   317,   224,   315,
+     300,   300,   300,   302,   302,   303,   303,   304,   304,   304,
+     304,   305,   305,   306,   307,   308,   309,   310,   311,   314,
+     258,   260,   352,   344,   262,   265,   357,   379,   317,   265,
+     317,   263,   377,   367,   315,   315,   354,   260,   262,   260,
+     258,   317,   265,   353,   223,   356,   368,   380,   256,   256,
+     317,   332,   339,   371,   361,   260,   354,   263,   255,   371,
+     381,   382,   363,   364,   365,   370,   373,   224,   256,   260,
+     315,   317,   265,   256,    17,   359,   358,   259,   264,   358,
+     362,   366,   256,   317,   362,   363,   367,   374,   354,   265,
+     260
+};
+
+#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
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
+      yyerror (pParseContext, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, parseContext)
+#endif
+
+/* 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 (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, pParseContext); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, pParseContext)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    glslang::TParseContext* pParseContext;
+#endif
+{
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
+  if (!yyvaluep)
+    return;
+  YYUSE (pParseContext);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, pParseContext)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    glslang::TParseContext* pParseContext;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, pParseContext);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  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 (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, glslang::TParseContext* pParseContext)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, pParseContext)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    glslang::TParseContext* pParseContext;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  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, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , pParseContext);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, pParseContext); \
+} while (YYID (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.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  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.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  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_NULL, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULL;
+  /* 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:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - 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_NULL, 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.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, glslang::TParseContext* pParseContext)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, pParseContext)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    glslang::TParseContext* pParseContext;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (pParseContext);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (glslang::TParseContext* pParseContext)
+#else
+int
+yyparse (pParseContext)
+    glslang::TParseContext* pParseContext;
+#endif
+#endif
+{
+/* The lookahead symbol.  */
+int yychar;
+
+
+#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
+/* Default value used for initialization, for pacifying older GCCs
+   or non-GCC compilers.  */
+static YYSTYPE yyval_default;
+# 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
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_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.
+
+       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;
+
+    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;
+
+#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))
+
+  /* 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;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  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;
+
+	/* 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),
+		    &yystacksize);
+
+	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);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + 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;
+    }
+
+  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
+
+  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];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+/* Line 1792 of yacc.c  */
+#line 250 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[(1) - (1)].lex).loc, (yyvsp[(1) - (1)].lex).symbol, (yyvsp[(1) - (1)].lex).string);
+    }
+    break;
+
+  case 3:
+/* Line 1792 of yacc.c  */
+#line 256 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 4:
+/* Line 1792 of yacc.c  */
+#line 259 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).i, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 5:
+/* Line 1792 of yacc.c  */
+#line 262 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "unsigned literal");
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).u, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 6:
+/* Line 1792 of yacc.c  */
+#line 266 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit integer literal");
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).i64, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 7:
+/* Line 1792 of yacc.c  */
+#line 270 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit unsigned integer literal");
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).u64, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 8:
+/* Line 1792 of yacc.c  */
+#line 274 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).d, EbtFloat, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 9:
+/* Line 1792 of yacc.c  */
+#line 277 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double literal");
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).d, EbtDouble, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 10:
+/* Line 1792 of yacc.c  */
+#line 281 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float literal");
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).d, EbtFloat16, (yyvsp[(1) - (1)].lex).loc, true);
+#endif
+    }
+    break;
+
+  case 11:
+/* Line 1792 of yacc.c  */
+#line 287 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[(1) - (1)].lex).b, (yyvsp[(1) - (1)].lex).loc, true);
+    }
+    break;
+
+  case 12:
+/* Line 1792 of yacc.c  */
+#line 290 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode);
+        if ((yyval.interm.intermTypedNode)->getAsConstantUnion())
+            (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression();
+    }
+    break;
+
+  case 13:
+/* Line 1792 of yacc.c  */
+#line 298 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 14:
+/* Line 1792 of yacc.c  */
+#line 301 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[(2) - (4)].lex).loc, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode));
+    }
+    break;
+
+  case 15:
+/* Line 1792 of yacc.c  */
+#line 304 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 16:
+/* Line 1792 of yacc.c  */
+#line 307 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[(3) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode), *(yyvsp[(3) - (3)].lex).string);
+    }
+    break;
+
+  case 17:
+/* Line 1792 of yacc.c  */
+#line 310 "glslang.y"
+    {
+        parseContext.variableCheck((yyvsp[(1) - (2)].interm.intermTypedNode));
+        parseContext.lValueErrorCheck((yyvsp[(2) - (2)].lex).loc, "++", (yyvsp[(1) - (2)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[(2) - (2)].lex).loc, "++", EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode));
+    }
+    break;
+
+  case 18:
+/* Line 1792 of yacc.c  */
+#line 315 "glslang.y"
+    {
+        parseContext.variableCheck((yyvsp[(1) - (2)].interm.intermTypedNode));
+        parseContext.lValueErrorCheck((yyvsp[(2) - (2)].lex).loc, "--", (yyvsp[(1) - (2)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[(2) - (2)].lex).loc, "--", EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode));
+    }
+    break;
+
+  case 19:
+/* Line 1792 of yacc.c  */
+#line 323 "glslang.y"
+    {
+        parseContext.integerCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]");
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 20:
+/* Line 1792 of yacc.c  */
+#line 330 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[(1) - (1)].interm).loc, (yyvsp[(1) - (1)].interm).function, (yyvsp[(1) - (1)].interm).intermNode);
+        delete (yyvsp[(1) - (1)].interm).function;
+    }
+    break;
+
+  case 21:
+/* Line 1792 of yacc.c  */
+#line 337 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (1)].interm);
+    }
+    break;
+
+  case 22:
+/* Line 1792 of yacc.c  */
+#line 343 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (2)].interm);
+        (yyval.interm).loc = (yyvsp[(2) - (2)].lex).loc;
+    }
+    break;
+
+  case 23:
+/* Line 1792 of yacc.c  */
+#line 347 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (2)].interm);
+        (yyval.interm).loc = (yyvsp[(2) - (2)].lex).loc;
+    }
+    break;
+
+  case 24:
+/* Line 1792 of yacc.c  */
+#line 354 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (2)].interm);
+    }
+    break;
+
+  case 25:
+/* Line 1792 of yacc.c  */
+#line 357 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (1)].interm);
+    }
+    break;
+
+  case 26:
+/* Line 1792 of yacc.c  */
+#line 363 "glslang.y"
+    {
+        TParameter param = { 0, new TType };
+        param.type->shallowCopy((yyvsp[(2) - (2)].interm.intermTypedNode)->getType());
+        (yyvsp[(1) - (2)].interm).function->addParameter(param);
+        (yyval.interm).function = (yyvsp[(1) - (2)].interm).function;
+        (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode);
+    }
+    break;
+
+  case 27:
+/* Line 1792 of yacc.c  */
+#line 370 "glslang.y"
+    {
+        TParameter param = { 0, new TType };
+        param.type->shallowCopy((yyvsp[(3) - (3)].interm.intermTypedNode)->getType());
+        (yyvsp[(1) - (3)].interm).function->addParameter(param);
+        (yyval.interm).function = (yyvsp[(1) - (3)].interm).function;
+        (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 28:
+/* Line 1792 of yacc.c  */
+#line 380 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (2)].interm);
+    }
+    break;
+
+  case 29:
+/* Line 1792 of yacc.c  */
+#line 388 "glslang.y"
+    {
+        // Constructor
+        (yyval.interm).intermNode = 0;
+        (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[(1) - (1)].interm.type).loc, (yyvsp[(1) - (1)].interm.type));
+    }
+    break;
+
+  case 30:
+/* Line 1792 of yacc.c  */
+#line 393 "glslang.y"
+    {
+        //
+        // Should be a method or subroutine call, but we haven't recognized the arguments yet.
+        //
+        (yyval.interm).function = 0;
+        (yyval.interm).intermNode = 0;
+
+        TIntermMethod* method = (yyvsp[(1) - (1)].interm.intermTypedNode)->getAsMethodNode();
+        if (method) {
+            (yyval.interm).function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength);
+            (yyval.interm).intermNode = method->getObject();
+        } else {
+            TIntermSymbol* symbol = (yyvsp[(1) - (1)].interm.intermTypedNode)->getAsSymbolNode();
+            if (symbol) {
+                parseContext.reservedErrorCheck(symbol->getLoc(), symbol->getName());
+                TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid));
+                (yyval.interm).function = function;
+            } else
+                parseContext.error((yyvsp[(1) - (1)].interm.intermTypedNode)->getLoc(), "function call, method, or subroutine call expected", "", "");
+        }
+
+        if ((yyval.interm).function == 0) {
+            // error recover
+            TString empty("");
+            (yyval.interm).function = new TFunction(&empty, TType(EbtVoid), EOpNull);
+        }
+    }
+    break;
+
+  case 31:
+/* Line 1792 of yacc.c  */
+#line 423 "glslang.y"
+    {
+        parseContext.variableCheck((yyvsp[(1) - (1)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+        if (TIntermMethod* method = (yyvsp[(1) - (1)].interm.intermTypedNode)->getAsMethodNode())
+            parseContext.error((yyvsp[(1) - (1)].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), "");
+    }
+    break;
+
+  case 32:
+/* Line 1792 of yacc.c  */
+#line 429 "glslang.y"
+    {
+        parseContext.lValueErrorCheck((yyvsp[(1) - (2)].lex).loc, "++", (yyvsp[(2) - (2)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[(1) - (2)].lex).loc, "++", EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode));
+    }
+    break;
+
+  case 33:
+/* Line 1792 of yacc.c  */
+#line 433 "glslang.y"
+    {
+        parseContext.lValueErrorCheck((yyvsp[(1) - (2)].lex).loc, "--", (yyvsp[(2) - (2)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[(1) - (2)].lex).loc, "--", EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode));
+    }
+    break;
+
+  case 34:
+/* Line 1792 of yacc.c  */
+#line 437 "glslang.y"
+    {
+        if ((yyvsp[(1) - (2)].interm).op != EOpNull) {
+            char errorOp[2] = {0, 0};
+            switch((yyvsp[(1) - (2)].interm).op) {
+            case EOpNegative:   errorOp[0] = '-'; break;
+            case EOpLogicalNot: errorOp[0] = '!'; break;
+            case EOpBitwiseNot: errorOp[0] = '~'; break;
+            default: break; // some compilers want this
+            }
+            (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[(1) - (2)].interm).loc, errorOp, (yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode));
+        } else {
+            (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+            if ((yyval.interm.intermTypedNode)->getAsConstantUnion())
+                (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression();
+        }
+    }
+    break;
+
+  case 35:
+/* Line 1792 of yacc.c  */
+#line 457 "glslang.y"
+    { (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpNull; }
+    break;
+
+  case 36:
+/* Line 1792 of yacc.c  */
+#line 458 "glslang.y"
+    { (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpNegative; }
+    break;
+
+  case 37:
+/* Line 1792 of yacc.c  */
+#line 459 "glslang.y"
+    { (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpLogicalNot; }
+    break;
+
+  case 38:
+/* Line 1792 of yacc.c  */
+#line 460 "glslang.y"
+    { (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpBitwiseNot;
+              parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bitwise not"); }
+    break;
+
+  case 39:
+/* Line 1792 of yacc.c  */
+#line 466 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 40:
+/* Line 1792 of yacc.c  */
+#line 467 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "*", EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 41:
+/* Line 1792 of yacc.c  */
+#line 472 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "/", EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 42:
+/* Line 1792 of yacc.c  */
+#line 477 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "%");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "%", EOpMod, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 43:
+/* Line 1792 of yacc.c  */
+#line 486 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 44:
+/* Line 1792 of yacc.c  */
+#line 487 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "+", EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 45:
+/* Line 1792 of yacc.c  */
+#line 492 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "-", EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 46:
+/* Line 1792 of yacc.c  */
+#line 500 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 47:
+/* Line 1792 of yacc.c  */
+#line 501 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "bit shift left");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "<<", EOpLeftShift, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 48:
+/* Line 1792 of yacc.c  */
+#line 507 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "bit shift right");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, ">>", EOpRightShift, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 49:
+/* Line 1792 of yacc.c  */
+#line 516 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 50:
+/* Line 1792 of yacc.c  */
+#line 517 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "<", EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 51:
+/* Line 1792 of yacc.c  */
+#line 522 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, ">", EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 52:
+/* Line 1792 of yacc.c  */
+#line 527 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "<=", EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 53:
+/* Line 1792 of yacc.c  */
+#line 532 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 54:
+/* Line 1792 of yacc.c  */
+#line 540 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 55:
+/* Line 1792 of yacc.c  */
+#line 541 "glslang.y"
+    {
+        parseContext.arrayObjectCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "array comparison");
+        parseContext.opaqueCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "==");
+        parseContext.specializationCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "==");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "==", EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 56:
+/* Line 1792 of yacc.c  */
+#line 549 "glslang.y"
+    {
+        parseContext.arrayObjectCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "array comparison");
+        parseContext.opaqueCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "!=");
+        parseContext.specializationCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "!=");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "!=", EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 57:
+/* Line 1792 of yacc.c  */
+#line 560 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 58:
+/* Line 1792 of yacc.c  */
+#line 561 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "bitwise and");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "&", EOpAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 59:
+/* Line 1792 of yacc.c  */
+#line 570 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 60:
+/* Line 1792 of yacc.c  */
+#line 571 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "bitwise exclusive or");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "^", EOpExclusiveOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 61:
+/* Line 1792 of yacc.c  */
+#line 580 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 62:
+/* Line 1792 of yacc.c  */
+#line 581 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(2) - (3)].lex).loc, "bitwise inclusive or");
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "|", EOpInclusiveOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 63:
+/* Line 1792 of yacc.c  */
+#line 590 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 64:
+/* Line 1792 of yacc.c  */
+#line 591 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "&&", EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 65:
+/* Line 1792 of yacc.c  */
+#line 599 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 66:
+/* Line 1792 of yacc.c  */
+#line 600 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "^^", EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 67:
+/* Line 1792 of yacc.c  */
+#line 608 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 68:
+/* Line 1792 of yacc.c  */
+#line 609 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[(2) - (3)].lex).loc, "||", EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+        if ((yyval.interm.intermTypedNode) == 0)
+            (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[(2) - (3)].lex).loc);
+    }
+    break;
+
+  case 69:
+/* Line 1792 of yacc.c  */
+#line 617 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 70:
+/* Line 1792 of yacc.c  */
+#line 618 "glslang.y"
+    {
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 71:
+/* Line 1792 of yacc.c  */
+#line 621 "glslang.y"
+    {
+        --parseContext.controlFlowNestingLevel;
+        parseContext.boolCheck((yyvsp[(2) - (6)].lex).loc, (yyvsp[(1) - (6)].interm.intermTypedNode));
+        parseContext.rValueErrorCheck((yyvsp[(2) - (6)].lex).loc, "?", (yyvsp[(1) - (6)].interm.intermTypedNode));
+        parseContext.rValueErrorCheck((yyvsp[(5) - (6)].lex).loc, ":", (yyvsp[(4) - (6)].interm.intermTypedNode));
+        parseContext.rValueErrorCheck((yyvsp[(5) - (6)].lex).loc, ":", (yyvsp[(6) - (6)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addSelection((yyvsp[(1) - (6)].interm.intermTypedNode), (yyvsp[(4) - (6)].interm.intermTypedNode), (yyvsp[(6) - (6)].interm.intermTypedNode), (yyvsp[(2) - (6)].lex).loc);
+        if ((yyval.interm.intermTypedNode) == 0) {
+            parseContext.binaryOpError((yyvsp[(2) - (6)].lex).loc, ":", (yyvsp[(4) - (6)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(6) - (6)].interm.intermTypedNode)->getCompleteString());
+            (yyval.interm.intermTypedNode) = (yyvsp[(6) - (6)].interm.intermTypedNode);
+        }
+    }
+    break;
+
+  case 72:
+/* Line 1792 of yacc.c  */
+#line 636 "glslang.y"
+    { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+    break;
+
+  case 73:
+/* Line 1792 of yacc.c  */
+#line 637 "glslang.y"
+    {
+        parseContext.arrayObjectCheck((yyvsp[(2) - (3)].interm).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "array assignment");
+        parseContext.opaqueCheck((yyvsp[(2) - (3)].interm).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "=");
+        parseContext.specializationCheck((yyvsp[(2) - (3)].interm).loc, (yyvsp[(1) - (3)].interm.intermTypedNode)->getType(), "=");
+        parseContext.lValueErrorCheck((yyvsp[(2) - (3)].interm).loc, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode));
+        parseContext.rValueErrorCheck((yyvsp[(2) - (3)].interm).loc, "assign", (yyvsp[(3) - (3)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].interm).loc);
+        if ((yyval.interm.intermTypedNode) == 0) {
+            parseContext.assignError((yyvsp[(2) - (3)].interm).loc, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+            (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+        }
+    }
+    break;
+
+  case 74:
+/* Line 1792 of yacc.c  */
+#line 652 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpAssign;
+    }
+    break;
+
+  case 75:
+/* Line 1792 of yacc.c  */
+#line 656 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpMulAssign;
+    }
+    break;
+
+  case 76:
+/* Line 1792 of yacc.c  */
+#line 660 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpDivAssign;
+    }
+    break;
+
+  case 77:
+/* Line 1792 of yacc.c  */
+#line 664 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "%=");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpModAssign;
+    }
+    break;
+
+  case 78:
+/* Line 1792 of yacc.c  */
+#line 669 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpAddAssign;
+    }
+    break;
+
+  case 79:
+/* Line 1792 of yacc.c  */
+#line 673 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm).op = EOpSubAssign;
+    }
+    break;
+
+  case 80:
+/* Line 1792 of yacc.c  */
+#line 677 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bit-shift left assign");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpLeftShiftAssign;
+    }
+    break;
+
+  case 81:
+/* Line 1792 of yacc.c  */
+#line 681 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bit-shift right assign");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpRightShiftAssign;
+    }
+    break;
+
+  case 82:
+/* Line 1792 of yacc.c  */
+#line 685 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bitwise-and assign");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpAndAssign;
+    }
+    break;
+
+  case 83:
+/* Line 1792 of yacc.c  */
+#line 689 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bitwise-xor assign");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign;
+    }
+    break;
+
+  case 84:
+/* Line 1792 of yacc.c  */
+#line 693 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "bitwise-or assign");
+        (yyval.interm).loc = (yyvsp[(1) - (1)].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign;
+    }
+    break;
+
+  case 85:
+/* Line 1792 of yacc.c  */
+#line 700 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 86:
+/* Line 1792 of yacc.c  */
+#line 703 "glslang.y"
+    {
+        parseContext.samplerConstructorLocationCheck((yyvsp[(2) - (3)].lex).loc, ",", (yyvsp[(3) - (3)].interm.intermTypedNode));
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).loc);
+        if ((yyval.interm.intermTypedNode) == 0) {
+            parseContext.binaryOpError((yyvsp[(2) - (3)].lex).loc, ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+            (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode);
+        }
+    }
+    break;
+
+  case 87:
+/* Line 1792 of yacc.c  */
+#line 714 "glslang.y"
+    {
+        parseContext.constantValueCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "");
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 88:
+/* Line 1792 of yacc.c  */
+#line 721 "glslang.y"
+    {
+        parseContext.handleFunctionDeclarator((yyvsp[(1) - (2)].interm).loc, *(yyvsp[(1) - (2)].interm).function, true /* prototype */);
+        (yyval.interm.intermNode) = 0;
+        // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature
+    }
+    break;
+
+  case 89:
+/* Line 1792 of yacc.c  */
+#line 726 "glslang.y"
+    {
+        if ((yyvsp[(1) - (2)].interm).intermNode && (yyvsp[(1) - (2)].interm).intermNode->getAsAggregate())
+            (yyvsp[(1) - (2)].interm).intermNode->getAsAggregate()->setOperator(EOpSequence);
+        (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermNode;
+    }
+    break;
+
+  case 90:
+/* Line 1792 of yacc.c  */
+#line 731 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (4)].lex).loc, ENoProfile, 130, 0, "precision statement");
+
+        // lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope
+        parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]);
+        parseContext.setDefaultPrecision((yyvsp[(1) - (4)].lex).loc, (yyvsp[(3) - (4)].interm.type), (yyvsp[(2) - (4)].interm.type).qualifier.precision);
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 91:
+/* Line 1792 of yacc.c  */
+#line 739 "glslang.y"
+    {
+        parseContext.declareBlock((yyvsp[(1) - (2)].interm).loc, *(yyvsp[(1) - (2)].interm).typeList);
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 92:
+/* Line 1792 of yacc.c  */
+#line 743 "glslang.y"
+    {
+        parseContext.declareBlock((yyvsp[(1) - (3)].interm).loc, *(yyvsp[(1) - (3)].interm).typeList, (yyvsp[(2) - (3)].lex).string);
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 93:
+/* Line 1792 of yacc.c  */
+#line 747 "glslang.y"
+    {
+        parseContext.declareBlock((yyvsp[(1) - (4)].interm).loc, *(yyvsp[(1) - (4)].interm).typeList, (yyvsp[(2) - (4)].lex).string, (yyvsp[(3) - (4)].interm).arraySizes);
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 94:
+/* Line 1792 of yacc.c  */
+#line 751 "glslang.y"
+    {
+        parseContext.globalQualifierFixCheck((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier);
+        parseContext.updateStandaloneQualifierDefaults((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type));
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 95:
+/* Line 1792 of yacc.c  */
+#line 756 "glslang.y"
+    {
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (3)].interm.type).loc, (yyvsp[(1) - (3)].interm.type).shaderQualifiers);
+        parseContext.addQualifierToExisting((yyvsp[(1) - (3)].interm.type).loc, (yyvsp[(1) - (3)].interm.type).qualifier, *(yyvsp[(2) - (3)].lex).string);
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 96:
+/* Line 1792 of yacc.c  */
+#line 761 "glslang.y"
+    {
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (4)].interm.type).loc, (yyvsp[(1) - (4)].interm.type).shaderQualifiers);
+        (yyvsp[(3) - (4)].interm.identifierList)->push_back((yyvsp[(2) - (4)].lex).string);
+        parseContext.addQualifierToExisting((yyvsp[(1) - (4)].interm.type).loc, (yyvsp[(1) - (4)].interm.type).qualifier, *(yyvsp[(3) - (4)].interm.identifierList));
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 97:
+/* Line 1792 of yacc.c  */
+#line 770 "glslang.y"
+    { parseContext.nestedBlockCheck((yyvsp[(1) - (3)].interm.type).loc); }
+    break;
+
+  case 98:
+/* Line 1792 of yacc.c  */
+#line 770 "glslang.y"
+    {
+        --parseContext.structNestingLevel;
+        parseContext.blockName = (yyvsp[(2) - (6)].lex).string;
+        parseContext.globalQualifierFixCheck((yyvsp[(1) - (6)].interm.type).loc, (yyvsp[(1) - (6)].interm.type).qualifier);
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (6)].interm.type).loc, (yyvsp[(1) - (6)].interm.type).shaderQualifiers);
+        parseContext.currentBlockQualifier = (yyvsp[(1) - (6)].interm.type).qualifier;
+        (yyval.interm).loc = (yyvsp[(1) - (6)].interm.type).loc;
+        (yyval.interm).typeList = (yyvsp[(5) - (6)].interm.typeList);
+    }
+    break;
+
+  case 99:
+/* Line 1792 of yacc.c  */
+#line 781 "glslang.y"
+    {
+        (yyval.interm.identifierList) = new TIdentifierList;
+        (yyval.interm.identifierList)->push_back((yyvsp[(2) - (2)].lex).string);
+    }
+    break;
+
+  case 100:
+/* Line 1792 of yacc.c  */
+#line 785 "glslang.y"
+    {
+        (yyval.interm.identifierList) = (yyvsp[(1) - (3)].interm.identifierList);
+        (yyval.interm.identifierList)->push_back((yyvsp[(3) - (3)].lex).string);
+    }
+    break;
+
+  case 101:
+/* Line 1792 of yacc.c  */
+#line 792 "glslang.y"
+    {
+        (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+        (yyval.interm).loc = (yyvsp[(2) - (2)].lex).loc;
+    }
+    break;
+
+  case 102:
+/* Line 1792 of yacc.c  */
+#line 799 "glslang.y"
+    {
+        (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+    }
+    break;
+
+  case 103:
+/* Line 1792 of yacc.c  */
+#line 802 "glslang.y"
+    {
+        (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+    }
+    break;
+
+  case 104:
+/* Line 1792 of yacc.c  */
+#line 809 "glslang.y"
+    {
+        // Add the parameter
+        (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+        if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid)
+            (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param);
+        else
+            delete (yyvsp[(2) - (2)].interm).param.type;
+    }
+    break;
+
+  case 105:
+/* Line 1792 of yacc.c  */
+#line 817 "glslang.y"
+    {
+        //
+        // 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[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) {
+            //
+            // This parameter > first is void
+            //
+            parseContext.error((yyvsp[(2) - (3)].lex).loc, "cannot be an argument type except for '(void)'", "void", "");
+            delete (yyvsp[(3) - (3)].interm).param.type;
+        } else {
+            // Add the parameter
+            (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function);
+            (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param);
+        }
+    }
+    break;
+
+  case 106:
+/* Line 1792 of yacc.c  */
+#line 837 "glslang.y"
+    {
+        if ((yyvsp[(1) - (3)].interm.type).qualifier.storage != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier.storage != EvqTemporary) {
+            parseContext.error((yyvsp[(2) - (3)].lex).loc, "no qualifiers allowed for function return",
+                               GetStorageQualifierString((yyvsp[(1) - (3)].interm.type).qualifier.storage), "");
+        }
+        if ((yyvsp[(1) - (3)].interm.type).arraySizes)
+            parseContext.arraySizeRequiredCheck((yyvsp[(1) - (3)].interm.type).loc, *(yyvsp[(1) - (3)].interm.type).arraySizes);
+
+        // Add the function as a prototype after parsing it (we do not support recursion)
+        TFunction *function;
+        TType type((yyvsp[(1) - (3)].interm.type));
+        function = new TFunction((yyvsp[(2) - (3)].lex).string, type);
+        (yyval.interm.function) = function;
+    }
+    break;
+
+  case 107:
+/* Line 1792 of yacc.c  */
+#line 855 "glslang.y"
+    {
+        if ((yyvsp[(1) - (2)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(1) - (2)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(1) - (2)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+            parseContext.arraySizeRequiredCheck((yyvsp[(1) - (2)].interm.type).loc, *(yyvsp[(1) - (2)].interm.type).arraySizes);
+        }
+        if ((yyvsp[(1) - (2)].interm.type).basicType == EbtVoid) {
+            parseContext.error((yyvsp[(2) - (2)].lex).loc, "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str(), "");
+        }
+        parseContext.reservedErrorCheck((yyvsp[(2) - (2)].lex).loc, *(yyvsp[(2) - (2)].lex).string);
+
+        TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))};
+        (yyval.interm).loc = (yyvsp[(2) - (2)].lex).loc;
+        (yyval.interm).param = param;
+    }
+    break;
+
+  case 108:
+/* Line 1792 of yacc.c  */
+#line 870 "glslang.y"
+    {
+        if ((yyvsp[(1) - (3)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(1) - (3)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(1) - (3)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+            parseContext.arraySizeRequiredCheck((yyvsp[(1) - (3)].interm.type).loc, *(yyvsp[(1) - (3)].interm.type).arraySizes);
+        }
+        parseContext.arrayDimCheck((yyvsp[(2) - (3)].lex).loc, (yyvsp[(1) - (3)].interm.type).arraySizes, (yyvsp[(3) - (3)].interm).arraySizes);
+
+        parseContext.arraySizeRequiredCheck((yyvsp[(3) - (3)].interm).loc, *(yyvsp[(3) - (3)].interm).arraySizes);
+        parseContext.reservedErrorCheck((yyvsp[(2) - (3)].lex).loc, *(yyvsp[(2) - (3)].lex).string);
+
+        (yyvsp[(1) - (3)].interm.type).arraySizes = (yyvsp[(3) - (3)].interm).arraySizes;
+
+        TParameter param = { (yyvsp[(2) - (3)].lex).string, new TType((yyvsp[(1) - (3)].interm.type))};
+        (yyval.interm).loc = (yyvsp[(2) - (3)].lex).loc;
+        (yyval.interm).param = param;
+    }
+    break;
+
+  case 109:
+/* Line 1792 of yacc.c  */
+#line 893 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(2) - (2)].interm);
+        if ((yyvsp[(1) - (2)].interm.type).qualifier.precision != EpqNone)
+            (yyval.interm).param.type->getQualifier().precision = (yyvsp[(1) - (2)].interm.type).qualifier.precision;
+        parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier());
+
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).shaderQualifiers);
+        parseContext.parameterTypeCheck((yyvsp[(2) - (2)].interm).loc, (yyvsp[(1) - (2)].interm.type).qualifier.storage, *(yyval.interm).param.type);
+        parseContext.paramCheckFix((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier, *(yyval.interm).param.type);
+
+    }
+    break;
+
+  case 110:
+/* Line 1792 of yacc.c  */
+#line 904 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (1)].interm);
+
+        parseContext.parameterTypeCheck((yyvsp[(1) - (1)].interm).loc, EvqIn, *(yyvsp[(1) - (1)].interm).param.type);
+        parseContext.paramCheckFix((yyvsp[(1) - (1)].interm).loc, EvqTemporary, *(yyval.interm).param.type);
+        parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier());
+    }
+    break;
+
+  case 111:
+/* Line 1792 of yacc.c  */
+#line 914 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(2) - (2)].interm);
+        if ((yyvsp[(1) - (2)].interm.type).qualifier.precision != EpqNone)
+            (yyval.interm).param.type->getQualifier().precision = (yyvsp[(1) - (2)].interm.type).qualifier.precision;
+        parseContext.precisionQualifierCheck((yyvsp[(1) - (2)].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier());
+
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).shaderQualifiers);
+        parseContext.parameterTypeCheck((yyvsp[(2) - (2)].interm).loc, (yyvsp[(1) - (2)].interm.type).qualifier.storage, *(yyval.interm).param.type);
+        parseContext.paramCheckFix((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier, *(yyval.interm).param.type);
+    }
+    break;
+
+  case 112:
+/* Line 1792 of yacc.c  */
+#line 924 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (1)].interm);
+
+        parseContext.parameterTypeCheck((yyvsp[(1) - (1)].interm).loc, EvqIn, *(yyvsp[(1) - (1)].interm).param.type);
+        parseContext.paramCheckFix((yyvsp[(1) - (1)].interm).loc, EvqTemporary, *(yyval.interm).param.type);
+        parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier());
+    }
+    break;
+
+  case 113:
+/* Line 1792 of yacc.c  */
+#line 934 "glslang.y"
+    {
+        TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) };
+        (yyval.interm).param = param;
+        if ((yyvsp[(1) - (1)].interm.type).arraySizes)
+            parseContext.arraySizeRequiredCheck((yyvsp[(1) - (1)].interm.type).loc, *(yyvsp[(1) - (1)].interm.type).arraySizes);
+    }
+    break;
+
+  case 114:
+/* Line 1792 of yacc.c  */
+#line 943 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (1)].interm);
+    }
+    break;
+
+  case 115:
+/* Line 1792 of yacc.c  */
+#line 946 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (3)].interm);
+        parseContext.declareVariable((yyvsp[(3) - (3)].lex).loc, *(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm).type);
+    }
+    break;
+
+  case 116:
+/* Line 1792 of yacc.c  */
+#line 950 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (4)].interm);
+        parseContext.declareVariable((yyvsp[(3) - (4)].lex).loc, *(yyvsp[(3) - (4)].lex).string, (yyvsp[(1) - (4)].interm).type, (yyvsp[(4) - (4)].interm).arraySizes);
+    }
+    break;
+
+  case 117:
+/* Line 1792 of yacc.c  */
+#line 954 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (6)].interm).type;
+        TIntermNode* initNode = parseContext.declareVariable((yyvsp[(3) - (6)].lex).loc, *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, (yyvsp[(4) - (6)].interm).arraySizes, (yyvsp[(6) - (6)].interm.intermTypedNode));
+        (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[(1) - (6)].interm).intermNode, initNode, (yyvsp[(5) - (6)].lex).loc);
+    }
+    break;
+
+  case 118:
+/* Line 1792 of yacc.c  */
+#line 959 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (5)].interm).type;
+        TIntermNode* initNode = parseContext.declareVariable((yyvsp[(3) - (5)].lex).loc, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, 0, (yyvsp[(5) - (5)].interm.intermTypedNode));
+        (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[(1) - (5)].interm).intermNode, initNode, (yyvsp[(4) - (5)].lex).loc);
+    }
+    break;
+
+  case 119:
+/* Line 1792 of yacc.c  */
+#line 967 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (1)].interm.type);
+        (yyval.interm).intermNode = 0;
+        parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type);
+    }
+    break;
+
+  case 120:
+/* Line 1792 of yacc.c  */
+#line 972 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (2)].interm.type);
+        (yyval.interm).intermNode = 0;
+        parseContext.declareVariable((yyvsp[(2) - (2)].lex).loc, *(yyvsp[(2) - (2)].lex).string, (yyvsp[(1) - (2)].interm.type));
+    }
+    break;
+
+  case 121:
+/* Line 1792 of yacc.c  */
+#line 977 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (3)].interm.type);
+        (yyval.interm).intermNode = 0;
+        parseContext.declareVariable((yyvsp[(2) - (3)].lex).loc, *(yyvsp[(2) - (3)].lex).string, (yyvsp[(1) - (3)].interm.type), (yyvsp[(3) - (3)].interm).arraySizes);
+    }
+    break;
+
+  case 122:
+/* Line 1792 of yacc.c  */
+#line 982 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (5)].interm.type);
+        TIntermNode* initNode = parseContext.declareVariable((yyvsp[(2) - (5)].lex).loc, *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), (yyvsp[(3) - (5)].interm).arraySizes, (yyvsp[(5) - (5)].interm.intermTypedNode));
+        (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[(4) - (5)].lex).loc);
+    }
+    break;
+
+  case 123:
+/* Line 1792 of yacc.c  */
+#line 987 "glslang.y"
+    {
+        (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+        TIntermNode* initNode = parseContext.declareVariable((yyvsp[(2) - (4)].lex).loc, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), 0, (yyvsp[(4) - (4)].interm.intermTypedNode));
+        (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[(3) - (4)].lex).loc);
+    }
+    break;
+
+  case 124:
+/* Line 1792 of yacc.c  */
+#line 996 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+        parseContext.globalQualifierTypeCheck((yyvsp[(1) - (1)].interm.type).loc, (yyvsp[(1) - (1)].interm.type).qualifier, (yyval.interm.type));
+        if ((yyvsp[(1) - (1)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(1) - (1)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(1) - (1)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+        }
+
+        parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier);
+    }
+    break;
+
+  case 125:
+/* Line 1792 of yacc.c  */
+#line 1007 "glslang.y"
+    {
+        parseContext.globalQualifierFixCheck((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier);
+        parseContext.globalQualifierTypeCheck((yyvsp[(1) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(2) - (2)].interm.type));
+
+        if ((yyvsp[(2) - (2)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(2) - (2)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(2) - (2)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+        }
+
+        if ((yyvsp[(2) - (2)].interm.type).arraySizes && parseContext.arrayQualifierError((yyvsp[(2) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).qualifier))
+            (yyvsp[(2) - (2)].interm.type).arraySizes = 0;
+
+        parseContext.checkNoShaderLayouts((yyvsp[(2) - (2)].interm.type).loc, (yyvsp[(1) - (2)].interm.type).shaderQualifiers);
+        (yyvsp[(2) - (2)].interm.type).shaderQualifiers.merge((yyvsp[(1) - (2)].interm.type).shaderQualifiers);
+        parseContext.mergeQualifiers((yyvsp[(2) - (2)].interm.type).loc, (yyvsp[(2) - (2)].interm.type).qualifier, (yyvsp[(1) - (2)].interm.type).qualifier, true);
+        parseContext.precisionQualifierCheck((yyvsp[(2) - (2)].interm.type).loc, (yyvsp[(2) - (2)].interm.type).basicType, (yyvsp[(2) - (2)].interm.type).qualifier);
+
+        (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+
+        if (! (yyval.interm.type).qualifier.isInterpolation() &&
+            ((parseContext.language == EShLangVertex   && (yyval.interm.type).qualifier.storage == EvqVaryingOut) ||
+             (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn)))
+            (yyval.interm.type).qualifier.smooth = true;
+    }
+    break;
+
+  case 126:
+/* Line 1792 of yacc.c  */
+#line 1034 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "invariant");
+        parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.invariant = true;
+    }
+    break;
+
+  case 127:
+/* Line 1792 of yacc.c  */
+#line 1043 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "smooth");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "smooth");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, EEsProfile, 300, 0, "smooth");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.smooth = true;
+    }
+    break;
+
+  case 128:
+/* Line 1792 of yacc.c  */
+#line 1050 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "flat");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "flat");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, EEsProfile, 300, 0, "flat");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.flat = true;
+    }
+    break;
+
+  case 129:
+/* Line 1792 of yacc.c  */
+#line 1057 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "noperspective");
+        parseContext.requireProfile((yyvsp[(1) - (1)].lex).loc, ~EEsProfile, "noperspective");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "noperspective");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.nopersp = true;
+    }
+    break;
+
+  case 130:
+/* Line 1792 of yacc.c  */
+#line 1064 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "__explicitInterpAMD");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.explicitInterp = true;
+#endif
+    }
+    break;
+
+  case 131:
+/* Line 1792 of yacc.c  */
+#line 1076 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(3) - (4)].interm.type);
+    }
+    break;
+
+  case 132:
+/* Line 1792 of yacc.c  */
+#line 1082 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 133:
+/* Line 1792 of yacc.c  */
+#line 1085 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (3)].interm.type);
+        (yyval.interm.type).shaderQualifiers.merge((yyvsp[(3) - (3)].interm.type).shaderQualifiers);
+        parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[(3) - (3)].interm.type).qualifier, false);
+    }
+    break;
+
+  case 134:
+/* Line 1792 of yacc.c  */
+#line 1092 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        parseContext.setLayoutQualifier((yyvsp[(1) - (1)].lex).loc, (yyval.interm.type), *(yyvsp[(1) - (1)].lex).string);
+    }
+    break;
+
+  case 135:
+/* Line 1792 of yacc.c  */
+#line 1096 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (3)].lex).loc);
+        parseContext.setLayoutQualifier((yyvsp[(1) - (3)].lex).loc, (yyval.interm.type), *(yyvsp[(1) - (3)].lex).string, (yyvsp[(3) - (3)].interm.intermTypedNode));
+    }
+    break;
+
+  case 136:
+/* Line 1792 of yacc.c  */
+#line 1100 "glslang.y"
+    { // because "shared" is both an identifier and a keyword
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        TString strShared("shared");
+        parseContext.setLayoutQualifier((yyvsp[(1) - (1)].lex).loc, (yyval.interm.type), strShared);
+    }
+    break;
+
+  case 137:
+/* Line 1792 of yacc.c  */
+#line 1108 "glslang.y"
+    {
+        parseContext.profileRequires((yyval.interm.type).loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader5, "precise");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, "precise");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.noContraction = true;
+    }
+    break;
+
+  case 138:
+/* Line 1792 of yacc.c  */
+#line 1117 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 139:
+/* Line 1792 of yacc.c  */
+#line 1120 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (2)].interm.type);
+        if ((yyval.interm.type).basicType == EbtVoid)
+            (yyval.interm.type).basicType = (yyvsp[(2) - (2)].interm.type).basicType;
+
+        (yyval.interm.type).shaderQualifiers.merge((yyvsp[(2) - (2)].interm.type).shaderQualifiers);
+        parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[(2) - (2)].interm.type).qualifier, false);
+    }
+    break;
+
+  case 140:
+/* Line 1792 of yacc.c  */
+#line 1131 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 141:
+/* Line 1792 of yacc.c  */
+#line 1134 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 142:
+/* Line 1792 of yacc.c  */
+#line 1137 "glslang.y"
+    {
+        parseContext.checkPrecisionQualifier((yyvsp[(1) - (1)].interm.type).loc, (yyvsp[(1) - (1)].interm.type).qualifier.precision);
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 143:
+/* Line 1792 of yacc.c  */
+#line 1141 "glslang.y"
+    {
+        // allow inheritance of storage qualifier from block declaration
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 144:
+/* Line 1792 of yacc.c  */
+#line 1145 "glslang.y"
+    {
+        // allow inheritance of storage qualifier from block declaration
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 145:
+/* Line 1792 of yacc.c  */
+#line 1149 "glslang.y"
+    {
+        // allow inheritance of storage qualifier from block declaration
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+    }
+    break;
+
+  case 146:
+/* Line 1792 of yacc.c  */
+#line 1156 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqConst;  // will later turn into EvqConstReadOnly, if the initializer is not constant
+    }
+    break;
+
+  case 147:
+/* Line 1792 of yacc.c  */
+#line 1160 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangVertex, "attribute");
+        parseContext.checkDeprecated((yyvsp[(1) - (1)].lex).loc, ECoreProfile, 130, "attribute");
+        parseContext.checkDeprecated((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, "attribute");
+        parseContext.requireNotRemoved((yyvsp[(1) - (1)].lex).loc, ECoreProfile, 420, "attribute");
+        parseContext.requireNotRemoved((yyvsp[(1) - (1)].lex).loc, EEsProfile, 300, "attribute");
+
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "attribute");
+
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqVaryingIn;
+    }
+    break;
+
+  case 148:
+/* Line 1792 of yacc.c  */
+#line 1172 "glslang.y"
+    {
+        parseContext.checkDeprecated((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, "varying");
+        parseContext.checkDeprecated((yyvsp[(1) - (1)].lex).loc, ECoreProfile, 130, "varying");
+        parseContext.requireNotRemoved((yyvsp[(1) - (1)].lex).loc, ECoreProfile, 420, "varying");
+        parseContext.requireNotRemoved((yyvsp[(1) - (1)].lex).loc, EEsProfile, 300, "varying");
+
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "varying");
+
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        if (parseContext.language == EShLangVertex)
+            (yyval.interm.type).qualifier.storage = EvqVaryingOut;
+        else
+            (yyval.interm.type).qualifier.storage = EvqVaryingIn;
+    }
+    break;
+
+  case 149:
+/* Line 1792 of yacc.c  */
+#line 1186 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "inout");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqInOut;
+    }
+    break;
+
+  case 150:
+/* Line 1792 of yacc.c  */
+#line 1191 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "in");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later
+        (yyval.interm.type).qualifier.storage = EvqIn;
+    }
+    break;
+
+  case 151:
+/* Line 1792 of yacc.c  */
+#line 1197 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "out");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later
+        (yyval.interm.type).qualifier.storage = EvqOut;
+    }
+    break;
+
+  case 152:
+/* Line 1792 of yacc.c  */
+#line 1203 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 120, 0, "centroid");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, EEsProfile, 300, 0, "centroid");
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "centroid");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.centroid = true;
+    }
+    break;
+
+  case 153:
+/* Line 1792 of yacc.c  */
+#line 1210 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "patch");
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.patch = true;
+    }
+    break;
+
+  case 154:
+/* Line 1792 of yacc.c  */
+#line 1216 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "sample");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.sample = true;
+    }
+    break;
+
+  case 155:
+/* Line 1792 of yacc.c  */
+#line 1221 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "uniform");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqUniform;
+    }
+    break;
+
+  case 156:
+/* Line 1792 of yacc.c  */
+#line 1226 "glslang.y"
+    {
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "buffer");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqBuffer;
+    }
+    break;
+
+  case 157:
+/* Line 1792 of yacc.c  */
+#line 1231 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared");
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, EEsProfile, 310, 0, "shared");
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangCompute, "shared");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqShared;
+    }
+    break;
+
+  case 158:
+/* Line 1792 of yacc.c  */
+#line 1238 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.coherent = true;
+    }
+    break;
+
+  case 159:
+/* Line 1792 of yacc.c  */
+#line 1242 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.volatil = true;
+    }
+    break;
+
+  case 160:
+/* Line 1792 of yacc.c  */
+#line 1246 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.restrict = true;
+    }
+    break;
+
+  case 161:
+/* Line 1792 of yacc.c  */
+#line 1250 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.readonly = true;
+    }
+    break;
+
+  case 162:
+/* Line 1792 of yacc.c  */
+#line 1254 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.writeonly = true;
+    }
+    break;
+
+  case 163:
+/* Line 1792 of yacc.c  */
+#line 1258 "glslang.y"
+    {
+        parseContext.spvRemoved((yyvsp[(1) - (1)].lex).loc, "subroutine");
+        parseContext.globalCheck((yyvsp[(1) - (1)].lex).loc, "subroutine");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqUniform;
+    }
+    break;
+
+  case 164:
+/* Line 1792 of yacc.c  */
+#line 1264 "glslang.y"
+    {
+        parseContext.spvRemoved((yyvsp[(1) - (4)].lex).loc, "subroutine");
+        parseContext.globalCheck((yyvsp[(1) - (4)].lex).loc, "subroutine");
+        (yyval.interm.type).init((yyvsp[(1) - (4)].lex).loc);
+        (yyval.interm.type).qualifier.storage = EvqUniform;
+        // TODO: 4.0 semantics: subroutines
+        // 1) make sure each identifier is a type declared earlier with SUBROUTINE
+        // 2) save all of the identifiers for future comparison with the declared function
+    }
+    break;
+
+  case 165:
+/* Line 1792 of yacc.c  */
+#line 1276 "glslang.y"
+    {
+        // TODO: 4.0 functionality: subroutine type to list
+    }
+    break;
+
+  case 166:
+/* Line 1792 of yacc.c  */
+#line 1279 "glslang.y"
+    {
+    }
+    break;
+
+  case 167:
+/* Line 1792 of yacc.c  */
+#line 1284 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+        (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type));
+    }
+    break;
+
+  case 168:
+/* Line 1792 of yacc.c  */
+#line 1288 "glslang.y"
+    {
+        parseContext.arrayDimCheck((yyvsp[(2) - (2)].interm).loc, (yyvsp[(2) - (2)].interm).arraySizes, 0);
+        (yyval.interm.type) = (yyvsp[(1) - (2)].interm.type);
+        (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type));
+        (yyval.interm.type).arraySizes = (yyvsp[(2) - (2)].interm).arraySizes;
+    }
+    break;
+
+  case 169:
+/* Line 1792 of yacc.c  */
+#line 1297 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (2)].lex).loc;
+        (yyval.interm).arraySizes = new TArraySizes;
+        (yyval.interm).arraySizes->addInnerSize();
+    }
+    break;
+
+  case 170:
+/* Line 1792 of yacc.c  */
+#line 1302 "glslang.y"
+    {
+        (yyval.interm).loc = (yyvsp[(1) - (3)].lex).loc;
+        (yyval.interm).arraySizes = new TArraySizes;
+
+        TArraySize size;
+        parseContext.arraySizeCheck((yyvsp[(2) - (3)].interm.intermTypedNode)->getLoc(), (yyvsp[(2) - (3)].interm.intermTypedNode), size);
+        (yyval.interm).arraySizes->addInnerSize(size);
+    }
+    break;
+
+  case 171:
+/* Line 1792 of yacc.c  */
+#line 1310 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (3)].interm);
+        (yyval.interm).arraySizes->addInnerSize();
+    }
+    break;
+
+  case 172:
+/* Line 1792 of yacc.c  */
+#line 1314 "glslang.y"
+    {
+        (yyval.interm) = (yyvsp[(1) - (4)].interm);
+
+        TArraySize size;
+        parseContext.arraySizeCheck((yyvsp[(3) - (4)].interm.intermTypedNode)->getLoc(), (yyvsp[(3) - (4)].interm.intermTypedNode), size);
+        (yyval.interm).arraySizes->addInnerSize(size);
+    }
+    break;
+
+  case 173:
+/* Line 1792 of yacc.c  */
+#line 1324 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtVoid;
+    }
+    break;
+
+  case 174:
+/* Line 1792 of yacc.c  */
+#line 1328 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+    }
+    break;
+
+  case 175:
+/* Line 1792 of yacc.c  */
+#line 1332 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+    }
+    break;
+
+  case 176:
+/* Line 1792 of yacc.c  */
+#line 1337 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+#endif
+    }
+    break;
+
+  case 177:
+/* Line 1792 of yacc.c  */
+#line 1344 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt;
+    }
+    break;
+
+  case 178:
+/* Line 1792 of yacc.c  */
+#line 1348 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "unsigned integer");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint;
+    }
+    break;
+
+  case 179:
+/* Line 1792 of yacc.c  */
+#line 1353 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt64;
+    }
+    break;
+
+  case 180:
+/* Line 1792 of yacc.c  */
+#line 1358 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint64;
+    }
+    break;
+
+  case 181:
+/* Line 1792 of yacc.c  */
+#line 1363 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtBool;
+    }
+    break;
+
+  case 182:
+/* Line 1792 of yacc.c  */
+#line 1367 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 183:
+/* Line 1792 of yacc.c  */
+#line 1372 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 184:
+/* Line 1792 of yacc.c  */
+#line 1377 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 185:
+/* Line 1792 of yacc.c  */
+#line 1382 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 186:
+/* Line 1792 of yacc.c  */
+#line 1388 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 187:
+/* Line 1792 of yacc.c  */
+#line 1394 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 188:
+/* Line 1792 of yacc.c  */
+#line 1400 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setVector(2);
+#endif
+    }
+    break;
+
+  case 189:
+/* Line 1792 of yacc.c  */
+#line 1408 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setVector(3);
+#endif
+    }
+    break;
+
+  case 190:
+/* Line 1792 of yacc.c  */
+#line 1416 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setVector(4);
+#endif
+    }
+    break;
+
+  case 191:
+/* Line 1792 of yacc.c  */
+#line 1424 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtBool;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 192:
+/* Line 1792 of yacc.c  */
+#line 1429 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtBool;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 193:
+/* Line 1792 of yacc.c  */
+#line 1434 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtBool;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 194:
+/* Line 1792 of yacc.c  */
+#line 1439 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 195:
+/* Line 1792 of yacc.c  */
+#line 1444 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 196:
+/* Line 1792 of yacc.c  */
+#line 1449 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 197:
+/* Line 1792 of yacc.c  */
+#line 1454 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt64;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 198:
+/* Line 1792 of yacc.c  */
+#line 1460 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt64;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 199:
+/* Line 1792 of yacc.c  */
+#line 1466 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtInt64;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 200:
+/* Line 1792 of yacc.c  */
+#line 1472 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "unsigned integer vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 201:
+/* Line 1792 of yacc.c  */
+#line 1478 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "unsigned integer vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 202:
+/* Line 1792 of yacc.c  */
+#line 1484 "glslang.y"
+    {
+        parseContext.fullIntegerCheck((yyvsp[(1) - (1)].lex).loc, "unsigned integer vector");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 203:
+/* Line 1792 of yacc.c  */
+#line 1490 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint64;
+        (yyval.interm.type).setVector(2);
+    }
+    break;
+
+  case 204:
+/* Line 1792 of yacc.c  */
+#line 1496 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint64;
+        (yyval.interm.type).setVector(3);
+    }
+    break;
+
+  case 205:
+/* Line 1792 of yacc.c  */
+#line 1502 "glslang.y"
+    {
+        parseContext.int64Check((yyvsp[(1) - (1)].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtUint64;
+        (yyval.interm.type).setVector(4);
+    }
+    break;
+
+  case 206:
+/* Line 1792 of yacc.c  */
+#line 1508 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(2, 2);
+    }
+    break;
+
+  case 207:
+/* Line 1792 of yacc.c  */
+#line 1513 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(3, 3);
+    }
+    break;
+
+  case 208:
+/* Line 1792 of yacc.c  */
+#line 1518 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(4, 4);
+    }
+    break;
+
+  case 209:
+/* Line 1792 of yacc.c  */
+#line 1523 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(2, 2);
+    }
+    break;
+
+  case 210:
+/* Line 1792 of yacc.c  */
+#line 1528 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(2, 3);
+    }
+    break;
+
+  case 211:
+/* Line 1792 of yacc.c  */
+#line 1533 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(2, 4);
+    }
+    break;
+
+  case 212:
+/* Line 1792 of yacc.c  */
+#line 1538 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(3, 2);
+    }
+    break;
+
+  case 213:
+/* Line 1792 of yacc.c  */
+#line 1543 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(3, 3);
+    }
+    break;
+
+  case 214:
+/* Line 1792 of yacc.c  */
+#line 1548 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(3, 4);
+    }
+    break;
+
+  case 215:
+/* Line 1792 of yacc.c  */
+#line 1553 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(4, 2);
+    }
+    break;
+
+  case 216:
+/* Line 1792 of yacc.c  */
+#line 1558 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(4, 3);
+    }
+    break;
+
+  case 217:
+/* Line 1792 of yacc.c  */
+#line 1563 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat;
+        (yyval.interm.type).setMatrix(4, 4);
+    }
+    break;
+
+  case 218:
+/* Line 1792 of yacc.c  */
+#line 1568 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(2, 2);
+    }
+    break;
+
+  case 219:
+/* Line 1792 of yacc.c  */
+#line 1574 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(3, 3);
+    }
+    break;
+
+  case 220:
+/* Line 1792 of yacc.c  */
+#line 1580 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(4, 4);
+    }
+    break;
+
+  case 221:
+/* Line 1792 of yacc.c  */
+#line 1586 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(2, 2);
+    }
+    break;
+
+  case 222:
+/* Line 1792 of yacc.c  */
+#line 1592 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(2, 3);
+    }
+    break;
+
+  case 223:
+/* Line 1792 of yacc.c  */
+#line 1598 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(2, 4);
+    }
+    break;
+
+  case 224:
+/* Line 1792 of yacc.c  */
+#line 1604 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(3, 2);
+    }
+    break;
+
+  case 225:
+/* Line 1792 of yacc.c  */
+#line 1610 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(3, 3);
+    }
+    break;
+
+  case 226:
+/* Line 1792 of yacc.c  */
+#line 1616 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(3, 4);
+    }
+    break;
+
+  case 227:
+/* Line 1792 of yacc.c  */
+#line 1622 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(4, 2);
+    }
+    break;
+
+  case 228:
+/* Line 1792 of yacc.c  */
+#line 1628 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(4, 3);
+    }
+    break;
+
+  case 229:
+/* Line 1792 of yacc.c  */
+#line 1634 "glslang.y"
+    {
+        parseContext.doubleCheck((yyvsp[(1) - (1)].lex).loc, "double matrix");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtDouble;
+        (yyval.interm.type).setMatrix(4, 4);
+    }
+    break;
+
+  case 230:
+/* Line 1792 of yacc.c  */
+#line 1640 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(2, 2);
+#endif
+    }
+    break;
+
+  case 231:
+/* Line 1792 of yacc.c  */
+#line 1648 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(3, 3);
+#endif
+    }
+    break;
+
+  case 232:
+/* Line 1792 of yacc.c  */
+#line 1656 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(4, 4);
+#endif
+    }
+    break;
+
+  case 233:
+/* Line 1792 of yacc.c  */
+#line 1664 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(2, 2);
+#endif
+    }
+    break;
+
+  case 234:
+/* Line 1792 of yacc.c  */
+#line 1672 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(2, 3);
+#endif
+    }
+    break;
+
+  case 235:
+/* Line 1792 of yacc.c  */
+#line 1680 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(2, 4);
+#endif
+    }
+    break;
+
+  case 236:
+/* Line 1792 of yacc.c  */
+#line 1688 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(3, 2);
+#endif
+    }
+    break;
+
+  case 237:
+/* Line 1792 of yacc.c  */
+#line 1696 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(3, 3);
+#endif
+    }
+    break;
+
+  case 238:
+/* Line 1792 of yacc.c  */
+#line 1704 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(3, 4);
+#endif
+    }
+    break;
+
+  case 239:
+/* Line 1792 of yacc.c  */
+#line 1712 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(4, 2);
+#endif
+    }
+    break;
+
+  case 240:
+/* Line 1792 of yacc.c  */
+#line 1720 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(4, 3);
+#endif
+    }
+    break;
+
+  case 241:
+/* Line 1792 of yacc.c  */
+#line 1728 "glslang.y"
+    {
+#ifdef AMD_EXTENSIONS
+        parseContext.float16Check((yyvsp[(1) - (1)].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtFloat16;
+        (yyval.interm.type).setMatrix(4, 4);
+#endif
+    }
+    break;
+
+  case 242:
+/* Line 1792 of yacc.c  */
+#line 1736 "glslang.y"
+    {
+        parseContext.vulkanRemoved((yyvsp[(1) - (1)].lex).loc, "atomic counter types");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtAtomicUint;
+    }
+    break;
+
+  case 243:
+/* Line 1792 of yacc.c  */
+#line 1741 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd1D);
+    }
+    break;
+
+  case 244:
+/* Line 1792 of yacc.c  */
+#line 1746 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D);
+    }
+    break;
+
+  case 245:
+/* Line 1792 of yacc.c  */
+#line 1751 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd3D);
+    }
+    break;
+
+  case 246:
+/* Line 1792 of yacc.c  */
+#line 1756 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdCube);
+    }
+    break;
+
+  case 247:
+/* Line 1792 of yacc.c  */
+#line 1761 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true);
+    }
+    break;
+
+  case 248:
+/* Line 1792 of yacc.c  */
+#line 1766 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true);
+    }
+    break;
+
+  case 249:
+/* Line 1792 of yacc.c  */
+#line 1771 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true);
+    }
+    break;
+
+  case 250:
+/* Line 1792 of yacc.c  */
+#line 1776 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true);
+    }
+    break;
+
+  case 251:
+/* Line 1792 of yacc.c  */
+#line 1781 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true);
+    }
+    break;
+
+  case 252:
+/* Line 1792 of yacc.c  */
+#line 1786 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true);
+    }
+    break;
+
+  case 253:
+/* Line 1792 of yacc.c  */
+#line 1791 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true);
+    }
+    break;
+
+  case 254:
+/* Line 1792 of yacc.c  */
+#line 1796 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true);
+    }
+    break;
+
+  case 255:
+/* Line 1792 of yacc.c  */
+#line 1801 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true);
+    }
+    break;
+
+  case 256:
+/* Line 1792 of yacc.c  */
+#line 1806 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd1D);
+    }
+    break;
+
+  case 257:
+/* Line 1792 of yacc.c  */
+#line 1811 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd2D);
+    }
+    break;
+
+  case 258:
+/* Line 1792 of yacc.c  */
+#line 1816 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd3D);
+    }
+    break;
+
+  case 259:
+/* Line 1792 of yacc.c  */
+#line 1821 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, EsdCube);
+    }
+    break;
+
+  case 260:
+/* Line 1792 of yacc.c  */
+#line 1826 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd1D, true);
+    }
+    break;
+
+  case 261:
+/* Line 1792 of yacc.c  */
+#line 1831 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd2D, true);
+    }
+    break;
+
+  case 262:
+/* Line 1792 of yacc.c  */
+#line 1836 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, EsdCube, true);
+    }
+    break;
+
+  case 263:
+/* Line 1792 of yacc.c  */
+#line 1841 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd1D);
+    }
+    break;
+
+  case 264:
+/* Line 1792 of yacc.c  */
+#line 1846 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd2D);
+    }
+    break;
+
+  case 265:
+/* Line 1792 of yacc.c  */
+#line 1851 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd3D);
+    }
+    break;
+
+  case 266:
+/* Line 1792 of yacc.c  */
+#line 1856 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, EsdCube);
+    }
+    break;
+
+  case 267:
+/* Line 1792 of yacc.c  */
+#line 1861 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd1D, true);
+    }
+    break;
+
+  case 268:
+/* Line 1792 of yacc.c  */
+#line 1866 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd2D, true);
+    }
+    break;
+
+  case 269:
+/* Line 1792 of yacc.c  */
+#line 1871 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, EsdCube, true);
+    }
+    break;
+
+  case 270:
+/* Line 1792 of yacc.c  */
+#line 1876 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdRect);
+    }
+    break;
+
+  case 271:
+/* Line 1792 of yacc.c  */
+#line 1881 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true);
+    }
+    break;
+
+  case 272:
+/* Line 1792 of yacc.c  */
+#line 1886 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, EsdRect);
+    }
+    break;
+
+  case 273:
+/* Line 1792 of yacc.c  */
+#line 1891 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, EsdRect);
+    }
+    break;
+
+  case 274:
+/* Line 1792 of yacc.c  */
+#line 1896 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer);
+    }
+    break;
+
+  case 275:
+/* Line 1792 of yacc.c  */
+#line 1901 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, EsdBuffer);
+    }
+    break;
+
+  case 276:
+/* Line 1792 of yacc.c  */
+#line 1906 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, EsdBuffer);
+    }
+    break;
+
+  case 277:
+/* Line 1792 of yacc.c  */
+#line 1911 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true);
+    }
+    break;
+
+  case 278:
+/* Line 1792 of yacc.c  */
+#line 1916 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true);
+    }
+    break;
+
+  case 279:
+/* Line 1792 of yacc.c  */
+#line 1921 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true);
+    }
+    break;
+
+  case 280:
+/* Line 1792 of yacc.c  */
+#line 1926 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true);
+    }
+    break;
+
+  case 281:
+/* Line 1792 of yacc.c  */
+#line 1931 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true);
+    }
+    break;
+
+  case 282:
+/* Line 1792 of yacc.c  */
+#line 1936 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true);
+    }
+    break;
+
+  case 283:
+/* Line 1792 of yacc.c  */
+#line 1941 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setPureSampler(false);
+    }
+    break;
+
+  case 284:
+/* Line 1792 of yacc.c  */
+#line 1946 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setPureSampler(true);
+    }
+    break;
+
+  case 285:
+/* Line 1792 of yacc.c  */
+#line 1951 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D);
+    }
+    break;
+
+  case 286:
+/* Line 1792 of yacc.c  */
+#line 1956 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D);
+    }
+    break;
+
+  case 287:
+/* Line 1792 of yacc.c  */
+#line 1961 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd3D);
+    }
+    break;
+
+  case 288:
+/* Line 1792 of yacc.c  */
+#line 1966 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube);
+    }
+    break;
+
+  case 289:
+/* Line 1792 of yacc.c  */
+#line 1971 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D, true);
+    }
+    break;
+
+  case 290:
+/* Line 1792 of yacc.c  */
+#line 1976 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true);
+    }
+    break;
+
+  case 291:
+/* Line 1792 of yacc.c  */
+#line 1981 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube, true);
+    }
+    break;
+
+  case 292:
+/* Line 1792 of yacc.c  */
+#line 1986 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D);
+    }
+    break;
+
+  case 293:
+/* Line 1792 of yacc.c  */
+#line 1991 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D);
+    }
+    break;
+
+  case 294:
+/* Line 1792 of yacc.c  */
+#line 1996 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd3D);
+    }
+    break;
+
+  case 295:
+/* Line 1792 of yacc.c  */
+#line 2001 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube);
+    }
+    break;
+
+  case 296:
+/* Line 1792 of yacc.c  */
+#line 2006 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D, true);
+    }
+    break;
+
+  case 297:
+/* Line 1792 of yacc.c  */
+#line 2011 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true);
+    }
+    break;
+
+  case 298:
+/* Line 1792 of yacc.c  */
+#line 2016 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube, true);
+    }
+    break;
+
+  case 299:
+/* Line 1792 of yacc.c  */
+#line 2021 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D);
+    }
+    break;
+
+  case 300:
+/* Line 1792 of yacc.c  */
+#line 2026 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D);
+    }
+    break;
+
+  case 301:
+/* Line 1792 of yacc.c  */
+#line 2031 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd3D);
+    }
+    break;
+
+  case 302:
+/* Line 1792 of yacc.c  */
+#line 2036 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube);
+    }
+    break;
+
+  case 303:
+/* Line 1792 of yacc.c  */
+#line 2041 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D, true);
+    }
+    break;
+
+  case 304:
+/* Line 1792 of yacc.c  */
+#line 2046 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true);
+    }
+    break;
+
+  case 305:
+/* Line 1792 of yacc.c  */
+#line 2051 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube, true);
+    }
+    break;
+
+  case 306:
+/* Line 1792 of yacc.c  */
+#line 2056 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, EsdRect);
+    }
+    break;
+
+  case 307:
+/* Line 1792 of yacc.c  */
+#line 2061 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, EsdRect);
+    }
+    break;
+
+  case 308:
+/* Line 1792 of yacc.c  */
+#line 2066 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, EsdRect);
+    }
+    break;
+
+  case 309:
+/* Line 1792 of yacc.c  */
+#line 2071 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, EsdBuffer);
+    }
+    break;
+
+  case 310:
+/* Line 1792 of yacc.c  */
+#line 2076 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, EsdBuffer);
+    }
+    break;
+
+  case 311:
+/* Line 1792 of yacc.c  */
+#line 2081 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, EsdBuffer);
+    }
+    break;
+
+  case 312:
+/* Line 1792 of yacc.c  */
+#line 2086 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, false, false, true);
+    }
+    break;
+
+  case 313:
+/* Line 1792 of yacc.c  */
+#line 2091 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, false, false, true);
+    }
+    break;
+
+  case 314:
+/* Line 1792 of yacc.c  */
+#line 2096 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, false, false, true);
+    }
+    break;
+
+  case 315:
+/* Line 1792 of yacc.c  */
+#line 2101 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true, false, true);
+    }
+    break;
+
+  case 316:
+/* Line 1792 of yacc.c  */
+#line 2106 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true, false, true);
+    }
+    break;
+
+  case 317:
+/* Line 1792 of yacc.c  */
+#line 2111 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true, false, true);
+    }
+    break;
+
+  case 318:
+/* Line 1792 of yacc.c  */
+#line 2116 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D);
+    }
+    break;
+
+  case 319:
+/* Line 1792 of yacc.c  */
+#line 2121 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd1D);
+    }
+    break;
+
+  case 320:
+/* Line 1792 of yacc.c  */
+#line 2126 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd1D);
+    }
+    break;
+
+  case 321:
+/* Line 1792 of yacc.c  */
+#line 2131 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D);
+    }
+    break;
+
+  case 322:
+/* Line 1792 of yacc.c  */
+#line 2136 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd2D);
+    }
+    break;
+
+  case 323:
+/* Line 1792 of yacc.c  */
+#line 2141 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd2D);
+    }
+    break;
+
+  case 324:
+/* Line 1792 of yacc.c  */
+#line 2146 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D);
+    }
+    break;
+
+  case 325:
+/* Line 1792 of yacc.c  */
+#line 2151 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd3D);
+    }
+    break;
+
+  case 326:
+/* Line 1792 of yacc.c  */
+#line 2156 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd3D);
+    }
+    break;
+
+  case 327:
+/* Line 1792 of yacc.c  */
+#line 2161 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect);
+    }
+    break;
+
+  case 328:
+/* Line 1792 of yacc.c  */
+#line 2166 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, EsdRect);
+    }
+    break;
+
+  case 329:
+/* Line 1792 of yacc.c  */
+#line 2171 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, EsdRect);
+    }
+    break;
+
+  case 330:
+/* Line 1792 of yacc.c  */
+#line 2176 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube);
+    }
+    break;
+
+  case 331:
+/* Line 1792 of yacc.c  */
+#line 2181 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, EsdCube);
+    }
+    break;
+
+  case 332:
+/* Line 1792 of yacc.c  */
+#line 2186 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, EsdCube);
+    }
+    break;
+
+  case 333:
+/* Line 1792 of yacc.c  */
+#line 2191 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer);
+    }
+    break;
+
+  case 334:
+/* Line 1792 of yacc.c  */
+#line 2196 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer);
+    }
+    break;
+
+  case 335:
+/* Line 1792 of yacc.c  */
+#line 2201 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer);
+    }
+    break;
+
+  case 336:
+/* Line 1792 of yacc.c  */
+#line 2206 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true);
+    }
+    break;
+
+  case 337:
+/* Line 1792 of yacc.c  */
+#line 2211 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true);
+    }
+    break;
+
+  case 338:
+/* Line 1792 of yacc.c  */
+#line 2216 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true);
+    }
+    break;
+
+  case 339:
+/* Line 1792 of yacc.c  */
+#line 2221 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true);
+    }
+    break;
+
+  case 340:
+/* Line 1792 of yacc.c  */
+#line 2226 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true);
+    }
+    break;
+
+  case 341:
+/* Line 1792 of yacc.c  */
+#line 2231 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true);
+    }
+    break;
+
+  case 342:
+/* Line 1792 of yacc.c  */
+#line 2236 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true);
+    }
+    break;
+
+  case 343:
+/* Line 1792 of yacc.c  */
+#line 2241 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true);
+    }
+    break;
+
+  case 344:
+/* Line 1792 of yacc.c  */
+#line 2246 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true);
+    }
+    break;
+
+  case 345:
+/* Line 1792 of yacc.c  */
+#line 2251 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true);
+    }
+    break;
+
+  case 346:
+/* Line 1792 of yacc.c  */
+#line 2256 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true);
+    }
+    break;
+
+  case 347:
+/* Line 1792 of yacc.c  */
+#line 2261 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true);
+    }
+    break;
+
+  case 348:
+/* Line 1792 of yacc.c  */
+#line 2266 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true);
+    }
+    break;
+
+  case 349:
+/* Line 1792 of yacc.c  */
+#line 2271 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true);
+    }
+    break;
+
+  case 350:
+/* Line 1792 of yacc.c  */
+#line 2276 "glslang.y"
+    {
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true);
+    }
+    break;
+
+  case 351:
+/* Line 1792 of yacc.c  */
+#line 2281 "glslang.y"
+    {  // GL_OES_EGL_image_external
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.set(EbtFloat, Esd2D);
+        (yyval.interm.type).sampler.external = true;
+    }
+    break;
+
+  case 352:
+/* Line 1792 of yacc.c  */
+#line 2287 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtFloat);
+    }
+    break;
+
+  case 353:
+/* Line 1792 of yacc.c  */
+#line 2293 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtFloat, true);
+    }
+    break;
+
+  case 354:
+/* Line 1792 of yacc.c  */
+#line 2299 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtInt);
+    }
+    break;
+
+  case 355:
+/* Line 1792 of yacc.c  */
+#line 2305 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtInt, true);
+    }
+    break;
+
+  case 356:
+/* Line 1792 of yacc.c  */
+#line 2311 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtUint);
+    }
+    break;
+
+  case 357:
+/* Line 1792 of yacc.c  */
+#line 2317 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (1)].lex).loc, EShLangFragment, "subpass input");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        (yyval.interm.type).basicType = EbtSampler;
+        (yyval.interm.type).sampler.setSubpass(EbtUint, true);
+    }
+    break;
+
+  case 358:
+/* Line 1792 of yacc.c  */
+#line 2323 "glslang.y"
+    {
+        (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+        (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+        parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type));
+    }
+    break;
+
+  case 359:
+/* Line 1792 of yacc.c  */
+#line 2328 "glslang.y"
+    {
+        //
+        // This is for user defined type names.  The lexical phase looked up the
+        // type.
+        //
+        if (const TVariable* variable = ((yyvsp[(1) - (1)].lex).symbol)->getAsVariable()) {
+            const TType& structure = variable->getType();
+            (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+            (yyval.interm.type).basicType = EbtStruct;
+            (yyval.interm.type).userDef = &structure;
+        } else
+            parseContext.error((yyvsp[(1) - (1)].lex).loc, "expected type name", (yyvsp[(1) - (1)].lex).string->c_str(), "");
+    }
+    break;
+
+  case 360:
+/* Line 1792 of yacc.c  */
+#line 2344 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "highp precision qualifier");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        parseContext.handlePrecisionQualifier((yyvsp[(1) - (1)].lex).loc, (yyval.interm.type).qualifier, EpqHigh);
+    }
+    break;
+
+  case 361:
+/* Line 1792 of yacc.c  */
+#line 2349 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        parseContext.handlePrecisionQualifier((yyvsp[(1) - (1)].lex).loc, (yyval.interm.type).qualifier, EpqMedium);
+    }
+    break;
+
+  case 362:
+/* Line 1792 of yacc.c  */
+#line 2354 "glslang.y"
+    {
+        parseContext.profileRequires((yyvsp[(1) - (1)].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier");
+        (yyval.interm.type).init((yyvsp[(1) - (1)].lex).loc, parseContext.symbolTable.atGlobalLevel());
+        parseContext.handlePrecisionQualifier((yyvsp[(1) - (1)].lex).loc, (yyval.interm.type).qualifier, EpqLow);
+    }
+    break;
+
+  case 363:
+/* Line 1792 of yacc.c  */
+#line 2362 "glslang.y"
+    { parseContext.nestedStructCheck((yyvsp[(1) - (3)].lex).loc); }
+    break;
+
+  case 364:
+/* Line 1792 of yacc.c  */
+#line 2362 "glslang.y"
+    {
+        TType* structure = new TType((yyvsp[(5) - (6)].interm.typeList), *(yyvsp[(2) - (6)].lex).string);
+        parseContext.structArrayCheck((yyvsp[(2) - (6)].lex).loc, *structure);
+        TVariable* userTypeDef = new TVariable((yyvsp[(2) - (6)].lex).string, *structure, true);
+        if (! parseContext.symbolTable.insert(*userTypeDef))
+            parseContext.error((yyvsp[(2) - (6)].lex).loc, "redefinition", (yyvsp[(2) - (6)].lex).string->c_str(), "struct");
+        (yyval.interm.type).init((yyvsp[(1) - (6)].lex).loc);
+        (yyval.interm.type).basicType = EbtStruct;
+        (yyval.interm.type).userDef = structure;
+        --parseContext.structNestingLevel;
+    }
+    break;
+
+  case 365:
+/* Line 1792 of yacc.c  */
+#line 2373 "glslang.y"
+    { parseContext.nestedStructCheck((yyvsp[(1) - (2)].lex).loc); }
+    break;
+
+  case 366:
+/* Line 1792 of yacc.c  */
+#line 2373 "glslang.y"
+    {
+        TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), TString(""));
+        (yyval.interm.type).init((yyvsp[(1) - (5)].lex).loc);
+        (yyval.interm.type).basicType = EbtStruct;
+        (yyval.interm.type).userDef = structure;
+        --parseContext.structNestingLevel;
+    }
+    break;
+
+  case 367:
+/* Line 1792 of yacc.c  */
+#line 2383 "glslang.y"
+    {
+        (yyval.interm.typeList) = (yyvsp[(1) - (1)].interm.typeList);
+    }
+    break;
+
+  case 368:
+/* Line 1792 of yacc.c  */
+#line 2386 "glslang.y"
+    {
+        (yyval.interm.typeList) = (yyvsp[(1) - (2)].interm.typeList);
+        for (unsigned int i = 0; i < (yyvsp[(2) - (2)].interm.typeList)->size(); ++i) {
+            for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) {
+                if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName())
+                    parseContext.error((*(yyvsp[(2) - (2)].interm.typeList))[i].loc, "duplicate member name:", "", (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName().c_str());
+            }
+            (yyval.interm.typeList)->push_back((*(yyvsp[(2) - (2)].interm.typeList))[i]);
+        }
+    }
+    break;
+
+  case 369:
+/* Line 1792 of yacc.c  */
+#line 2399 "glslang.y"
+    {
+        if ((yyvsp[(1) - (3)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(1) - (3)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(1) - (3)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+            if (parseContext.profile == EEsProfile)
+                parseContext.arraySizeRequiredCheck((yyvsp[(1) - (3)].interm.type).loc, *(yyvsp[(1) - (3)].interm.type).arraySizes);
+        }
+
+        (yyval.interm.typeList) = (yyvsp[(2) - (3)].interm.typeList);
+
+        parseContext.voidErrorCheck((yyvsp[(1) - (3)].interm.type).loc, (*(yyvsp[(2) - (3)].interm.typeList))[0].type->getFieldName(), (yyvsp[(1) - (3)].interm.type).basicType);
+        parseContext.precisionQualifierCheck((yyvsp[(1) - (3)].interm.type).loc, (yyvsp[(1) - (3)].interm.type).basicType, (yyvsp[(1) - (3)].interm.type).qualifier);
+
+        for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) {
+            parseContext.arrayDimCheck((yyvsp[(1) - (3)].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[(1) - (3)].interm.type).arraySizes);
+            (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[(1) - (3)].interm.type));
+        }
+    }
+    break;
+
+  case 370:
+/* Line 1792 of yacc.c  */
+#line 2417 "glslang.y"
+    {
+        parseContext.globalQualifierFixCheck((yyvsp[(1) - (4)].interm.type).loc, (yyvsp[(1) - (4)].interm.type).qualifier);
+        if ((yyvsp[(2) - (4)].interm.type).arraySizes) {
+            parseContext.profileRequires((yyvsp[(2) - (4)].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
+            parseContext.profileRequires((yyvsp[(2) - (4)].interm.type).loc, EEsProfile, 300, 0, "arrayed type");
+            if (parseContext.profile == EEsProfile)
+                parseContext.arraySizeRequiredCheck((yyvsp[(2) - (4)].interm.type).loc, *(yyvsp[(2) - (4)].interm.type).arraySizes);
+        }
+
+        (yyval.interm.typeList) = (yyvsp[(3) - (4)].interm.typeList);
+
+        parseContext.checkNoShaderLayouts((yyvsp[(1) - (4)].interm.type).loc, (yyvsp[(1) - (4)].interm.type).shaderQualifiers);
+        parseContext.voidErrorCheck((yyvsp[(2) - (4)].interm.type).loc, (*(yyvsp[(3) - (4)].interm.typeList))[0].type->getFieldName(), (yyvsp[(2) - (4)].interm.type).basicType);
+        parseContext.mergeQualifiers((yyvsp[(2) - (4)].interm.type).loc, (yyvsp[(2) - (4)].interm.type).qualifier, (yyvsp[(1) - (4)].interm.type).qualifier, true);
+        parseContext.precisionQualifierCheck((yyvsp[(2) - (4)].interm.type).loc, (yyvsp[(2) - (4)].interm.type).basicType, (yyvsp[(2) - (4)].interm.type).qualifier);
+
+        for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) {
+            parseContext.arrayDimCheck((yyvsp[(1) - (4)].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[(2) - (4)].interm.type).arraySizes);
+            (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[(2) - (4)].interm.type));
+        }
+    }
+    break;
+
+  case 371:
+/* Line 1792 of yacc.c  */
+#line 2441 "glslang.y"
+    {
+        (yyval.interm.typeList) = new TTypeList;
+        (yyval.interm.typeList)->push_back((yyvsp[(1) - (1)].interm.typeLine));
+    }
+    break;
+
+  case 372:
+/* Line 1792 of yacc.c  */
+#line 2445 "glslang.y"
+    {
+        (yyval.interm.typeList)->push_back((yyvsp[(3) - (3)].interm.typeLine));
+    }
+    break;
+
+  case 373:
+/* Line 1792 of yacc.c  */
+#line 2451 "glslang.y"
+    {
+        (yyval.interm.typeLine).type = new TType(EbtVoid);
+        (yyval.interm.typeLine).loc = (yyvsp[(1) - (1)].lex).loc;
+        (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (1)].lex).string);
+    }
+    break;
+
+  case 374:
+/* Line 1792 of yacc.c  */
+#line 2456 "glslang.y"
+    {
+        parseContext.arrayDimCheck((yyvsp[(1) - (2)].lex).loc, (yyvsp[(2) - (2)].interm).arraySizes, 0);
+
+        (yyval.interm.typeLine).type = new TType(EbtVoid);
+        (yyval.interm.typeLine).loc = (yyvsp[(1) - (2)].lex).loc;
+        (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (2)].lex).string);
+        (yyval.interm.typeLine).type->newArraySizes(*(yyvsp[(2) - (2)].interm).arraySizes);
+    }
+    break;
+
+  case 375:
+/* Line 1792 of yacc.c  */
+#line 2467 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 376:
+/* Line 1792 of yacc.c  */
+#line 2470 "glslang.y"
+    {
+        const char* initFeature = "{ } style initializers";
+        parseContext.requireProfile((yyvsp[(1) - (3)].lex).loc, ~EEsProfile, initFeature);
+        parseContext.profileRequires((yyvsp[(1) - (3)].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
+        (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 377:
+/* Line 1792 of yacc.c  */
+#line 2476 "glslang.y"
+    {
+        const char* initFeature = "{ } style initializers";
+        parseContext.requireProfile((yyvsp[(1) - (4)].lex).loc, ~EEsProfile, initFeature);
+        parseContext.profileRequires((yyvsp[(1) - (4)].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
+        (yyval.interm.intermTypedNode) = (yyvsp[(2) - (4)].interm.intermTypedNode);
+    }
+    break;
+
+  case 378:
+/* Line 1792 of yacc.c  */
+#line 2485 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[(1) - (1)].interm.intermTypedNode), (yyvsp[(1) - (1)].interm.intermTypedNode)->getLoc());
+    }
+    break;
+
+  case 379:
+/* Line 1792 of yacc.c  */
+#line 2488 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode));
+    }
+    break;
+
+  case 380:
+/* Line 1792 of yacc.c  */
+#line 2494 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 381:
+/* Line 1792 of yacc.c  */
+#line 2498 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 382:
+/* Line 1792 of yacc.c  */
+#line 2499 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 383:
+/* Line 1792 of yacc.c  */
+#line 2505 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 384:
+/* Line 1792 of yacc.c  */
+#line 2506 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 385:
+/* Line 1792 of yacc.c  */
+#line 2507 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 386:
+/* Line 1792 of yacc.c  */
+#line 2508 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 387:
+/* Line 1792 of yacc.c  */
+#line 2509 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 388:
+/* Line 1792 of yacc.c  */
+#line 2510 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 389:
+/* Line 1792 of yacc.c  */
+#line 2511 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 390:
+/* Line 1792 of yacc.c  */
+#line 2515 "glslang.y"
+    { (yyval.interm.intermNode) = 0; }
+    break;
+
+  case 391:
+/* Line 1792 of yacc.c  */
+#line 2516 "glslang.y"
+    {
+        parseContext.symbolTable.push();
+        ++parseContext.statementNestingLevel;
+    }
+    break;
+
+  case 392:
+/* Line 1792 of yacc.c  */
+#line 2520 "glslang.y"
+    {
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        --parseContext.statementNestingLevel;
+    }
+    break;
+
+  case 393:
+/* Line 1792 of yacc.c  */
+#line 2524 "glslang.y"
+    {
+        if ((yyvsp[(3) - (5)].interm.intermNode) && (yyvsp[(3) - (5)].interm.intermNode)->getAsAggregate())
+            (yyvsp[(3) - (5)].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence);
+        (yyval.interm.intermNode) = (yyvsp[(3) - (5)].interm.intermNode);
+    }
+    break;
+
+  case 394:
+/* Line 1792 of yacc.c  */
+#line 2532 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 395:
+/* Line 1792 of yacc.c  */
+#line 2533 "glslang.y"
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+    break;
+
+  case 396:
+/* Line 1792 of yacc.c  */
+#line 2537 "glslang.y"
+    {
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 397:
+/* Line 1792 of yacc.c  */
+#line 2540 "glslang.y"
+    {
+        --parseContext.controlFlowNestingLevel;
+        (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode);
+    }
+    break;
+
+  case 398:
+/* Line 1792 of yacc.c  */
+#line 2544 "glslang.y"
+    {
+        parseContext.symbolTable.push();
+        ++parseContext.statementNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 399:
+/* Line 1792 of yacc.c  */
+#line 2549 "glslang.y"
+    {
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        --parseContext.statementNestingLevel;
+        --parseContext.controlFlowNestingLevel;
+        (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode);
+    }
+    break;
+
+  case 400:
+/* Line 1792 of yacc.c  */
+#line 2558 "glslang.y"
+    {
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 401:
+/* Line 1792 of yacc.c  */
+#line 2561 "glslang.y"
+    {
+        if ((yyvsp[(2) - (3)].interm.intermNode) && (yyvsp[(2) - (3)].interm.intermNode)->getAsAggregate())
+            (yyvsp[(2) - (3)].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence);
+        (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermNode);
+    }
+    break;
+
+  case 402:
+/* Line 1792 of yacc.c  */
+#line 2569 "glslang.y"
+    {
+        (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode));
+        if ((yyvsp[(1) - (1)].interm.intermNode) && (yyvsp[(1) - (1)].interm.intermNode)->getAsBranchNode() && ((yyvsp[(1) - (1)].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase ||
+                                            (yyvsp[(1) - (1)].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) {
+            parseContext.wrapupSwitchSubsequence(0, (yyvsp[(1) - (1)].interm.intermNode));
+            (yyval.interm.intermNode) = 0;  // start a fresh subsequence for what's after this case
+        }
+    }
+    break;
+
+  case 403:
+/* Line 1792 of yacc.c  */
+#line 2577 "glslang.y"
+    {
+        if ((yyvsp[(2) - (2)].interm.intermNode) && (yyvsp[(2) - (2)].interm.intermNode)->getAsBranchNode() && ((yyvsp[(2) - (2)].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase ||
+                                            (yyvsp[(2) - (2)].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) {
+            parseContext.wrapupSwitchSubsequence((yyvsp[(1) - (2)].interm.intermNode) ? (yyvsp[(1) - (2)].interm.intermNode)->getAsAggregate() : 0, (yyvsp[(2) - (2)].interm.intermNode));
+            (yyval.interm.intermNode) = 0;  // start a fresh subsequence for what's after this case
+        } else
+            (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode));
+    }
+    break;
+
+  case 404:
+/* Line 1792 of yacc.c  */
+#line 2588 "glslang.y"
+    { (yyval.interm.intermNode) = 0; }
+    break;
+
+  case 405:
+/* Line 1792 of yacc.c  */
+#line 2589 "glslang.y"
+    { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); }
+    break;
+
+  case 406:
+/* Line 1792 of yacc.c  */
+#line 2593 "glslang.y"
+    {
+        parseContext.boolCheck((yyvsp[(1) - (5)].lex).loc, (yyvsp[(3) - (5)].interm.intermTypedNode));
+        (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yyvsp[(1) - (5)].lex).loc);
+    }
+    break;
+
+  case 407:
+/* Line 1792 of yacc.c  */
+#line 2600 "glslang.y"
+    {
+        (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode);
+        (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode);
+    }
+    break;
+
+  case 408:
+/* Line 1792 of yacc.c  */
+#line 2604 "glslang.y"
+    {
+        (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode);
+        (yyval.interm.nodePair).node2 = 0;
+    }
+    break;
+
+  case 409:
+/* Line 1792 of yacc.c  */
+#line 2612 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+        parseContext.boolCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLoc(), (yyvsp[(1) - (1)].interm.intermTypedNode));
+    }
+    break;
+
+  case 410:
+/* Line 1792 of yacc.c  */
+#line 2616 "glslang.y"
+    {
+        parseContext.boolCheck((yyvsp[(2) - (4)].lex).loc, (yyvsp[(1) - (4)].interm.type));
+
+        TType type((yyvsp[(1) - (4)].interm.type));
+        TIntermNode* initNode = parseContext.declareVariable((yyvsp[(2) - (4)].lex).loc, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), 0, (yyvsp[(4) - (4)].interm.intermTypedNode));
+        if (initNode)
+            (yyval.interm.intermTypedNode) = initNode->getAsTyped();
+        else
+            (yyval.interm.intermTypedNode) = 0;
+    }
+    break;
+
+  case 411:
+/* Line 1792 of yacc.c  */
+#line 2629 "glslang.y"
+    {
+        // start new switch sequence on the switch stack
+        ++parseContext.controlFlowNestingLevel;
+        ++parseContext.statementNestingLevel;
+        parseContext.switchSequenceStack.push_back(new TIntermSequence);
+        parseContext.switchLevel.push_back(parseContext.statementNestingLevel);
+        parseContext.symbolTable.push();
+    }
+    break;
+
+  case 412:
+/* Line 1792 of yacc.c  */
+#line 2637 "glslang.y"
+    {
+        (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[(1) - (8)].lex).loc, (yyvsp[(3) - (8)].interm.intermTypedNode), (yyvsp[(7) - (8)].interm.intermNode) ? (yyvsp[(7) - (8)].interm.intermNode)->getAsAggregate() : 0);
+        delete parseContext.switchSequenceStack.back();
+        parseContext.switchSequenceStack.pop_back();
+        parseContext.switchLevel.pop_back();
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        --parseContext.statementNestingLevel;
+        --parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 413:
+/* Line 1792 of yacc.c  */
+#line 2649 "glslang.y"
+    {
+        (yyval.interm.intermNode) = 0;
+    }
+    break;
+
+  case 414:
+/* Line 1792 of yacc.c  */
+#line 2652 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    }
+    break;
+
+  case 415:
+/* Line 1792 of yacc.c  */
+#line 2658 "glslang.y"
+    {
+        (yyval.interm.intermNode) = 0;
+        if (parseContext.switchLevel.size() == 0)
+            parseContext.error((yyvsp[(1) - (3)].lex).loc, "cannot appear outside switch statement", "case", "");
+        else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel)
+            parseContext.error((yyvsp[(1) - (3)].lex).loc, "cannot be nested inside control flow", "case", "");
+        else {
+            parseContext.constantValueCheck((yyvsp[(2) - (3)].interm.intermTypedNode), "case");
+            parseContext.integerCheck((yyvsp[(2) - (3)].interm.intermTypedNode), "case");
+            (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[(2) - (3)].interm.intermTypedNode), (yyvsp[(1) - (3)].lex).loc);
+        }
+    }
+    break;
+
+  case 416:
+/* Line 1792 of yacc.c  */
+#line 2670 "glslang.y"
+    {
+        (yyval.interm.intermNode) = 0;
+        if (parseContext.switchLevel.size() == 0)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "cannot appear outside switch statement", "default", "");
+        else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "cannot be nested inside control flow", "default", "");
+        else
+            (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[(1) - (2)].lex).loc);
+    }
+    break;
+
+  case 417:
+/* Line 1792 of yacc.c  */
+#line 2682 "glslang.y"
+    {
+        if (! parseContext.limits.whileLoops)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "while loops not available", "limitation", "");
+        parseContext.symbolTable.push();
+        ++parseContext.loopNestingLevel;
+        ++parseContext.statementNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 418:
+/* Line 1792 of yacc.c  */
+#line 2690 "glslang.y"
+    {
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[(6) - (6)].interm.intermNode), (yyvsp[(4) - (6)].interm.intermTypedNode), 0, true, (yyvsp[(1) - (6)].lex).loc);
+        --parseContext.loopNestingLevel;
+        --parseContext.statementNestingLevel;
+        --parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 419:
+/* Line 1792 of yacc.c  */
+#line 2697 "glslang.y"
+    {
+        ++parseContext.loopNestingLevel;
+        ++parseContext.statementNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 420:
+/* Line 1792 of yacc.c  */
+#line 2702 "glslang.y"
+    {
+        if (! parseContext.limits.whileLoops)
+            parseContext.error((yyvsp[(1) - (8)].lex).loc, "do-while loops not available", "limitation", "");
+
+        parseContext.boolCheck((yyvsp[(8) - (8)].lex).loc, (yyvsp[(6) - (8)].interm.intermTypedNode));
+
+        (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[(3) - (8)].interm.intermNode), (yyvsp[(6) - (8)].interm.intermTypedNode), 0, false, (yyvsp[(4) - (8)].lex).loc);
+        --parseContext.loopNestingLevel;
+        --parseContext.statementNestingLevel;
+        --parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 421:
+/* Line 1792 of yacc.c  */
+#line 2713 "glslang.y"
+    {
+        parseContext.symbolTable.push();
+        ++parseContext.loopNestingLevel;
+        ++parseContext.statementNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 422:
+/* Line 1792 of yacc.c  */
+#line 2719 "glslang.y"
+    {
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[(4) - (7)].interm.intermNode), (yyvsp[(2) - (7)].lex).loc);
+        TIntermLoop* forLoop = parseContext.intermediate.addLoop((yyvsp[(7) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), true, (yyvsp[(1) - (7)].lex).loc);
+        if (! parseContext.limits.nonInductiveForLoops)
+            parseContext.inductiveLoopCheck((yyvsp[(1) - (7)].lex).loc, (yyvsp[(4) - (7)].interm.intermNode), forLoop);
+        (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyval.interm.intermNode), forLoop, (yyvsp[(1) - (7)].lex).loc);
+        (yyval.interm.intermNode)->getAsAggregate()->setOperator(EOpSequence);
+        --parseContext.loopNestingLevel;
+        --parseContext.statementNestingLevel;
+        --parseContext.controlFlowNestingLevel;
+    }
+    break;
+
+  case 423:
+/* Line 1792 of yacc.c  */
+#line 2734 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    }
+    break;
+
+  case 424:
+/* Line 1792 of yacc.c  */
+#line 2737 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    }
+    break;
+
+  case 425:
+/* Line 1792 of yacc.c  */
+#line 2743 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    }
+    break;
+
+  case 426:
+/* Line 1792 of yacc.c  */
+#line 2746 "glslang.y"
+    {
+        (yyval.interm.intermTypedNode) = 0;
+    }
+    break;
+
+  case 427:
+/* Line 1792 of yacc.c  */
+#line 2752 "glslang.y"
+    {
+        (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode);
+        (yyval.interm.nodePair).node2 = 0;
+    }
+    break;
+
+  case 428:
+/* Line 1792 of yacc.c  */
+#line 2756 "glslang.y"
+    {
+        (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode);
+        (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode);
+    }
+    break;
+
+  case 429:
+/* Line 1792 of yacc.c  */
+#line 2763 "glslang.y"
+    {
+        if (parseContext.loopNestingLevel <= 0)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "continue statement only allowed in loops", "", "");
+        (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[(1) - (2)].lex).loc);
+    }
+    break;
+
+  case 430:
+/* Line 1792 of yacc.c  */
+#line 2768 "glslang.y"
+    {
+        if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "break statement only allowed in switch and loops", "", "");
+        (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[(1) - (2)].lex).loc);
+    }
+    break;
+
+  case 431:
+/* Line 1792 of yacc.c  */
+#line 2773 "glslang.y"
+    {
+        (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[(1) - (2)].lex).loc);
+        if (parseContext.currentFunctionType->getBasicType() != EbtVoid)
+            parseContext.error((yyvsp[(1) - (2)].lex).loc, "non-void function must return a value", "return", "");
+        if (parseContext.inMain)
+            parseContext.postMainReturn = true;
+    }
+    break;
+
+  case 432:
+/* Line 1792 of yacc.c  */
+#line 2780 "glslang.y"
+    {
+        (yyval.interm.intermNode) = parseContext.handleReturnValue((yyvsp[(1) - (3)].lex).loc, (yyvsp[(2) - (3)].interm.intermTypedNode));
+    }
+    break;
+
+  case 433:
+/* Line 1792 of yacc.c  */
+#line 2783 "glslang.y"
+    {
+        parseContext.requireStage((yyvsp[(1) - (2)].lex).loc, EShLangFragment, "discard");
+        (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[(1) - (2)].lex).loc);
+    }
+    break;
+
+  case 434:
+/* Line 1792 of yacc.c  */
+#line 2792 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+        parseContext.intermediate.setTreeRoot((yyval.interm.intermNode));
+    }
+    break;
+
+  case 435:
+/* Line 1792 of yacc.c  */
+#line 2796 "glslang.y"
+    {
+        (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode));
+        parseContext.intermediate.setTreeRoot((yyval.interm.intermNode));
+    }
+    break;
+
+  case 436:
+/* Line 1792 of yacc.c  */
+#line 2803 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    }
+    break;
+
+  case 437:
+/* Line 1792 of yacc.c  */
+#line 2806 "glslang.y"
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    }
+    break;
+
+  case 438:
+/* Line 1792 of yacc.c  */
+#line 2812 "glslang.y"
+    {
+        (yyvsp[(1) - (1)].interm).function = parseContext.handleFunctionDeclarator((yyvsp[(1) - (1)].interm).loc, *(yyvsp[(1) - (1)].interm).function, false /* not prototype */);
+        (yyvsp[(1) - (1)].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[(1) - (1)].interm).loc, *(yyvsp[(1) - (1)].interm).function);
+    }
+    break;
+
+  case 439:
+/* Line 1792 of yacc.c  */
+#line 2816 "glslang.y"
+    {
+        //   May be best done as post process phase on intermediate code
+        if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue)
+            parseContext.error((yyvsp[(1) - (3)].interm).loc, "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str());
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermNode));
+        parseContext.intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[(1) - (3)].interm).function->getType(), (yyvsp[(1) - (3)].interm).loc);
+        (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str());
+
+        // store the pragma information for debug and optimize and other vendor specific
+        // information. This information can be queried from the parse tree
+        (yyval.interm.intermNode)->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize);
+        (yyval.interm.intermNode)->getAsAggregate()->setDebug(parseContext.contextPragma.debug);
+        (yyval.interm.intermNode)->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable);
+    }
+    break;
+
+
+/* Line 1792 of yacc.c  */
+#line 8088 "glslang_tab.cpp"
+      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;
+
+  /* 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 (pParseContext, 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 (pParseContext, yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+
+
+  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, pParseContext);
+	  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;
+
+  /* Do not reclaim the symbols of the rule which 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;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, pParseContext);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* 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 (pParseContext, 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, pParseContext);
+    }
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, pParseContext);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+/* Line 2055 of yacc.c  */
+#line 2833 "glslang.y"
+

+ 400 - 0
src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h

@@ -0,0 +1,400 @@
+/* A Bison parser, made by GNU Bison 2.7.  */
+
+/* Bison interface for Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989-1990, 2000-2012 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_CPP_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ATTRIBUTE = 258,
+     VARYING = 259,
+     CONST = 260,
+     BOOL = 261,
+     FLOAT = 262,
+     DOUBLE = 263,
+     INT = 264,
+     UINT = 265,
+     INT64_T = 266,
+     UINT64_T = 267,
+     FLOAT16_T = 268,
+     BREAK = 269,
+     CONTINUE = 270,
+     DO = 271,
+     ELSE = 272,
+     FOR = 273,
+     IF = 274,
+     DISCARD = 275,
+     RETURN = 276,
+     SWITCH = 277,
+     CASE = 278,
+     DEFAULT = 279,
+     SUBROUTINE = 280,
+     BVEC2 = 281,
+     BVEC3 = 282,
+     BVEC4 = 283,
+     IVEC2 = 284,
+     IVEC3 = 285,
+     IVEC4 = 286,
+     I64VEC2 = 287,
+     I64VEC3 = 288,
+     I64VEC4 = 289,
+     UVEC2 = 290,
+     UVEC3 = 291,
+     UVEC4 = 292,
+     U64VEC2 = 293,
+     U64VEC3 = 294,
+     U64VEC4 = 295,
+     VEC2 = 296,
+     VEC3 = 297,
+     VEC4 = 298,
+     MAT2 = 299,
+     MAT3 = 300,
+     MAT4 = 301,
+     CENTROID = 302,
+     IN = 303,
+     OUT = 304,
+     INOUT = 305,
+     UNIFORM = 306,
+     PATCH = 307,
+     SAMPLE = 308,
+     BUFFER = 309,
+     SHARED = 310,
+     COHERENT = 311,
+     VOLATILE = 312,
+     RESTRICT = 313,
+     READONLY = 314,
+     WRITEONLY = 315,
+     DVEC2 = 316,
+     DVEC3 = 317,
+     DVEC4 = 318,
+     DMAT2 = 319,
+     DMAT3 = 320,
+     DMAT4 = 321,
+     F16VEC2 = 322,
+     F16VEC3 = 323,
+     F16VEC4 = 324,
+     F16MAT2 = 325,
+     F16MAT3 = 326,
+     F16MAT4 = 327,
+     NOPERSPECTIVE = 328,
+     FLAT = 329,
+     SMOOTH = 330,
+     LAYOUT = 331,
+     __EXPLICITINTERPAMD = 332,
+     MAT2X2 = 333,
+     MAT2X3 = 334,
+     MAT2X4 = 335,
+     MAT3X2 = 336,
+     MAT3X3 = 337,
+     MAT3X4 = 338,
+     MAT4X2 = 339,
+     MAT4X3 = 340,
+     MAT4X4 = 341,
+     DMAT2X2 = 342,
+     DMAT2X3 = 343,
+     DMAT2X4 = 344,
+     DMAT3X2 = 345,
+     DMAT3X3 = 346,
+     DMAT3X4 = 347,
+     DMAT4X2 = 348,
+     DMAT4X3 = 349,
+     DMAT4X4 = 350,
+     F16MAT2X2 = 351,
+     F16MAT2X3 = 352,
+     F16MAT2X4 = 353,
+     F16MAT3X2 = 354,
+     F16MAT3X3 = 355,
+     F16MAT3X4 = 356,
+     F16MAT4X2 = 357,
+     F16MAT4X3 = 358,
+     F16MAT4X4 = 359,
+     ATOMIC_UINT = 360,
+     SAMPLER1D = 361,
+     SAMPLER2D = 362,
+     SAMPLER3D = 363,
+     SAMPLERCUBE = 364,
+     SAMPLER1DSHADOW = 365,
+     SAMPLER2DSHADOW = 366,
+     SAMPLERCUBESHADOW = 367,
+     SAMPLER1DARRAY = 368,
+     SAMPLER2DARRAY = 369,
+     SAMPLER1DARRAYSHADOW = 370,
+     SAMPLER2DARRAYSHADOW = 371,
+     ISAMPLER1D = 372,
+     ISAMPLER2D = 373,
+     ISAMPLER3D = 374,
+     ISAMPLERCUBE = 375,
+     ISAMPLER1DARRAY = 376,
+     ISAMPLER2DARRAY = 377,
+     USAMPLER1D = 378,
+     USAMPLER2D = 379,
+     USAMPLER3D = 380,
+     USAMPLERCUBE = 381,
+     USAMPLER1DARRAY = 382,
+     USAMPLER2DARRAY = 383,
+     SAMPLER2DRECT = 384,
+     SAMPLER2DRECTSHADOW = 385,
+     ISAMPLER2DRECT = 386,
+     USAMPLER2DRECT = 387,
+     SAMPLERBUFFER = 388,
+     ISAMPLERBUFFER = 389,
+     USAMPLERBUFFER = 390,
+     SAMPLERCUBEARRAY = 391,
+     SAMPLERCUBEARRAYSHADOW = 392,
+     ISAMPLERCUBEARRAY = 393,
+     USAMPLERCUBEARRAY = 394,
+     SAMPLER2DMS = 395,
+     ISAMPLER2DMS = 396,
+     USAMPLER2DMS = 397,
+     SAMPLER2DMSARRAY = 398,
+     ISAMPLER2DMSARRAY = 399,
+     USAMPLER2DMSARRAY = 400,
+     SAMPLEREXTERNALOES = 401,
+     SAMPLER = 402,
+     SAMPLERSHADOW = 403,
+     TEXTURE1D = 404,
+     TEXTURE2D = 405,
+     TEXTURE3D = 406,
+     TEXTURECUBE = 407,
+     TEXTURE1DARRAY = 408,
+     TEXTURE2DARRAY = 409,
+     ITEXTURE1D = 410,
+     ITEXTURE2D = 411,
+     ITEXTURE3D = 412,
+     ITEXTURECUBE = 413,
+     ITEXTURE1DARRAY = 414,
+     ITEXTURE2DARRAY = 415,
+     UTEXTURE1D = 416,
+     UTEXTURE2D = 417,
+     UTEXTURE3D = 418,
+     UTEXTURECUBE = 419,
+     UTEXTURE1DARRAY = 420,
+     UTEXTURE2DARRAY = 421,
+     TEXTURE2DRECT = 422,
+     ITEXTURE2DRECT = 423,
+     UTEXTURE2DRECT = 424,
+     TEXTUREBUFFER = 425,
+     ITEXTUREBUFFER = 426,
+     UTEXTUREBUFFER = 427,
+     TEXTURECUBEARRAY = 428,
+     ITEXTURECUBEARRAY = 429,
+     UTEXTURECUBEARRAY = 430,
+     TEXTURE2DMS = 431,
+     ITEXTURE2DMS = 432,
+     UTEXTURE2DMS = 433,
+     TEXTURE2DMSARRAY = 434,
+     ITEXTURE2DMSARRAY = 435,
+     UTEXTURE2DMSARRAY = 436,
+     SUBPASSINPUT = 437,
+     SUBPASSINPUTMS = 438,
+     ISUBPASSINPUT = 439,
+     ISUBPASSINPUTMS = 440,
+     USUBPASSINPUT = 441,
+     USUBPASSINPUTMS = 442,
+     IMAGE1D = 443,
+     IIMAGE1D = 444,
+     UIMAGE1D = 445,
+     IMAGE2D = 446,
+     IIMAGE2D = 447,
+     UIMAGE2D = 448,
+     IMAGE3D = 449,
+     IIMAGE3D = 450,
+     UIMAGE3D = 451,
+     IMAGE2DRECT = 452,
+     IIMAGE2DRECT = 453,
+     UIMAGE2DRECT = 454,
+     IMAGECUBE = 455,
+     IIMAGECUBE = 456,
+     UIMAGECUBE = 457,
+     IMAGEBUFFER = 458,
+     IIMAGEBUFFER = 459,
+     UIMAGEBUFFER = 460,
+     IMAGE1DARRAY = 461,
+     IIMAGE1DARRAY = 462,
+     UIMAGE1DARRAY = 463,
+     IMAGE2DARRAY = 464,
+     IIMAGE2DARRAY = 465,
+     UIMAGE2DARRAY = 466,
+     IMAGECUBEARRAY = 467,
+     IIMAGECUBEARRAY = 468,
+     UIMAGECUBEARRAY = 469,
+     IMAGE2DMS = 470,
+     IIMAGE2DMS = 471,
+     UIMAGE2DMS = 472,
+     IMAGE2DMSARRAY = 473,
+     IIMAGE2DMSARRAY = 474,
+     UIMAGE2DMSARRAY = 475,
+     STRUCT = 476,
+     VOID = 477,
+     WHILE = 478,
+     IDENTIFIER = 479,
+     TYPE_NAME = 480,
+     FLOATCONSTANT = 481,
+     DOUBLECONSTANT = 482,
+     INTCONSTANT = 483,
+     UINTCONSTANT = 484,
+     INT64CONSTANT = 485,
+     UINT64CONSTANT = 486,
+     BOOLCONSTANT = 487,
+     FLOAT16CONSTANT = 488,
+     LEFT_OP = 489,
+     RIGHT_OP = 490,
+     INC_OP = 491,
+     DEC_OP = 492,
+     LE_OP = 493,
+     GE_OP = 494,
+     EQ_OP = 495,
+     NE_OP = 496,
+     AND_OP = 497,
+     OR_OP = 498,
+     XOR_OP = 499,
+     MUL_ASSIGN = 500,
+     DIV_ASSIGN = 501,
+     ADD_ASSIGN = 502,
+     MOD_ASSIGN = 503,
+     LEFT_ASSIGN = 504,
+     RIGHT_ASSIGN = 505,
+     AND_ASSIGN = 506,
+     XOR_ASSIGN = 507,
+     OR_ASSIGN = 508,
+     SUB_ASSIGN = 509,
+     LEFT_PAREN = 510,
+     RIGHT_PAREN = 511,
+     LEFT_BRACKET = 512,
+     RIGHT_BRACKET = 513,
+     LEFT_BRACE = 514,
+     RIGHT_BRACE = 515,
+     DOT = 516,
+     COMMA = 517,
+     COLON = 518,
+     EQUAL = 519,
+     SEMICOLON = 520,
+     BANG = 521,
+     DASH = 522,
+     TILDE = 523,
+     PLUS = 524,
+     STAR = 525,
+     SLASH = 526,
+     PERCENT = 527,
+     LEFT_ANGLE = 528,
+     RIGHT_ANGLE = 529,
+     VERTICAL_BAR = 530,
+     CARET = 531,
+     AMPERSAND = 532,
+     QUESTION = 533,
+     INVARIANT = 534,
+     PRECISE = 535,
+     HIGH_PRECISION = 536,
+     MEDIUM_PRECISION = 537,
+     LOW_PRECISION = 538,
+     PRECISION = 539,
+     PACKED = 540,
+     RESOURCE = 541,
+     SUPERP = 542
+   };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2058 of yacc.c  */
+#line 66 "glslang.y"
+
+    struct {
+        glslang::TSourceLoc loc;
+        union {
+            glslang::TString *string;
+            int i;
+            unsigned int u;
+            long long i64;
+            unsigned long long u64;
+            bool b;
+            double d;
+        };
+        glslang::TSymbol* symbol;
+    } lex;
+    struct {
+        glslang::TSourceLoc loc;
+        glslang::TOperator op;
+        union {
+            TIntermNode* intermNode;
+            glslang::TIntermNodePair nodePair;
+            glslang::TIntermTyped* intermTypedNode;
+        };
+        union {
+            glslang::TPublicType type;
+            glslang::TFunction* function;
+            glslang::TParameter param;
+            glslang::TTypeLoc typeLine;
+            glslang::TTypeList* typeList;
+            glslang::TArraySizes* arraySizes;
+            glslang::TIdentifierList* identifierList;
+        };
+    } interm;
+
+
+/* Line 2058 of yacc.c  */
+#line 379 "glslang_tab.cpp.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (glslang::TParseContext* pParseContext);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_CPP_H_INCLUDED  */

+ 950 - 0
src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp

@@ -0,0 +1,950 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "localintermediate.h"
+#include "../Include/InfoSink.h"
+
+#ifdef _MSC_VER
+#include <cfloat>
+#else
+#include <cmath>
+#endif
+
+namespace {
+
+bool is_positive_infinity(double x) {
+#ifdef _MSC_VER
+  return _fpclass(x) == _FPCLASS_PINF;
+#else
+  return std::isinf(x) && (x >= 0);
+#endif
+}
+
+}
+
+namespace glslang {
+
+//
+// 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(TInfoSink& i) : infoSink(i) { }
+
+    virtual bool visitBinary(TVisit, TIntermBinary* node);
+    virtual bool visitUnary(TVisit, TIntermUnary* node);
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
+    virtual bool visitSelection(TVisit, TIntermSelection* node);
+    virtual void visitConstantUnion(TIntermConstantUnion* node);
+    virtual void visitSymbol(TIntermSymbol* node);
+    virtual bool visitLoop(TVisit, TIntermLoop* node);
+    virtual bool visitBranch(TVisit, TIntermBranch* node);
+    virtual bool visitSwitch(TVisit, TIntermSwitch* node);
+
+    TInfoSink& infoSink;
+protected:
+    TOutputTraverser(TOutputTraverser&);
+    TOutputTraverser& operator=(TOutputTraverser&);
+};
+
+//
+// Helper functions for printing, not part of traversing.
+//
+
+static void OutputTreeText(TInfoSink& infoSink, const TIntermNode* node, const int depth)
+{
+    int i;
+
+    infoSink.debug << node->getLoc().string << ":";
+    if (node->getLoc().line)
+        infoSink.debug << node->getLoc().line;
+    else
+        infoSink.debug << "? ";
+
+    for (i = 0; i < depth; ++i)
+        infoSink.debug << "  ";
+}
+
+//
+// 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.
+//
+
+bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+
+    switch (node->getOp()) {
+    case EOpAssign:                   out.debug << "move second child to first child";           break;
+    case EOpAddAssign:                out.debug << "add second child into first child";          break;
+    case EOpSubAssign:                out.debug << "subtract second child into first child";     break;
+    case EOpMulAssign:                out.debug << "multiply second child into first child";     break;
+    case EOpVectorTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
+    case EOpVectorTimesScalarAssign:  out.debug << "vector scale second child into first child"; break;
+    case EOpMatrixTimesScalarAssign:  out.debug << "matrix scale second child into first child"; break;
+    case EOpMatrixTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
+    case EOpDivAssign:                out.debug << "divide second child into first child";       break;
+    case EOpModAssign:                out.debug << "mod second child into first child";          break;
+    case EOpAndAssign:                out.debug << "and second child into first child";          break;
+    case EOpInclusiveOrAssign:        out.debug << "or second child into first child";           break;
+    case EOpExclusiveOrAssign:        out.debug << "exclusive or second child into first child"; break;
+    case EOpLeftShiftAssign:          out.debug << "left shift second child into first child";   break;
+    case EOpRightShiftAssign:         out.debug << "right shift second child into first child";  break;
+
+    case EOpIndexDirect:   out.debug << "direct index";   break;
+    case EOpIndexIndirect: out.debug << "indirect index"; break;
+    case EOpIndexDirectStruct:
+        out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
+        out.debug << ": direct index for structure";      break;
+    case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
+    case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
+
+    case EOpAdd:    out.debug << "add";                     break;
+    case EOpSub:    out.debug << "subtract";                break;
+    case EOpMul:    out.debug << "component-wise multiply"; break;
+    case EOpDiv:    out.debug << "divide";                  break;
+    case EOpMod:    out.debug << "mod";                     break;
+    case EOpRightShift:  out.debug << "right-shift";  break;
+    case EOpLeftShift:   out.debug << "left-shift";   break;
+    case EOpAnd:         out.debug << "bitwise and";  break;
+    case EOpInclusiveOr: out.debug << "inclusive-or"; break;
+    case EOpExclusiveOr: out.debug << "exclusive-or"; break;
+    case EOpEqual:            out.debug << "Compare Equal";                 break;
+    case EOpNotEqual:         out.debug << "Compare Not Equal";             break;
+    case EOpLessThan:         out.debug << "Compare Less Than";             break;
+    case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
+    case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
+    case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
+    case EOpVectorEqual:      out.debug << "Equal";                         break;
+    case EOpVectorNotEqual:   out.debug << "NotEqual";                      break;
+
+    case EOpVectorTimesScalar: out.debug << "vector-scale";          break;
+    case EOpVectorTimesMatrix: out.debug << "vector-times-matrix";   break;
+    case EOpMatrixTimesVector: out.debug << "matrix-times-vector";   break;
+    case EOpMatrixTimesScalar: out.debug << "matrix-scale";          break;
+    case EOpMatrixTimesMatrix: out.debug << "matrix-multiply";       break;
+
+    case EOpLogicalOr:  out.debug << "logical-or";   break;
+    case EOpLogicalXor: out.debug << "logical-xor"; break;
+    case EOpLogicalAnd: out.debug << "logical-and"; break;
+    default: out.debug << "<unknown op>";
+    }
+
+    out.debug << " (" << node->getCompleteString() << ")";
+
+    out.debug << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+
+    switch (node->getOp()) {
+    case EOpNegative:       out.debug << "Negate value";         break;
+    case EOpVectorLogicalNot:
+    case EOpLogicalNot:     out.debug << "Negate conditional";   break;
+    case EOpBitwiseNot:     out.debug << "Bitwise not";          break;
+
+    case EOpPostIncrement:  out.debug << "Post-Increment";       break;
+    case EOpPostDecrement:  out.debug << "Post-Decrement";       break;
+    case EOpPreIncrement:   out.debug << "Pre-Increment";        break;
+    case EOpPreDecrement:   out.debug << "Pre-Decrement";        break;
+
+    case EOpConvIntToBool:     out.debug << "Convert int to bool";     break;
+    case EOpConvUintToBool:    out.debug << "Convert uint to bool";    break;
+    case EOpConvFloatToBool:   out.debug << "Convert float to bool";   break;
+    case EOpConvDoubleToBool:  out.debug << "Convert double to bool";  break;
+    case EOpConvInt64ToBool:   out.debug << "Convert int64 to bool";   break;
+    case EOpConvUint64ToBool:  out.debug << "Convert uint64 to bool";  break;
+    case EOpConvIntToFloat:    out.debug << "Convert int to float";    break;
+    case EOpConvUintToFloat:   out.debug << "Convert uint to float";   break;
+    case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break;
+    case EOpConvInt64ToFloat:  out.debug << "Convert int64 to float";  break;
+    case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break;
+    case EOpConvBoolToFloat:   out.debug << "Convert bool to float";   break;
+    case EOpConvUintToInt:     out.debug << "Convert uint to int";     break;
+    case EOpConvFloatToInt:    out.debug << "Convert float to int";    break;
+    case EOpConvDoubleToInt:   out.debug << "Convert double to int";   break;
+    case EOpConvBoolToInt:     out.debug << "Convert bool to int";     break;
+    case EOpConvInt64ToInt:    out.debug << "Convert int64 to int";    break;
+    case EOpConvUint64ToInt:   out.debug << "Convert uint64 to int";   break;
+    case EOpConvIntToUint:     out.debug << "Convert int to uint";     break;
+    case EOpConvFloatToUint:   out.debug << "Convert float to uint";   break;
+    case EOpConvDoubleToUint:  out.debug << "Convert double to uint";  break;
+    case EOpConvBoolToUint:    out.debug << "Convert bool to uint";    break;
+    case EOpConvInt64ToUint:   out.debug << "Convert int64 to uint";   break;
+    case EOpConvUint64ToUint:  out.debug << "Convert uint64 to uint";  break;
+    case EOpConvIntToDouble:   out.debug << "Convert int to double";   break;
+    case EOpConvUintToDouble:  out.debug << "Convert uint to double";  break;
+    case EOpConvFloatToDouble: out.debug << "Convert float to double"; break;
+    case EOpConvBoolToDouble:  out.debug << "Convert bool to double";  break;
+    case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break;
+    case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double";  break;
+    case EOpConvBoolToInt64:   out.debug << "Convert bool to int64";   break;
+    case EOpConvIntToInt64:    out.debug << "Convert int to int64";    break;
+    case EOpConvUintToInt64:   out.debug << "Convert uint to int64";   break;
+    case EOpConvFloatToInt64:  out.debug << "Convert float to int64";  break;
+    case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break;
+    case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break;
+    case EOpConvBoolToUint64:  out.debug << "Convert bool to uint64";  break;
+    case EOpConvIntToUint64:   out.debug << "Convert int to uint64";   break;
+    case EOpConvUintToUint64:  out.debug << "Convert uint to uint64";  break;
+    case EOpConvFloatToUint64: out.debug << "Convert float to uint64"; break;
+    case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
+    case EOpConvInt64ToUint64: out.debug << "Convert uint64 to uint64"; break;
+
+    case EOpRadians:        out.debug << "radians";              break;
+    case EOpDegrees:        out.debug << "degrees";              break;
+    case EOpSin:            out.debug << "sine";                 break;
+    case EOpCos:            out.debug << "cosine";               break;
+    case EOpTan:            out.debug << "tangent";              break;
+    case EOpAsin:           out.debug << "arc sine";             break;
+    case EOpAcos:           out.debug << "arc cosine";           break;
+    case EOpAtan:           out.debug << "arc tangent";          break;
+    case EOpSinh:           out.debug << "hyp. sine";            break;
+    case EOpCosh:           out.debug << "hyp. cosine";          break;
+    case EOpTanh:           out.debug << "hyp. tangent";         break;
+    case EOpAsinh:          out.debug << "arc hyp. sine";        break;
+    case EOpAcosh:          out.debug << "arc hyp. cosine";      break;
+    case EOpAtanh:          out.debug << "arc hyp. tangent";     break;
+
+    case EOpExp:            out.debug << "exp";                  break;
+    case EOpLog:            out.debug << "log";                  break;
+    case EOpExp2:           out.debug << "exp2";                 break;
+    case EOpLog2:           out.debug << "log2";                 break;
+    case EOpSqrt:           out.debug << "sqrt";                 break;
+    case EOpInverseSqrt:    out.debug << "inverse sqrt";         break;
+
+    case EOpAbs:            out.debug << "Absolute value";       break;
+    case EOpSign:           out.debug << "Sign";                 break;
+    case EOpFloor:          out.debug << "Floor";                break;
+    case EOpTrunc:          out.debug << "trunc";                break;
+    case EOpRound:          out.debug << "round";                break;
+    case EOpRoundEven:      out.debug << "roundEven";            break;
+    case EOpCeil:           out.debug << "Ceiling";              break;
+    case EOpFract:          out.debug << "Fraction";             break;
+
+    case EOpIsNan:          out.debug << "isnan";                break;
+    case EOpIsInf:          out.debug << "isinf";                break;
+
+    case EOpFloatBitsToInt: out.debug << "floatBitsToInt";       break;
+    case EOpFloatBitsToUint:out.debug << "floatBitsToUint";      break;
+    case EOpIntBitsToFloat: out.debug << "intBitsToFloat";       break;
+    case EOpUintBitsToFloat:out.debug << "uintBitsToFloat";      break;
+    case EOpDoubleBitsToInt64:  out.debug << "doubleBitsToInt64";  break;
+    case EOpDoubleBitsToUint64: out.debug << "doubleBitsToUint64"; break;
+    case EOpInt64BitsToDouble:  out.debug << "int64BitsToDouble";  break;
+    case EOpUint64BitsToDouble: out.debug << "uint64BitsToDouble"; break;
+    case EOpPackSnorm2x16:  out.debug << "packSnorm2x16";        break;
+    case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16";      break;
+    case EOpPackUnorm2x16:  out.debug << "packUnorm2x16";        break;
+    case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16";      break;
+    case EOpPackHalf2x16:   out.debug << "packHalf2x16";         break;
+    case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16";       break;
+
+    case EOpPackSnorm4x8:     out.debug << "PackSnorm4x8";       break;
+    case EOpUnpackSnorm4x8:   out.debug << "UnpackSnorm4x8";     break;
+    case EOpPackUnorm4x8:     out.debug << "PackUnorm4x8";       break;
+    case EOpUnpackUnorm4x8:   out.debug << "UnpackUnorm4x8";     break;
+    case EOpPackDouble2x32:   out.debug << "PackDouble2x32";     break;
+    case EOpUnpackDouble2x32: out.debug << "UnpackDouble2x32";   break;
+
+    case EOpPackInt2x32:      out.debug << "packInt2x32";        break;
+    case EOpUnpackInt2x32:    out.debug << "unpackInt2x32";      break;
+    case EOpPackUint2x32:     out.debug << "packUint2x32";       break;
+    case EOpUnpackUint2x32:   out.debug << "unpackUint2x32";     break;
+
+#ifdef AMD_EXTENSIONS
+    case EOpPackFloat2x16:    out.debug << "packFloat2x16";      break;
+    case EOpUnpackFloat2x16:  out.debug << "unpackFloat2x16";    break;
+#endif
+
+    case EOpLength:         out.debug << "length";               break;
+    case EOpNormalize:      out.debug << "normalize";            break;
+    case EOpDPdx:           out.debug << "dPdx";                 break;
+    case EOpDPdy:           out.debug << "dPdy";                 break;
+    case EOpFwidth:         out.debug << "fwidth";               break;
+    case EOpDPdxFine:       out.debug << "dPdxFine";             break;
+    case EOpDPdyFine:       out.debug << "dPdyFine";             break;
+    case EOpFwidthFine:     out.debug << "fwidthFine";           break;
+    case EOpDPdxCoarse:     out.debug << "dPdxCoarse";           break;
+    case EOpDPdyCoarse:     out.debug << "dPdyCoarse";           break;
+    case EOpFwidthCoarse:   out.debug << "fwidthCoarse";         break;
+
+    case EOpInterpolateAtCentroid: out.debug << "interpolateAtCentroid";  break;
+
+    case EOpDeterminant:    out.debug << "determinant";          break;
+    case EOpMatrixInverse:  out.debug << "inverse";              break;
+    case EOpTranspose:      out.debug << "transpose";            break;
+
+    case EOpAny:            out.debug << "any";                  break;
+    case EOpAll:            out.debug << "all";                  break;
+
+    case EOpArrayLength:    out.debug << "array length";         break;
+
+    case EOpEmitStreamVertex:   out.debug << "EmitStreamVertex";   break;
+    case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break;
+
+    case EOpAtomicCounterIncrement: out.debug << "AtomicCounterIncrement";break;
+    case EOpAtomicCounterDecrement: out.debug << "AtomicCounterDecrement";break;
+    case EOpAtomicCounter:          out.debug << "AtomicCounter";         break;
+
+    case EOpTextureQuerySize:       out.debug << "textureSize";           break;
+    case EOpTextureQueryLod:        out.debug << "textureQueryLod";       break;
+    case EOpTextureQueryLevels:     out.debug << "textureQueryLevels";    break;
+    case EOpTextureQuerySamples:    out.debug << "textureSamples";        break;
+    case EOpImageQuerySize:         out.debug << "imageQuerySize";        break;
+    case EOpImageQuerySamples:      out.debug << "imageQuerySamples";     break;
+    case EOpImageLoad:              out.debug << "imageLoad";             break;
+
+    case EOpBitFieldReverse:        out.debug << "bitFieldReverse";       break;
+    case EOpBitCount:               out.debug << "bitCount";              break;
+    case EOpFindLSB:                out.debug << "findLSB";               break;
+    case EOpFindMSB:                out.debug << "findMSB";               break;
+
+    case EOpNoise:                  out.debug << "noise";                 break;
+
+    case EOpBallot:                 out.debug << "ballot";                break;
+    case EOpReadFirstInvocation:    out.debug << "readFirstInvocation";   break;
+
+    case EOpAnyInvocation:          out.debug << "anyInvocation";         break;
+    case EOpAllInvocations:         out.debug << "allInvocations";        break;
+    case EOpAllInvocationsEqual:    out.debug << "allInvocationsEqual";   break;
+
+    case EOpClip:                   out.debug << "clip";                  break;
+    case EOpIsFinite:               out.debug << "isfinite";              break;
+    case EOpLog10:                  out.debug << "log10";                 break;
+    case EOpRcp:                    out.debug << "rcp";                   break;
+    case EOpSaturate:               out.debug << "saturate";              break;
+
+#ifdef AMD_EXTENSIONS
+    case EOpMinInvocations:             out.debug << "minInvocations";              break;
+    case EOpMaxInvocations:             out.debug << "maxInvocations";              break;
+    case EOpAddInvocations:             out.debug << "addInvocations";              break;
+    case EOpMinInvocationsNonUniform:   out.debug << "minInvocationsNonUniform";    break;
+    case EOpMaxInvocationsNonUniform:   out.debug << "maxInvocationsNonUniform";    break;
+    case EOpAddInvocationsNonUniform:   out.debug << "addInvocationsNonUniform";    break;
+
+    case EOpMinInvocationsInclusiveScan:            out.debug << "minInvocationsInclusiveScan";             break;
+    case EOpMaxInvocationsInclusiveScan:            out.debug << "maxInvocationsInclusiveScan";             break;
+    case EOpAddInvocationsInclusiveScan:            out.debug << "addInvocationsInclusiveScan";             break;
+    case EOpMinInvocationsInclusiveScanNonUniform:  out.debug << "minInvocationsInclusiveScanNonUniform";   break;
+    case EOpMaxInvocationsInclusiveScanNonUniform:  out.debug << "maxInvocationsInclusiveScanNonUniform";   break;
+    case EOpAddInvocationsInclusiveScanNonUniform:  out.debug << "addInvocationsInclusiveScanNonUniform";   break;
+
+    case EOpMinInvocationsExclusiveScan:            out.debug << "minInvocationsExclusiveScan";             break;
+    case EOpMaxInvocationsExclusiveScan:            out.debug << "maxInvocationsExclusiveScan";             break;
+    case EOpAddInvocationsExclusiveScan:            out.debug << "addInvocationsExclusiveScan";             break;
+    case EOpMinInvocationsExclusiveScanNonUniform:  out.debug << "minInvocationsExclusiveScanNonUniform";   break;
+    case EOpMaxInvocationsExclusiveScanNonUniform:  out.debug << "maxInvocationsExclusiveScanNonUniform";   break;
+    case EOpAddInvocationsExclusiveScanNonUniform:  out.debug << "addInvocationsExclusiveScanNonUniform";   break;
+
+    case EOpMbcnt:                      out.debug << "mbcnt";                       break;
+
+    case EOpCubeFaceIndex:          out.debug << "cubeFaceIndex";         break;
+    case EOpCubeFaceCoord:          out.debug << "cubeFaceCoord";         break;
+
+    case EOpConvBoolToFloat16:      out.debug << "Convert bool to float16";     break;
+    case EOpConvIntToFloat16:       out.debug << "Convert int to float16";      break;
+    case EOpConvUintToFloat16:      out.debug << "Convert uint to float16";     break;
+    case EOpConvFloatToFloat16:     out.debug << "Convert float to float16";    break;
+    case EOpConvDoubleToFloat16:    out.debug << "Convert double to float16";   break;
+    case EOpConvInt64ToFloat16:     out.debug << "Convert int64 to float16";    break;
+    case EOpConvUint64ToFloat16:    out.debug << "Convert uint64 to float16";   break;
+    case EOpConvFloat16ToBool:      out.debug << "Convert float16 to bool";     break;
+    case EOpConvFloat16ToInt:       out.debug << "Convert float16 to int";      break;
+    case EOpConvFloat16ToUint:      out.debug << "Convert float16 to uint";     break;
+    case EOpConvFloat16ToFloat:     out.debug << "Convert float16 to float";    break;
+    case EOpConvFloat16ToDouble:    out.debug << "Convert float16 to double";   break;
+    case EOpConvFloat16ToInt64:     out.debug << "Convert float16 to int64";    break;
+    case EOpConvFloat16ToUint64:    out.debug << "Convert float16 to uint64";   break;
+#endif
+
+    default: out.debug.message(EPrefixError, "Bad unary op");
+    }
+
+    out.debug << " (" << node->getCompleteString() << ")";
+
+    out.debug << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
+{
+    TInfoSink& out = infoSink;
+
+    if (node->getOp() == EOpNull) {
+        out.debug.message(EPrefixError, "node is still EOpNull!");
+        return true;
+    }
+
+    OutputTreeText(out, node, depth);
+
+    switch (node->getOp()) {
+    case EOpSequence:      out.debug << "Sequence\n";       return true;
+    case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true;
+    case EOpComma:         out.debug << "Comma";            break;
+    case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
+    case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
+    case EOpParameters:    out.debug << "Function Parameters: ";                    break;
+
+    case EOpConstructFloat: out.debug << "Construct float"; break;
+    case EOpConstructDouble:out.debug << "Construct double"; break;
+    case EOpConstructVec2:  out.debug << "Construct vec2";  break;
+    case EOpConstructVec3:  out.debug << "Construct vec3";  break;
+    case EOpConstructVec4:  out.debug << "Construct vec4";  break;
+    case EOpConstructBool:  out.debug << "Construct bool";  break;
+    case EOpConstructBVec2: out.debug << "Construct bvec2"; break;
+    case EOpConstructBVec3: out.debug << "Construct bvec3"; break;
+    case EOpConstructBVec4: out.debug << "Construct bvec4"; break;
+    case EOpConstructInt:   out.debug << "Construct int";   break;
+    case EOpConstructIVec2: out.debug << "Construct ivec2"; break;
+    case EOpConstructIVec3: out.debug << "Construct ivec3"; break;
+    case EOpConstructIVec4: out.debug << "Construct ivec4"; break;
+    case EOpConstructUint:    out.debug << "Construct uint";    break;
+    case EOpConstructUVec2:   out.debug << "Construct uvec2";   break;
+    case EOpConstructUVec3:   out.debug << "Construct uvec3";   break;
+    case EOpConstructUVec4:   out.debug << "Construct uvec4";   break;
+    case EOpConstructInt64:   out.debug << "Construct int64_t"; break;
+    case EOpConstructI64Vec2: out.debug << "Construct i64vec2"; break;
+    case EOpConstructI64Vec3: out.debug << "Construct i64vec3"; break;
+    case EOpConstructI64Vec4: out.debug << "Construct i64vec4"; break;
+    case EOpConstructUint64:  out.debug << "Construct uint64_t"; break;
+    case EOpConstructU64Vec2: out.debug << "Construct u64vec2"; break;
+    case EOpConstructU64Vec3: out.debug << "Construct u64vec3"; break;
+    case EOpConstructU64Vec4: out.debug << "Construct u64vec4"; break;
+    case EOpConstructMat2x2:  out.debug << "Construct mat2";    break;
+    case EOpConstructMat2x3:  out.debug << "Construct mat2x3";  break;
+    case EOpConstructMat2x4:  out.debug << "Construct mat2x4";  break;
+    case EOpConstructMat3x2:  out.debug << "Construct mat3x2";  break;
+    case EOpConstructMat3x3:  out.debug << "Construct mat3";    break;
+    case EOpConstructMat3x4:  out.debug << "Construct mat3x4";  break;
+    case EOpConstructMat4x2:  out.debug << "Construct mat4x2";  break;
+    case EOpConstructMat4x3:  out.debug << "Construct mat4x3";  break;
+    case EOpConstructMat4x4:  out.debug << "Construct mat4";    break;
+    case EOpConstructDMat2x2: out.debug << "Construct dmat2";   break;
+    case EOpConstructDMat2x3: out.debug << "Construct dmat2x3"; break;
+    case EOpConstructDMat2x4: out.debug << "Construct dmat2x4"; break;
+    case EOpConstructDMat3x2: out.debug << "Construct dmat3x2"; break;
+    case EOpConstructDMat3x3: out.debug << "Construct dmat3";   break;
+    case EOpConstructDMat3x4: out.debug << "Construct dmat3x4"; break;
+    case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break;
+    case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
+    case EOpConstructDMat4x4: out.debug << "Construct dmat4";   break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16:   out.debug << "Construct float16_t"; break;
+    case EOpConstructF16Vec2:   out.debug << "Construct f16vec2";   break;
+    case EOpConstructF16Vec3:   out.debug << "Construct f16vec3";   break;
+    case EOpConstructF16Vec4:   out.debug << "Construct f16vec4";   break;
+    case EOpConstructF16Mat2x2: out.debug << "Construct f16mat2";   break;
+    case EOpConstructF16Mat2x3: out.debug << "Construct f16mat2x3"; break;
+    case EOpConstructF16Mat2x4: out.debug << "Construct f16mat2x4"; break;
+    case EOpConstructF16Mat3x2: out.debug << "Construct f16mat3x2"; break;
+    case EOpConstructF16Mat3x3: out.debug << "Construct f16mat3";   break;
+    case EOpConstructF16Mat3x4: out.debug << "Construct f16mat3x4"; break;
+    case EOpConstructF16Mat4x2: out.debug << "Construct f16mat4x2"; break;
+    case EOpConstructF16Mat4x3: out.debug << "Construct f16mat4x3"; break;
+    case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4";   break;
+#endif
+    case EOpConstructStruct:  out.debug << "Construct structure";  break;
+    case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
+
+    case EOpLessThan:         out.debug << "Compare Less Than";             break;
+    case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
+    case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
+    case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
+    case EOpVectorEqual:      out.debug << "Equal";                         break;
+    case EOpVectorNotEqual:   out.debug << "NotEqual";                      break;
+
+    case EOpMod:           out.debug << "mod";         break;
+    case EOpModf:          out.debug << "modf";        break;
+    case EOpPow:           out.debug << "pow";         break;
+
+    case EOpAtan:          out.debug << "arc tangent"; break;
+
+    case EOpMin:           out.debug << "min";         break;
+    case EOpMax:           out.debug << "max";         break;
+    case EOpClamp:         out.debug << "clamp";       break;
+    case EOpMix:           out.debug << "mix";         break;
+    case EOpStep:          out.debug << "step";        break;
+    case EOpSmoothStep:    out.debug << "smoothstep";  break;
+
+    case EOpDistance:      out.debug << "distance";                break;
+    case EOpDot:           out.debug << "dot-product";             break;
+    case EOpCross:         out.debug << "cross-product";           break;
+    case EOpFaceForward:   out.debug << "face-forward";            break;
+    case EOpReflect:       out.debug << "reflect";                 break;
+    case EOpRefract:       out.debug << "refract";                 break;
+    case EOpMul:           out.debug << "component-wise multiply"; break;
+    case EOpOuterProduct:  out.debug << "outer product";           break;
+
+    case EOpEmitVertex:    out.debug << "EmitVertex";              break;
+    case EOpEndPrimitive:  out.debug << "EndPrimitive";            break;
+
+    case EOpBarrier:                    out.debug << "Barrier";                    break;
+    case EOpMemoryBarrier:              out.debug << "MemoryBarrier";              break;
+    case EOpMemoryBarrierAtomicCounter: out.debug << "MemoryBarrierAtomicCounter"; break;
+    case EOpMemoryBarrierBuffer:        out.debug << "MemoryBarrierBuffer";        break;
+    case EOpMemoryBarrierImage:         out.debug << "MemoryBarrierImage";         break;
+    case EOpMemoryBarrierShared:        out.debug << "MemoryBarrierShared";        break;
+    case EOpGroupMemoryBarrier:         out.debug << "GroupMemoryBarrier";         break;
+
+    case EOpReadInvocation:             out.debug << "readInvocation";        break;
+
+#ifdef AMD_EXTENSIONS
+    case EOpSwizzleInvocations:         out.debug << "swizzleInvocations";       break;
+    case EOpSwizzleInvocationsMasked:   out.debug << "swizzleInvocationsMasked"; break;
+    case EOpWriteInvocation:            out.debug << "writeInvocation";          break;
+
+    case EOpMin3:                       out.debug << "min3";                  break;
+    case EOpMax3:                       out.debug << "max3";                  break;
+    case EOpMid3:                       out.debug << "mid3";                  break;
+
+    case EOpTime:                       out.debug << "time";                  break;
+#endif
+
+    case EOpAtomicAdd:                  out.debug << "AtomicAdd";             break;
+    case EOpAtomicMin:                  out.debug << "AtomicMin";             break;
+    case EOpAtomicMax:                  out.debug << "AtomicMax";             break;
+    case EOpAtomicAnd:                  out.debug << "AtomicAnd";             break;
+    case EOpAtomicOr:                   out.debug << "AtomicOr";              break;
+    case EOpAtomicXor:                  out.debug << "AtomicXor";             break;
+    case EOpAtomicExchange:             out.debug << "AtomicExchange";        break;
+    case EOpAtomicCompSwap:             out.debug << "AtomicCompSwap";        break;
+
+    case EOpImageQuerySize:             out.debug << "imageQuerySize";        break;
+    case EOpImageQuerySamples:          out.debug << "imageQuerySamples";     break;
+    case EOpImageLoad:                  out.debug << "imageLoad";             break;
+    case EOpImageStore:                 out.debug << "imageStore";            break;
+    case EOpImageAtomicAdd:             out.debug << "imageAtomicAdd";        break;
+    case EOpImageAtomicMin:             out.debug << "imageAtomicMin";        break;
+    case EOpImageAtomicMax:             out.debug << "imageAtomicMax";        break;
+    case EOpImageAtomicAnd:             out.debug << "imageAtomicAnd";        break;
+    case EOpImageAtomicOr:              out.debug << "imageAtomicOr";         break;
+    case EOpImageAtomicXor:             out.debug << "imageAtomicXor";        break;
+    case EOpImageAtomicExchange:        out.debug << "imageAtomicExchange";   break;
+    case EOpImageAtomicCompSwap:        out.debug << "imageAtomicCompSwap";   break;
+
+    case EOpTextureQuerySize:           out.debug << "textureSize";           break;
+    case EOpTextureQueryLod:            out.debug << "textureQueryLod";       break;
+    case EOpTextureQueryLevels:         out.debug << "textureQueryLevels";    break;
+    case EOpTextureQuerySamples:        out.debug << "textureSamples";        break;
+    case EOpTexture:                    out.debug << "texture";               break;
+    case EOpTextureProj:                out.debug << "textureProj";           break;
+    case EOpTextureLod:                 out.debug << "textureLod";            break;
+    case EOpTextureOffset:              out.debug << "textureOffset";         break;
+    case EOpTextureFetch:               out.debug << "textureFetch";          break;
+    case EOpTextureFetchOffset:         out.debug << "textureFetchOffset";    break;
+    case EOpTextureProjOffset:          out.debug << "textureProjOffset";     break;
+    case EOpTextureLodOffset:           out.debug << "textureLodOffset";      break;
+    case EOpTextureProjLod:             out.debug << "textureProjLod";        break;
+    case EOpTextureProjLodOffset:       out.debug << "textureProjLodOffset";  break;
+    case EOpTextureGrad:                out.debug << "textureGrad";           break;
+    case EOpTextureGradOffset:          out.debug << "textureGradOffset";     break;
+    case EOpTextureProjGrad:            out.debug << "textureProjGrad";       break;
+    case EOpTextureProjGradOffset:      out.debug << "textureProjGradOffset"; break;
+    case EOpTextureGather:              out.debug << "textureGather";         break;
+    case EOpTextureGatherOffset:        out.debug << "textureGatherOffset";   break;
+    case EOpTextureGatherOffsets:       out.debug << "textureGatherOffsets";  break;
+
+    case EOpAddCarry:                   out.debug << "addCarry";              break;
+    case EOpSubBorrow:                  out.debug << "subBorrow";             break;
+    case EOpUMulExtended:               out.debug << "uMulExtended";          break;
+    case EOpIMulExtended:               out.debug << "iMulExtended";          break;
+    case EOpBitfieldExtract:            out.debug << "bitfieldExtract";       break;
+    case EOpBitfieldInsert:             out.debug << "bitfieldInsert";        break;
+
+    case EOpFma:                        out.debug << "fma";                   break;
+    case EOpFrexp:                      out.debug << "frexp";                 break;
+    case EOpLdexp:                      out.debug << "ldexp";                 break;
+
+    case EOpInterpolateAtSample:   out.debug << "interpolateAtSample";    break;
+    case EOpInterpolateAtOffset:   out.debug << "interpolateAtOffset";    break;
+#ifdef AMD_EXTENSIONS
+    case EOpInterpolateAtVertex:   out.debug << "interpolateAtVertex";    break;
+#endif
+
+    case EOpSinCos:                     out.debug << "sincos";                break;
+    case EOpGenMul:                     out.debug << "mul";                   break;
+
+    case EOpAllMemoryBarrierWithGroupSync:    out.debug << "AllMemoryBarrierWithGroupSync";    break;
+    case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break;
+    case EOpWorkgroupMemoryBarrier:           out.debug << "WorkgroupMemoryBarrier";           break;
+    case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break;
+
+    default: out.debug.message(EPrefixError, "Bad aggregation op");
+    }
+
+    if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+        out.debug << " (" << node->getCompleteString() << ")";
+
+    out.debug << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+
+    out.debug << "Test condition and select";
+    out.debug << " (" << node->getCompleteString() << ")\n";
+
+    ++depth;
+
+    OutputTreeText(out, node, depth);
+    out.debug << "Condition\n";
+    node->getCondition()->traverse(this);
+
+    OutputTreeText(out, node, depth);
+    if (node->getTrueBlock()) {
+        out.debug << "true case\n";
+        node->getTrueBlock()->traverse(this);
+    } else
+        out.debug << "true case is null\n";
+
+    if (node->getFalseBlock()) {
+        OutputTreeText(out, node, depth);
+        out.debug << "false case\n";
+        node->getFalseBlock()->traverse(this);
+    }
+
+    --depth;
+
+    return false;
+}
+
+static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
+{
+    int size = node->getType().computeNumComponents();
+
+    for (int i = 0; i < size; i++) {
+        OutputTreeText(out, node, depth);
+        switch (constUnion[i].getType()) {
+        case EbtBool:
+            if (constUnion[i].getBConst())
+                out.debug << "true";
+            else
+                out.debug << "false";
+
+            out.debug << " (" << "const bool" << ")";
+
+            out.debug << "\n";
+            break;
+        case EbtFloat:
+        case EbtDouble:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            {
+                const double value = constUnion[i].getDConst();
+                // Print infinity in a portable way, for test stability.
+                // Other cases may be needed in the future: negative infinity,
+                // and NaNs.
+                if (is_positive_infinity(value))
+                    out.debug << "inf\n";
+                else {
+                    const int maxSize = 300;
+                    char buf[maxSize];
+                    snprintf(buf, maxSize, "%f", value);
+
+                    out.debug << buf << "\n";
+                }
+            }
+            break;
+        case EbtInt:
+            {
+                const int maxSize = 300;
+                char buf[maxSize];
+                snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int");
+
+                out.debug << buf << "\n";
+            }
+            break;
+        case EbtUint:
+            {
+                const int maxSize = 300;
+                char buf[maxSize];
+                snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint");
+
+                out.debug << buf << "\n";
+            }
+            break;
+        case EbtInt64:
+            {
+                const int maxSize = 300;
+                char buf[maxSize];
+                snprintf(buf, maxSize, "%lld (%s)", constUnion[i].getI64Const(), "const int64_t");
+
+                out.debug << buf << "\n";
+            }
+            break;
+        case EbtUint64:
+            {
+                const int maxSize = 300;
+                char buf[maxSize];
+                snprintf(buf, maxSize, "%llu (%s)", constUnion[i].getU64Const(), "const uint64_t");
+
+                out.debug << buf << "\n";
+            }
+            break;
+        default:
+            out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc());
+            break;
+        }
+    }
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+    OutputTreeText(infoSink, node, depth);
+    infoSink.debug << "Constant:\n";
+
+    OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
+}
+
+void TOutputTraverser::visitSymbol(TIntermSymbol* node)
+{
+    OutputTreeText(infoSink, node, depth);
+
+    infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n";
+
+    if (! node->getConstArray().empty())
+        OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
+    else if (node->getConstSubtree()) {
+        incrementDepth(node);
+        node->getConstSubtree()->traverse(this);
+        decrementDepth();
+    }
+}
+
+bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+
+    out.debug << "Loop with condition ";
+    if (! node->testFirst())
+        out.debug << "not ";
+    out.debug << "tested first\n";
+
+    ++depth;
+
+    OutputTreeText(infoSink, node, depth);
+    if (node->getTest()) {
+        out.debug << "Loop Condition\n";
+        node->getTest()->traverse(this);
+    } else
+        out.debug << "No loop condition\n";
+
+    OutputTreeText(infoSink, node, depth);
+    if (node->getBody()) {
+        out.debug << "Loop Body\n";
+        node->getBody()->traverse(this);
+    } else
+        out.debug << "No loop body\n";
+
+    if (node->getTerminal()) {
+        OutputTreeText(infoSink, node, depth);
+        out.debug << "Loop Terminal Expression\n";
+        node->getTerminal()->traverse(this);
+    }
+
+    --depth;
+
+    return false;
+}
+
+bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+
+    switch (node->getFlowOp()) {
+    case EOpKill:      out.debug << "Branch: Kill";           break;
+    case EOpBreak:     out.debug << "Branch: Break";          break;
+    case EOpContinue:  out.debug << "Branch: Continue";       break;
+    case EOpReturn:    out.debug << "Branch: Return";         break;
+    case EOpCase:      out.debug << "case: ";                 break;
+    case EOpDefault:   out.debug << "default: ";              break;
+    default:               out.debug << "Branch: Unknown Branch"; break;
+    }
+
+    if (node->getExpression()) {
+        out.debug << " with expression\n";
+        ++depth;
+        node->getExpression()->traverse(this);
+        --depth;
+    } else
+        out.debug << "\n";
+
+    return false;
+}
+
+bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
+{
+    TInfoSink& out = infoSink;
+
+    OutputTreeText(out, node, depth);
+    out.debug << "switch\n";
+
+    OutputTreeText(out, node, depth);
+    out.debug << "condition\n";
+    ++depth;
+    node->getCondition()->traverse(this);
+
+    --depth;
+    OutputTreeText(out, node, depth);
+    out.debug << "body\n";
+    ++depth;
+    node->getBody()->traverse(this);
+
+    --depth;
+
+    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::output(TInfoSink& infoSink, bool tree)
+{
+    infoSink.debug << "Shader version: " << version << "\n";
+    if (requestedExtensions.size() > 0) {
+        for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt)
+            infoSink.debug << "Requested " << *extIt << "\n";
+    }
+
+    if (xfbMode)
+        infoSink.debug << "in xfb mode\n";
+
+    switch (language) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+        infoSink.debug << "vertices = " << vertices << "\n";
+        break;
+
+    case EShLangTessEvaluation:
+        infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
+        infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n";
+        infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n";
+        if (pointMode)
+            infoSink.debug << "using point mode\n";
+        break;
+
+    case EShLangGeometry:
+        infoSink.debug << "invocations = " << invocations << "\n";
+        infoSink.debug << "max_vertices = " << vertices << "\n";
+        infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
+        infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n";
+        break;
+
+    case EShLangFragment:
+        if (pixelCenterInteger)
+            infoSink.debug << "gl_FragCoord pixel center is integer\n";
+        if (originUpperLeft)
+            infoSink.debug << "gl_FragCoord origin is upper left\n";
+        if (earlyFragmentTests)
+            infoSink.debug << "using early_fragment_tests\n";
+        if (depthLayout != EldNone)
+            infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
+        if (blendEquations != 0) {
+            infoSink.debug << "using";
+            // blendEquations is a mask, decode it
+            for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
+                if (blendEquations & (1 << be))
+                    infoSink.debug << " " << TQualifier::getBlendEquationString(be);
+            }
+            infoSink.debug << "\n";
+        }
+        break;
+
+    case EShLangCompute:
+        infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
+        {
+            if (localSizeSpecId[0] != TQualifier::layoutNotSet ||
+                localSizeSpecId[1] != TQualifier::layoutNotSet ||
+                localSizeSpecId[2] != TQualifier::layoutNotSet) {
+                infoSink.debug << "local_size ids = (" <<
+                    localSizeSpecId[0] << ", " <<
+                    localSizeSpecId[1] << ", " <<
+                    localSizeSpecId[2] << ")\n";
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    if (treeRoot == 0 || ! tree)
+        return;
+
+    TOutputTraverser it(infoSink);
+
+    treeRoot->traverse(&it);
+}
+
+} // end namespace glslang

+ 404 - 0
src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp

@@ -0,0 +1,404 @@
+//
+// Copyright (C) 2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "../Include/InfoSink.h"
+#include "iomapper.h"
+#include "LiveTraverser.h"
+#include "localintermediate.h"
+
+#include "gl_types.h"
+
+#include <unordered_set>
+#include <unordered_map>
+
+//
+// Map IO bindings.
+//
+// High-level algorithm for one stage:
+//
+// 1. Traverse all code (live+dead) to find the explicitly provided bindings.
+//
+// 2. Traverse (just) the live code to determine which non-provided bindings
+//    require auto-numbering.  We do not auto-number dead ones.
+//
+// 3. Traverse all the code to apply the bindings:
+//    a. explicitly given bindings are offset according to their type
+//    b. implicit live bindings are auto-numbered into the holes, using
+//       any open binding slot.
+//    c. implicit dead bindings are left un-bound.
+//
+
+
+namespace glslang {
+
+struct TVarEntryInfo
+{
+    int             id;
+    TIntermSymbol*  symbol;
+    bool            live;
+    int             newBinding;
+    int             newSet;
+
+    struct TOrderById
+    {
+      inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r)
+      {
+        return l.id < r.id;
+      }
+    };
+
+    struct TOrderByPriority
+    {
+        // ordering:
+        // 1) has both binding and set
+        // 2) has binding but no set
+        // 3) has no binding but set
+        // 4) has no binding and no set
+        inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r)
+        {
+            const TQualifier& lq = l.symbol->getQualifier();
+            const TQualifier& rq = r.symbol->getQualifier();
+
+            // simple rules:
+            // has binding gives 2 points
+            // has set gives 1 point
+            // who has the most points is more important.
+            int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
+            int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
+
+            if (lPoints == rPoints)
+              return l.id < r.id;
+            return lPoints > rPoints;
+        }
+    };
+};
+
+
+
+typedef std::vector<TVarEntryInfo> TVarLiveMap;
+
+class TVarGatherTraverser : public TLiveTraverser
+{
+public:
+    TVarGatherTraverser(const TIntermediate& i, TVarLiveMap& vars, bool traverseDeadCode)
+      : TLiveTraverser(i, traverseDeadCode, true, true, false)
+      , varLiveList(vars)
+    {
+    }
+
+
+    virtual void visitSymbol(TIntermSymbol* base)
+    {
+        if (base->getQualifier().storage == EvqUniform) {
+            TVarEntryInfo ent = { base->getId(), base, !traverseAll };
+            TVarLiveMap::iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById());
+            if (at != varLiveList.end() && at->id == ent.id)
+              at->live = at->live || !traverseAll; // update live state
+            else
+              varLiveList.insert(at, ent);
+        }
+    }
+
+private:
+    TVarLiveMap&    varLiveList;
+};
+
+class TVarSetTraverser : public TLiveTraverser
+{
+public:
+    TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& vars)
+      : TLiveTraverser(i, true, true, true, false)
+      , varLiveList(vars)
+    {
+    }
+
+
+    virtual void visitSymbol(TIntermSymbol* base)
+    {
+        TVarEntryInfo ent = { base->getId() };
+        TVarLiveMap::const_iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById());
+        if (at == varLiveList.end())
+            return;
+        if (!(at->id == ent.id))
+            return;
+
+        if (at->newBinding != -1)
+            base->getWritableType().getQualifier().layoutBinding = at->newBinding;
+        if (at->newSet != -1)
+            base->getWritableType().getQualifier().layoutSet = at->newSet;
+    }
+
+  private:
+    const TVarLiveMap&    varLiveList;
+};
+
+struct TResolverAdaptor
+{
+    TResolverAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
+      : stage(s)
+      , resolver(r)
+      , infoSink(i)
+      , error(e)
+    {
+    }
+
+    inline void operator()(TVarEntryInfo& ent)
+    {
+        const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+        if (isValid) {
+            ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+            ent.newSet = resolver.resolveSet(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+
+            if (ent.newBinding != -1) {
+                if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
+                    TString err = "mapped binding out of range: " + ent.symbol->getName();
+
+                    infoSink.info.message(EPrefixInternalError, err.c_str());
+                    error = true;
+                }
+            }
+            if (ent.newSet != -1) {
+                if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
+                    TString err = "mapped set out of range: " + ent.symbol->getName();
+
+                    infoSink.info.message(EPrefixInternalError, err.c_str());
+                    error = true;
+                }
+            }
+        } else {
+            TString errorMsg = "Invalid binding: " + ent.symbol->getName();
+            infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
+            error = true;
+        }
+    }
+
+    EShLanguage     stage;
+    TIoMapResolver& resolver;
+    TInfoSink&      infoSink;
+    bool&           error;
+};
+
+/*
+ * Basic implementation of glslang::TIoMapResolver that replaces the
+ * previous offset behaviour.
+ * It does the same, uses the offsets for th corresponding uniform
+ * types. Also respects the EOptionAutoMapBindings flag and binds
+ * them if needed.
+ */
+struct TDefaultIoResolver : public glslang::TIoMapResolver
+{
+    int baseSamplerBinding;
+    int baseTextureBinding;
+    int baseImageBinding;
+    int baseUboBinding;
+    bool doAutoMapping;
+    typedef std::vector<int> TSlotSet;
+    typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
+    TSlotSetMap slots;
+
+    TSlotSet::iterator findSlot(int set, int slot)
+    {
+        return std::lower_bound(slots[set].begin(), slots[set].end(), slot);
+    }
+
+    bool checkEmpty(int set, int slot)
+    {
+        TSlotSet::iterator at = findSlot(set, slot);
+        return !(at != slots[set].end() && *at == slot);
+    }
+
+    int reserveSlot(int set, int slot)
+    {
+        TSlotSet::iterator at = findSlot(set, slot);
+        slots[set].insert(at, slot);
+        return slot;
+    }
+
+    int getFreeSlot(int set, int base)
+    {
+        TSlotSet::iterator at = findSlot(set, base);
+        if (at == slots[set].end())
+            return reserveSlot(set, base);
+
+        // look in locksteps, if they not match, then there is a free slot
+        for (; at != slots[set].end(); ++at, ++base)
+            if (*at != base)
+                break;
+        return reserveSlot(set, base);
+    }
+
+    bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override
+    {
+        if (type.getQualifier().hasBinding()) {
+            int set;
+            if (type.getQualifier().hasSet())
+                set = type.getQualifier().layoutSet;
+            else
+                set = 0;
+
+            if (type.getBasicType() == glslang::EbtSampler) {
+                const glslang::TSampler& sampler = type.getSampler();
+                if (sampler.isPureSampler())
+                    return checkEmpty(set, baseSamplerBinding + type.getQualifier().layoutBinding);
+
+                if (sampler.isTexture())
+                    return checkEmpty(set, baseTextureBinding + type.getQualifier().layoutBinding);
+            }
+
+            if (type.getQualifier().isUniformOrBuffer())
+                return checkEmpty(set, baseUboBinding + type.getQualifier().layoutBinding);
+        }
+        return true;
+    }
+
+    int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override
+    {
+        int set;
+        if (type.getQualifier().hasSet())
+            set = type.getQualifier().layoutSet;
+        else
+            set = 0;
+
+        if (type.getQualifier().hasBinding()) {
+            if (type.getBasicType() == glslang::EbtSampler) {
+                const glslang::TSampler& sampler = type.getSampler();
+                if (sampler.isImage())
+                    return reserveSlot(set, baseImageBinding + type.getQualifier().layoutBinding);
+
+                if (sampler.isPureSampler())
+                    return reserveSlot(set, baseSamplerBinding + type.getQualifier().layoutBinding);
+
+                if (sampler.isTexture())
+                    return reserveSlot(set, baseTextureBinding + type.getQualifier().layoutBinding);
+            }
+
+            if (type.getQualifier().isUniformOrBuffer())
+                return reserveSlot(set, baseUboBinding + type.getQualifier().layoutBinding);
+        } else if (is_live && doAutoMapping) {
+            // find free slot, the caller did make sure it passes all vars with binding
+            // first and now all are passed that do not have a binding and needs one
+            if (type.getBasicType() == glslang::EbtSampler) {
+                const glslang::TSampler& sampler = type.getSampler();
+                if (sampler.isImage())
+                    return getFreeSlot(set, baseImageBinding);
+
+                if (sampler.isPureSampler())
+                    return getFreeSlot(set, baseSamplerBinding);
+
+                if (sampler.isTexture())
+                    return getFreeSlot(set, baseTextureBinding);
+            }
+
+            if (type.getQualifier().isUniformOrBuffer())
+                return getFreeSlot(set, baseUboBinding);
+        }
+
+        return -1;
+    }
+
+    int resolveSet(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override
+    {
+        if (type.getQualifier().hasSet())
+            return type.getQualifier().layoutSet;
+        return 0;
+    }
+};
+
+// Map I/O variables to provided offsets, and make bindings for
+// unbound but live variables.
+//
+// Returns false if the input is too malformed to do this.
+bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSink &infoSink, TIoMapResolver *resolver)
+{
+    // Trivial return if there is nothing to do.
+    if (intermediate.getShiftSamplerBinding() == 0 &&
+        intermediate.getShiftTextureBinding() == 0 &&
+        intermediate.getShiftImageBinding() == 0 &&
+        intermediate.getShiftUboBinding() == 0 &&
+        intermediate.getAutoMapBindings() == false &&
+        resolver == nullptr)
+        return true;
+
+    if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
+        return false;
+
+    TIntermNode* root = intermediate.getTreeRoot();
+    if (root == nullptr)
+        return false;
+
+    // if no resolver is provided, use the default resolver with the given shifts and auto map settings
+    TDefaultIoResolver defaultResolver;
+    if (resolver == nullptr) {
+        defaultResolver.baseSamplerBinding = intermediate.getShiftSamplerBinding();
+        defaultResolver.baseTextureBinding = intermediate.getShiftTextureBinding();
+        defaultResolver.baseImageBinding = intermediate.getShiftImageBinding();
+        defaultResolver.baseUboBinding = intermediate.getShiftUboBinding();
+        defaultResolver.doAutoMapping = intermediate.getAutoMapBindings();
+
+        resolver = &defaultResolver;
+    }
+
+    TVarLiveMap varMap;
+    TVarGatherTraverser iter_binding_all(intermediate, varMap, true);
+    TVarGatherTraverser iter_binding_live(intermediate, varMap, false);
+
+    root->traverse(&iter_binding_all);
+    iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
+
+    while (!iter_binding_live.functions.empty()) {
+        TIntermNode* function = iter_binding_live.functions.back();
+        iter_binding_live.functions.pop_back();
+        function->traverse(&iter_binding_live);
+    }
+
+    // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
+    std::sort(varMap.begin(), varMap.end(), TVarEntryInfo::TOrderByPriority());
+
+    bool hadError = false;
+    TResolverAdaptor doResolve(stage, *resolver, infoSink, hadError);
+    std::for_each(varMap.begin(), varMap.end(), doResolve);
+
+    if (!hadError) {
+        // sort by id again, so we can use lower bound to find entries
+        std::sort(varMap.begin(), varMap.end(), TVarEntryInfo::TOrderById());
+        TVarSetTraverser iter_iomap(intermediate, varMap);
+        root->traverse(&iter_iomap);
+    }
+
+    return !hadError;
+}
+
+} // end namespace glslang

+ 63 - 0
src/libraries/glslang/glslang/MachineIndependent/iomapper.h

@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _IOMAPPER_INCLUDED
+#define _IOMAPPER_INCLUDED
+
+#include "../Public/ShaderLang.h"
+
+//
+// A reflection database and its interface, consistent with the OpenGL API reflection queries.
+//
+
+class TInfoSink;
+
+namespace glslang {
+
+class TIntermediate;
+
+// I/O mapper
+class TIoMapper {
+public:
+    TIoMapper() {}
+    virtual ~TIoMapper() {}
+
+    // grow the reflection stage by stage
+    bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
+};
+
+} // end namespace glslang
+
+#endif // _IOMAPPER_INCLUDED

+ 198 - 0
src/libraries/glslang/glslang/MachineIndependent/limits.cpp

@@ -0,0 +1,198 @@
+//
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Do sub tree walks for
+// 1) inductive loop bodies to see if the inductive variable is modified
+// 2) array-index expressions to see if they are "constant-index-expression"
+//
+// These are per Appendix A of ES 2.0:
+//
+// "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
+// argument to a function out or inout parameter."
+//
+// "The following are constant-index-expressions:
+//  - Constant expressions
+//  - Loop indices as defined in section 4
+//  - Expressions composed of both of the above"
+//
+// N.B.: assuming the last rule excludes function calls
+//
+
+#include "ParseHelper.h"
+
+namespace glslang {
+
+//
+// The inductive loop-body traverser.
+//
+// Just look at things that might modify the loop index.
+//
+
+class TInductiveTraverser : public TIntermTraverser {
+public:
+    TInductiveTraverser(int id, TSymbolTable& st)
+    : loopId(id), symbolTable(st), bad(false)  { }
+
+    virtual bool visitBinary(TVisit, TIntermBinary* node);
+    virtual bool visitUnary(TVisit, TIntermUnary* node);
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
+
+    int loopId;           // unique ID of the symbol that's the loop inductive variable
+    TSymbolTable& symbolTable;
+    bool bad;
+    TSourceLoc badLoc;
+
+protected:
+    TInductiveTraverser(TInductiveTraverser&);
+    TInductiveTraverser& operator=(TInductiveTraverser&);
+};
+
+// check binary operations for those modifying the loop index
+bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
+{
+    if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
+                                 node->getLeft()->getAsSymbolNode()->getId() == loopId) {
+        bad = true;
+        badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+// check unary operations for those modifying the loop index
+bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
+{
+    if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
+                                 node->getOperand()->getAsSymbolNode()->getId() == loopId) {
+        bad = true;
+        badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+// check function calls for arguments modifying the loop index
+bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
+{
+    if (node->getOp() == EOpFunctionCall) {
+        // see if an out or inout argument is the loop index
+        const TIntermSequence& args = node->getSequence();
+        for (int i = 0; i < (int)args.size(); ++i) {
+            if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
+                TSymbol* function = symbolTable.find(node->getName());
+                const TType* type = (*function->getAsFunction())[i].type;
+                if (type->getQualifier().storage == EvqOut ||
+                    type->getQualifier().storage == EvqInOut) {
+                    bad = true;
+                    badLoc = node->getLoc();
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+//
+// External function to call for loop check.
+//
+void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
+{
+    TInductiveTraverser it(loopId, symbolTable);
+
+    if (body == nullptr)
+        return;
+
+    body->traverse(&it);
+
+    if (it.bad)
+        error(it.badLoc, "inductive loop index modified", "limitations", "");
+}
+
+//
+// The "constant-index-expression" tranverser.
+//
+// Just look at things that can form an index.
+//
+
+class TIndexTraverser : public TIntermTraverser {
+public:
+    TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
+    virtual void visitSymbol(TIntermSymbol* symbol);
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
+    const TIdSetType& inductiveLoopIds;
+    bool bad;
+    TSourceLoc badLoc;
+
+protected:
+    TIndexTraverser(TIndexTraverser&);
+    TIndexTraverser& operator=(TIndexTraverser&);
+};
+
+// make sure symbols are inductive-loop indexes
+void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
+{
+    if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
+        bad = true;
+        badLoc = symbol->getLoc();
+    }
+}
+
+// check for function calls, assuming they are bad; spec. doesn't really say
+bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
+{
+    if (node->getOp() == EOpFunctionCall) {
+        bad = true;
+        badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+//
+// External function to call for loop check.
+//
+void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
+{
+    TIndexTraverser it(inductiveLoopIds);
+
+    index->traverse(&it);
+
+    if (it.bad)
+        error(it.badLoc, "Non-constant-index-expression", "limitations", "");
+}
+
+} // end namespace glslang

+ 1220 - 0
src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp

@@ -0,0 +1,1220 @@
+//
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Do link-time merging and validation of intermediate representations.
+//
+// Basic model is that during compilation, each compilation unit (shader) is
+// compiled into one TIntermediate instance.  Then, at link time, multiple
+// units for the same stage can be merged together, which can generate errors.
+// Then, after all merging, a single instance of TIntermediate represents
+// the whole stage.  A final error check can be done on the resulting stage,
+// even if no merging was done (i.e., the stage was only one compilation unit).
+//
+
+#include "localintermediate.h"
+#include "../Include/InfoSink.h"
+
+namespace glslang {
+
+//
+// Link-time error emitter.
+//
+void TIntermediate::error(TInfoSink& infoSink, const char* message)
+{
+    infoSink.info.prefix(EPrefixError);
+    infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
+
+    ++numErrors;
+}
+
+// Link-time warning.
+void TIntermediate::warn(TInfoSink& infoSink, const char* message)
+{
+    infoSink.info.prefix(EPrefixWarning);
+    infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
+}
+
+// TODO: 4.4 offset/align:  "Two blocks linked together in the same program with the same block
+// name must have the exact same set of members qualified with offset and their integral-constant
+// expression values must be the same, or a link-time error results."
+
+//
+// Merge the information from 'unit' into 'this'
+//
+void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
+{
+    if (source == EShSourceNone)
+        source = unit.source;
+
+    if (source != unit.source)
+        error(infoSink, "can't link compilation units from different source languages");
+
+    if (unit.getNumEntryPoints() > 0) {
+        if (getNumEntryPoints() > 0)
+            error(infoSink, "can't handle multiple entry points per stage");
+        else {
+            entryPointName = unit.getEntryPointName();
+            entryPointMangledName = unit.getEntryPointMangledName();
+        }
+    }
+    numEntryPoints += unit.getNumEntryPoints();
+    numErrors += unit.getNumErrors();
+    numPushConstants += unit.numPushConstants;
+    callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
+
+    if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger)
+        error(infoSink, "gl_FragCoord redeclarations must match across shaders");
+
+    if (! earlyFragmentTests)
+        earlyFragmentTests = unit.earlyFragmentTests;
+
+    if (depthLayout == EldNone)
+        depthLayout = unit.depthLayout;
+    else if (depthLayout != unit.depthLayout)
+        error(infoSink, "Contradictory depth layouts");
+
+    blendEquations |= unit.blendEquations;
+
+    if (inputPrimitive == ElgNone)
+        inputPrimitive = unit.inputPrimitive;
+    else if (inputPrimitive != unit.inputPrimitive)
+        error(infoSink, "Contradictory input layout primitives");
+
+    if (outputPrimitive == ElgNone)
+        outputPrimitive = unit.outputPrimitive;
+    else if (outputPrimitive != unit.outputPrimitive)
+        error(infoSink, "Contradictory output layout primitives");
+
+    if (vertices == TQualifier::layoutNotSet)
+        vertices = unit.vertices;
+    else if (vertices != unit.vertices) {
+        if (language == EShLangGeometry)
+            error(infoSink, "Contradictory layout max_vertices values");
+        else if (language == EShLangTessControl)
+            error(infoSink, "Contradictory layout vertices values");
+        else
+            assert(0);
+    }
+
+    if (vertexSpacing == EvsNone)
+        vertexSpacing = unit.vertexSpacing;
+    else if (vertexSpacing != unit.vertexSpacing)
+        error(infoSink, "Contradictory input vertex spacing");
+
+    if (vertexOrder == EvoNone)
+        vertexOrder = unit.vertexOrder;
+    else if (vertexOrder != unit.vertexOrder)
+        error(infoSink, "Contradictory triangle ordering");
+
+    if (unit.pointMode)
+        pointMode = true;
+
+    for (int i = 0; i < 3; ++i) {
+        if (localSize[i] > 1)
+            localSize[i] = unit.localSize[i];
+        else if (localSize[i] != unit.localSize[i])
+            error(infoSink, "Contradictory local size");
+
+        if (localSizeSpecId[i] != TQualifier::layoutNotSet)
+            localSizeSpecId[i] = unit.localSizeSpecId[i];
+        else if (localSizeSpecId[i] != unit.localSizeSpecId[i])
+            error(infoSink, "Contradictory local size specialization ids");
+    }
+
+    if (unit.xfbMode)
+        xfbMode = true;
+    for (size_t b = 0; b < xfbBuffers.size(); ++b) {
+        if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd)
+            xfbBuffers[b].stride = unit.xfbBuffers[b].stride;
+        else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
+            error(infoSink, "Contradictory xfb_stride");
+        xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
+        if (unit.xfbBuffers[b].containsDouble)
+            xfbBuffers[b].containsDouble = true;
+        // TODO: 4.4 link: enhanced layouts: compare ranges
+    }
+
+    if (unit.treeRoot == 0)
+        return;
+
+    if (treeRoot == 0) {
+        treeRoot = unit.treeRoot;
+        version = unit.version;
+        requestedExtensions = unit.requestedExtensions;
+        return;
+    }
+
+    // Getting this far means we have two existing trees to merge...
+
+    version = std::max(version, unit.version);
+    requestedExtensions.insert(unit.requestedExtensions.begin(), unit.requestedExtensions.end());
+
+    // Get the top-level globals of each unit
+    TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
+    TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
+
+    // Get the linker-object lists
+    TIntermSequence& linkerObjects = findLinkerObjects();
+    TIntermSequence& unitLinkerObjects = unit.findLinkerObjects();
+
+    mergeBodies(infoSink, globals, unitGlobals);
+    mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
+
+    ioAccessed.insert(unit.ioAccessed.begin(), unit.ioAccessed.end());
+}
+
+//
+// Merge the function bodies and global-level initializers from unitGlobals into globals.
+// Will error check duplication of function bodies for the same signature.
+//
+void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
+{
+    // TODO: link-time performance: Processing in alphabetical order will be faster
+
+    // Error check the global objects, not including the linker objects
+    for (unsigned int child = 0; child < globals.size() - 1; ++child) {
+        for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
+            TIntermAggregate* body = globals[child]->getAsAggregate();
+            TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
+            if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
+                error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
+                infoSink.info << "    " << globals[child]->getAsAggregate()->getName() << "\n";
+            }
+        }
+    }
+
+    // Merge the global objects, just in front of the linker objects
+    globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
+}
+
+//
+// Merge the linker objects from unitLinkerObjects into linkerObjects.
+// Duplication is expected and filtered out, but contradictions are an error.
+//
+void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
+{
+    // Error check and merge the linker objects (duplicates should not be created)
+    std::size_t initialNumLinkerObjects = linkerObjects.size();
+    for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
+        bool merge = true;
+        for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
+            TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
+            TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
+            assert(symbol && unitSymbol);
+            if (symbol->getName() == unitSymbol->getName()) {
+                // filter out copy
+                merge = false;
+
+                // but if one has an initializer and the other does not, update
+                // the initializer
+                if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty())
+                    symbol->setConstArray(unitSymbol->getConstArray());
+
+                // Similarly for binding
+                if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding())
+                    symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding;
+
+                // Update implicit array sizes
+                mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType());
+
+                // Check for consistent types/qualification/initializers etc.
+                mergeErrorCheck(infoSink, *symbol, *unitSymbol, false);
+            }
+        }
+        if (merge)
+            linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
+    }
+}
+
+// TODO 4.5 link functionality: cull distance array size checking
+
+// Recursively merge the implicit array sizes through the objects' respective type trees.
+void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType)
+{
+    if (type.isImplicitlySizedArray() && unitType.isArray()) {
+        int newImplicitArraySize = unitType.isImplicitlySizedArray() ? unitType.getImplicitArraySize() : unitType.getOuterArraySize();
+        if (newImplicitArraySize > type.getImplicitArraySize ())
+            type.setImplicitArraySize(newImplicitArraySize);
+    }
+
+    // Type mismatches are caught and reported after this, just be careful for now.
+    if (! type.isStruct() || ! unitType.isStruct() || type.getStruct()->size() != unitType.getStruct()->size())
+        return;
+
+    for (int i = 0; i < (int)type.getStruct()->size(); ++i)
+        mergeImplicitArraySizes(*(*type.getStruct())[i].type, *(*unitType.getStruct())[i].type);
+}
+
+//
+// Compare two global objects from two compilation units and see if they match
+// well enough.  Rules can be different for intra- vs. cross-stage matching.
+//
+// This function only does one of intra- or cross-stage matching per call.
+//
+void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
+{
+    bool writeTypeComparison = false;
+
+    // Types have to match
+    if (symbol.getType() != unitSymbol.getType()) {
+        error(infoSink, "Types must match:");
+        writeTypeComparison = true;
+    }
+
+    // Qualifiers have to (almost) match
+
+    // Storage...
+    if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
+        error(infoSink, "Storage qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Precision...
+    if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
+        error(infoSink, "Precision qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Invariance...
+    if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
+        error(infoSink, "Presence of invariant qualifier must match:");
+        writeTypeComparison = true;
+    }
+
+    // Precise...
+    if (! crossStage && symbol.getQualifier().noContraction != unitSymbol.getQualifier().noContraction) {
+        error(infoSink, "Presence of precise qualifier must match:");
+        writeTypeComparison = true;
+    }
+
+    // Auxiliary and interpolation...
+    if (symbol.getQualifier().centroid  != unitSymbol.getQualifier().centroid ||
+        symbol.getQualifier().smooth    != unitSymbol.getQualifier().smooth ||
+        symbol.getQualifier().flat      != unitSymbol.getQualifier().flat ||
+        symbol.getQualifier().sample    != unitSymbol.getQualifier().sample ||
+        symbol.getQualifier().patch     != unitSymbol.getQualifier().patch ||
+        symbol.getQualifier().nopersp   != unitSymbol.getQualifier().nopersp) {
+        error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Memory...
+    if (symbol.getQualifier().coherent  != unitSymbol.getQualifier().coherent ||
+        symbol.getQualifier().volatil   != unitSymbol.getQualifier().volatil ||
+        symbol.getQualifier().restrict  != unitSymbol.getQualifier().restrict ||
+        symbol.getQualifier().readonly  != unitSymbol.getQualifier().readonly ||
+        symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
+        error(infoSink, "Memory qualifiers must match:");
+        writeTypeComparison = true;
+    }
+
+    // Layouts...
+    // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec
+    //       requires separate user-supplied offset from actual computed offset, but
+    //       current implementation only has one offset.
+    if (symbol.getQualifier().layoutMatrix    != unitSymbol.getQualifier().layoutMatrix ||
+        symbol.getQualifier().layoutPacking   != unitSymbol.getQualifier().layoutPacking ||
+        symbol.getQualifier().layoutLocation  != unitSymbol.getQualifier().layoutLocation ||
+        symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent ||
+        symbol.getQualifier().layoutIndex     != unitSymbol.getQualifier().layoutIndex ||
+        symbol.getQualifier().layoutBinding   != unitSymbol.getQualifier().layoutBinding ||
+        (symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset))) {
+        error(infoSink, "Layout qualification must match:");
+        writeTypeComparison = true;
+    }
+
+    // Initializers have to match, if both are present, and if we don't already know the types don't match
+    if (! writeTypeComparison) {
+        if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) {
+            if (symbol.getConstArray() != unitSymbol.getConstArray()) {
+                error(infoSink, "Initializers must match:");
+                infoSink.info << "    " << symbol.getName() << "\n";
+            }
+        }
+    }
+
+    if (writeTypeComparison)
+        infoSink.info << "    " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
+                                                             unitSymbol.getType().getCompleteString() << "\"\n";
+}
+
+//
+// Do final link-time error checking of a complete (merged) intermediate representation.
+// (Much error checking was done during merging).
+//
+// Also, lock in defaults of things not set, including array sizes.
+//
+void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
+{
+    if (getTreeRoot() == nullptr)
+        return;
+
+    if (numEntryPoints < 1) {
+        if (source == EShSourceGlsl)
+            error(infoSink, "Missing entry point: Each stage requires one entry point");
+        else
+            warn(infoSink, "Entry point not found");
+    }
+
+    if (numPushConstants > 1)
+        error(infoSink, "Only one push_constant block is allowed per stage");
+
+    // recursion and missing body checking
+    checkCallGraphCycles(infoSink);
+    checkCallGraphBodies(infoSink, keepUncalled);
+
+    // overlap/alias/missing I/O, etc.
+    inOutLocationCheck(infoSink);
+
+    // invocations
+    if (invocations == TQualifier::layoutNotSet)
+        invocations = 1;
+
+    if (inIoAccessed("gl_ClipDistance") && inIoAccessed("gl_ClipVertex"))
+        error(infoSink, "Can only use one of gl_ClipDistance or gl_ClipVertex (gl_ClipDistance is preferred)");
+    if (inIoAccessed("gl_CullDistance") && inIoAccessed("gl_ClipVertex"))
+        error(infoSink, "Can only use one of gl_CullDistance or gl_ClipVertex (gl_ClipDistance is preferred)");
+
+    if (userOutputUsed() && (inIoAccessed("gl_FragColor") || inIoAccessed("gl_FragData")))
+        error(infoSink, "Cannot use gl_FragColor or gl_FragData when using user-defined outputs");
+    if (inIoAccessed("gl_FragColor") && inIoAccessed("gl_FragData"))
+        error(infoSink, "Cannot use both gl_FragColor and gl_FragData");
+
+    for (size_t b = 0; b < xfbBuffers.size(); ++b) {
+        if (xfbBuffers[b].containsDouble)
+            RoundToPow2(xfbBuffers[b].implicitStride, 8);
+
+        // "It is a compile-time or link-time error to have
+        // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or
+        // in different compilation units. While xfb_stride can be declared multiple times for the same buffer, it is a
+        // compile-time or link-time error to have different values specified for the stride for the same buffer."
+        if (xfbBuffers[b].stride != TQualifier::layoutXfbStrideEnd && xfbBuffers[b].implicitStride > xfbBuffers[b].stride) {
+            error(infoSink, "xfb_stride is too small to hold all buffer entries:");
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << ", minimum stride needed: " << xfbBuffers[b].implicitStride << "\n";
+        }
+        if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd)
+            xfbBuffers[b].stride = xfbBuffers[b].implicitStride;
+
+        // "If the buffer is capturing any
+        // outputs with double-precision components, the stride must be a multiple of 8, otherwise it must be a
+        // multiple of 4, or a compile-time or link-time error results."
+        if (xfbBuffers[b].containsDouble && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) {
+            error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double:");
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
+        } else if (! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
+            error(infoSink, "xfb_stride must be multiple of 4:");
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
+        }
+
+        // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
+        // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
+        if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) {
+            error(infoSink, "xfb_stride is too large:");
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "    xfb_buffer " << (unsigned int)b << ", components (1/4 stride) needed are " << xfbBuffers[b].stride/4 << ", gl_MaxTransformFeedbackInterleavedComponents is " << resources.maxTransformFeedbackInterleavedComponents << "\n";
+        }
+    }
+
+    switch (language) {
+    case EShLangVertex:
+        break;
+    case EShLangTessControl:
+        if (vertices == TQualifier::layoutNotSet)
+            error(infoSink, "At least one shader must specify an output layout(vertices=...)");
+        break;
+    case EShLangTessEvaluation:
+        if (inputPrimitive == ElgNone)
+            error(infoSink, "At least one shader must specify an input layout primitive");
+        if (vertexSpacing == EvsNone)
+            vertexSpacing = EvsEqual;
+        if (vertexOrder == EvoNone)
+            vertexOrder = EvoCcw;
+        break;
+    case EShLangGeometry:
+        if (inputPrimitive == ElgNone)
+            error(infoSink, "At least one shader must specify an input layout primitive");
+        if (outputPrimitive == ElgNone
+#ifdef NV_EXTENSIONS
+            && !getGeoPassthroughEXT()
+#endif
+            )
+            error(infoSink, "At least one shader must specify an output layout primitive");
+        if (vertices == TQualifier::layoutNotSet
+#ifdef NV_EXTENSIONS
+            && !getGeoPassthroughEXT()
+#endif
+           )
+            error(infoSink, "At least one shader must specify a layout(max_vertices = value)");
+        break;
+    case EShLangFragment:
+        break;
+    case EShLangCompute:
+        break;
+    default:
+        error(infoSink, "Unknown Stage.");
+        break;
+    }
+
+    // Process the tree for any node-specific work.
+    class TFinalLinkTraverser : public TIntermTraverser {
+    public:
+        TFinalLinkTraverser() { }
+        virtual ~TFinalLinkTraverser() { }
+
+        virtual void visitSymbol(TIntermSymbol* symbol)
+        {
+            // Implicitly size arrays.
+            symbol->getWritableType().adoptImplicitArraySizes();
+        }
+    } finalLinkTraverser;
+
+    treeRoot->traverse(&finalLinkTraverser);
+}
+
+//
+// See if the call graph contains any static recursion, which is disallowed
+// by the specification.
+//
+void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
+{
+    // Clear fields we'll use for this.
+    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        call->visited = false;
+        call->currentPath = false;
+        call->errorGiven = false;
+    }
+
+    //
+    // Loop, looking for a new connected subgraph.  One subgraph is handled per loop iteration.
+    //
+
+    TCall* newRoot;
+    do {
+        // See if we have unvisited parts of the graph.
+        newRoot = 0;
+        for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+            if (! call->visited) {
+                newRoot = &(*call);
+                break;
+            }
+        }
+
+        // If not, we are done.
+        if (! newRoot)
+            break;
+
+        // Otherwise, we found a new subgraph, process it:
+        // See what all can be reached by this new root, and if any of
+        // that is recursive.  This is done by depth-first traversals, seeing
+        // if a new call is found that was already in the currentPath (a back edge),
+        // thereby detecting recursion.
+        std::list<TCall*> stack;
+        newRoot->currentPath = true; // currentPath will be true iff it is on the stack
+        stack.push_back(newRoot);
+        while (! stack.empty()) {
+            // get a caller
+            TCall* call = stack.back();
+
+            // Add to the stack just one callee.
+            // This algorithm always terminates, because only !visited and !currentPath causes a push
+            // and all pushes change currentPath to true, and all pops change visited to true.
+            TGraph::iterator child = callGraph.begin();
+            for (; child != callGraph.end(); ++child) {
+
+                // If we already visited this node, its whole subgraph has already been processed, so skip it.
+                if (child->visited)
+                    continue;
+
+                if (call->callee == child->caller) {
+                    if (child->currentPath) {
+                        // Then, we found a back edge
+                        if (! child->errorGiven) {
+                            error(infoSink, "Recursion detected:");
+                            infoSink.info << "    " << call->callee << " calling " << child->callee << "\n";
+                            child->errorGiven = true;
+                            recursive = true;
+                        }
+                    } else {
+                        child->currentPath = true;
+                        stack.push_back(&(*child));
+                        break;
+                    }
+                }
+            }
+            if (child == callGraph.end()) {
+                // no more callees, we bottomed out, never look at this node again
+                stack.back()->currentPath = false;
+                stack.back()->visited = true;
+                stack.pop_back();
+            }
+        }  // end while, meaning nothing left to process in this subtree
+
+    } while (newRoot);  // redundant loop check; should always exit via the 'break' above
+}
+
+//
+// See which functions are reachable from the entry point and which have bodies.
+// Reachable ones with missing bodies are errors.
+// Unreachable bodies are dead code.
+//
+void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled)
+{
+    // Clear fields we'll use for this.
+    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        call->visited = false;
+        call->calleeBodyPosition = -1;
+    }
+
+    // The top level of the AST includes function definitions (bodies).
+    // Compare these to function calls in the call graph.
+    // We'll end up knowing which have bodies, and if so,
+    // how to map the call-graph node to the location in the AST.
+    TIntermSequence &functionSequence = getTreeRoot()->getAsAggregate()->getSequence();
+    std::vector<bool> reachable(functionSequence.size(), true); // so that non-functions are reachable
+    for (int f = 0; f < (int)functionSequence.size(); ++f) {
+        glslang::TIntermAggregate* node = functionSequence[f]->getAsAggregate();
+        if (node && (node->getOp() == glslang::EOpFunction)) {
+            if (node->getName().compare(getEntryPointMangledName().c_str()) != 0)
+                reachable[f] = false; // so that function bodies are unreachable, until proven otherwise
+            for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+                if (call->callee == node->getName())
+                    call->calleeBodyPosition = f;
+            }
+        }
+    }
+
+    // Start call-graph traversal by visiting the entry point nodes.
+    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        if (call->caller.compare(getEntryPointMangledName().c_str()) == 0)
+            call->visited = true;
+    }
+
+    // Propagate 'visited' through the call-graph to every part of the graph it
+    // can reach (seeded with the entry-point setting above).
+    bool changed;
+    do {
+        changed = false;
+        for (auto call1 = callGraph.begin(); call1 != callGraph.end(); ++call1) {
+            if (call1->visited) {
+                for (TGraph::iterator call2 = callGraph.begin(); call2 != callGraph.end(); ++call2) {
+                    if (! call2->visited) {
+                        if (call1->callee == call2->caller) {
+                            changed = true;
+                            call2->visited = true;
+                        }
+                    }
+                }
+            }
+        }
+    } while (changed);
+
+    // Any call-graph node set to visited but without a callee body is an error.
+    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        if (call->visited) {
+            if (call->calleeBodyPosition == -1) {
+                error(infoSink, "No function definition (body) found: ");
+                infoSink.info << "    " << call->callee << "\n";
+            } else
+                reachable[call->calleeBodyPosition] = true;
+        }
+    }
+
+    // Bodies in the AST not reached by the call graph are dead;
+    // clear them out, since they can't be reached and also can't
+    // be translated further due to possibility of being ill defined.
+    if (! keepUncalled) {
+        for (int f = 0; f < (int)functionSequence.size(); ++f) {
+            if (! reachable[f])
+                functionSequence[f] = nullptr;
+        }
+        functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end());
+    }
+}
+
+//
+// Satisfy rules for location qualifiers on inputs and outputs
+//
+void TIntermediate::inOutLocationCheck(TInfoSink& infoSink)
+{
+    // ES 3.0 requires all outputs to have location qualifiers if there is more than one output
+    bool fragOutWithNoLocation = false;
+    int numFragOut = 0;
+
+    // TODO: linker functionality: location collision checking
+
+    TIntermSequence& linkObjects = findLinkerObjects();
+    for (size_t i = 0; i < linkObjects.size(); ++i) {
+        const TType& type = linkObjects[i]->getAsTyped()->getType();
+        const TQualifier& qualifier = type.getQualifier();
+        if (language == EShLangFragment) {
+            if (qualifier.storage == EvqVaryingOut && qualifier.builtIn == EbvNone) {
+                ++numFragOut;
+                if (!qualifier.hasAnyLocation())
+                    fragOutWithNoLocation = true;
+            }
+        }
+    }
+
+    if (profile == EEsProfile) {
+        if (numFragOut > 1 && fragOutWithNoLocation)
+            error(infoSink, "when more than one fragment shader output, all must have location qualifiers");
+    }
+}
+
+TIntermSequence& TIntermediate::findLinkerObjects() const
+{
+    // Get the top-level globals
+    TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
+
+    // Get the last member of the sequences, expected to be the linker-object lists
+    assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
+
+    return globals.back()->getAsAggregate()->getSequence();
+}
+
+// See if a variable was both a user-declared output and used.
+// Note: the spec discusses writing to one, but this looks at read or write, which
+// is more useful, and perhaps the spec should be changed to reflect that.
+bool TIntermediate::userOutputUsed() const
+{
+    const TIntermSequence& linkerObjects = findLinkerObjects();
+
+    bool found = false;
+    for (size_t i = 0; i < linkerObjects.size(); ++i) {
+        const TIntermSymbol& symbolNode = *linkerObjects[i]->getAsSymbolNode();
+        if (symbolNode.getQualifier().storage == EvqVaryingOut &&
+            symbolNode.getName().compare(0, 3, "gl_") != 0 &&
+            inIoAccessed(symbolNode.getName())) {
+            found = true;
+            break;
+        }
+    }
+
+    return found;
+}
+
+// Accumulate locations used for inputs, outputs, and uniforms, and check for collisions
+// as the accumulation is done.
+//
+// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
+//
+// typeCollision is set to true if there is no direct collision, but the types in the same location
+// are different.
+//
+int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& type, bool& typeCollision)
+{
+    typeCollision = false;
+
+    int set;
+    if (qualifier.isPipeInput())
+        set = 0;
+    else if (qualifier.isPipeOutput())
+        set = 1;
+    else if (qualifier.storage == EvqUniform)
+        set = 2;
+    else if (qualifier.storage == EvqBuffer)
+        set = 3;
+    else
+        return -1;
+
+    int size;
+    if (qualifier.isUniformOrBuffer()) {
+        if (type.isExplicitlySizedArray())
+            size = type.getCumulativeArraySize();
+        else
+            size = 1;
+    } else {
+        // Strip off the outer array dimension for those having an extra one.
+        if (type.isArray() && qualifier.isArrayedIo(language)) {
+            TType elementType(type, 0);
+            size = computeTypeLocationSize(elementType);
+        } else
+            size = computeTypeLocationSize(type);
+    }
+
+    // Locations, and components within locations.
+    //
+    // Almost always, dealing with components means a single location is involved.
+    // The exception is a dvec3. From the spec:
+    //
+    // "A dvec3 will consume all four components of the first location and components 0 and 1 of
+    // the second location. This leaves components 2 and 3 available for other component-qualified
+    // declarations."
+    //
+    // That means, without ever mentioning a component, a component range
+    // for a different location gets specified, if it's not a vertex shader input. (!)
+    // (A vertex shader input will show using only one location, even for a dvec3/4.)
+    //
+    // So, for the case of dvec3, we need two independent ioRanges.
+
+    int collision = -1; // no collision
+    if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 &&
+        (qualifier.isPipeInput() || qualifier.isPipeOutput())) {
+        // Dealing with dvec3 in/out split across two locations.
+        // Need two io-ranges.
+        // The case where the dvec3 doesn't start at component 0 was previously caught as overflow.
+
+        // First range:
+        TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation);
+        TRange componentRange(0, 3);
+        TIoRange range(locationRange, componentRange, type.getBasicType(), 0);
+
+        // check for collisions
+        collision = checkLocationRange(set, range, type, typeCollision);
+        if (collision < 0) {
+            usedIo[set].push_back(range);
+
+            // Second range:
+            TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1);
+            TRange componentRange2(0, 1);
+            TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0);
+
+            // check for collisions
+            collision = checkLocationRange(set, range2, type, typeCollision);
+            if (collision < 0)
+                usedIo[set].push_back(range2);
+        }
+    } else {
+        // Not a dvec3 in/out split across two locations, generic path.
+        // Need a single IO-range block.
+
+        TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1);
+        TRange componentRange(0, 3);
+        if (qualifier.hasComponent() || type.getVectorSize() > 0) {
+            int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1);
+            if (qualifier.hasComponent())
+                componentRange.start = qualifier.layoutComponent;
+            componentRange.last  = componentRange.start + consumedComponents - 1;
+        }
+
+        // combine location and component ranges
+        TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0);
+
+        // check for collisions, except for vertex inputs on desktop
+        if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput()))
+            collision = checkLocationRange(set, range, type, typeCollision);
+
+        if (collision < 0)
+            usedIo[set].push_back(range);
+    }
+
+    return collision;
+}
+
+// Compare a new (the passed in) 'range' against the existing set, and see
+// if there are any collisions.
+//
+// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
+//
+int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision)
+{
+    for (size_t r = 0; r < usedIo[set].size(); ++r) {
+        if (range.overlap(usedIo[set][r])) {
+            // there is a collision; pick one
+            return std::max(range.location.start, usedIo[set][r].location.start);
+        } else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) {
+            // aliased-type mismatch
+            typeCollision = true;
+            return std::max(range.location.start, usedIo[set][r].location.start);
+        }
+    }
+
+    return -1; // no collision
+}
+
+// Accumulate locations used for inputs, outputs, and uniforms, and check for collisions
+// as the accumulation is done.
+//
+// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
+//
+int TIntermediate::addUsedOffsets(int binding, int offset, int numOffsets)
+{
+    TRange bindingRange(binding, binding);
+    TRange offsetRange(offset, offset + numOffsets - 1);
+    TOffsetRange range(bindingRange, offsetRange);
+
+    // check for collisions, except for vertex inputs on desktop
+    for (size_t r = 0; r < usedAtomics.size(); ++r) {
+        if (range.overlap(usedAtomics[r])) {
+            // there is a collision; pick one
+            return std::max(offset, usedAtomics[r].offset.start);
+        }
+    }
+
+    usedAtomics.push_back(range);
+
+    return -1; // no collision
+}
+
+// Accumulate used constant_id values.
+//
+// Return false is one was already used.
+bool TIntermediate::addUsedConstantId(int id)
+{
+    if (usedConstantId.find(id) != usedConstantId.end())
+        return false;
+
+    usedConstantId.insert(id);
+
+    return true;
+}
+
+// Recursively figure out how many locations are used up by an input or output type.
+// Return the size of type, as measured by "locations".
+int TIntermediate::computeTypeLocationSize(const TType& type) const
+{
+    // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n
+    // consecutive locations..."
+    if (type.isArray()) {
+        // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
+        TType elementType(type, 0);
+        if (type.isImplicitlySizedArray()) {
+            // TODO: are there valid cases of having an implicitly-sized array with a location?  If so, running this code too early.
+            return computeTypeLocationSize(elementType);
+        } else
+            return type.getOuterArraySize() * computeTypeLocationSize(elementType);
+    }
+
+    // "The locations consumed by block and structure members are determined by applying the rules above
+    // recursively..."
+    if (type.isStruct()) {
+        int size = 0;
+        for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
+            TType memberType(type, member);
+            size += computeTypeLocationSize(memberType);
+        }
+        return size;
+    }
+
+    // ES: "If a shader input is any scalar or vector type, it will consume a single location."
+
+    // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex
+    // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while
+    // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will
+    // consume only a single location, in all stages."
+    if (type.isScalar())
+        return 1;
+    if (type.isVector()) {
+        if (language == EShLangVertex && type.getQualifier().isPipeInput())
+            return 1;
+        if (type.getBasicType() == EbtDouble && type.getVectorSize() > 2)
+            return 2;
+        else
+            return 1;
+    }
+
+    // "If the declared input is an n x m single- or double-precision matrix, ...
+    // The number of locations assigned for each matrix will be the same as
+    // for an n-element array of m-component vectors..."
+    if (type.isMatrix()) {
+        TType columnType(type, 0);
+        return type.getMatrixCols() * computeTypeLocationSize(columnType);
+    }
+
+    assert(0);
+    return 1;
+}
+
+// Accumulate xfb buffer ranges and check for collisions as the accumulation is done.
+//
+// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
+//
+int TIntermediate::addXfbBufferOffset(const TType& type)
+{
+    const TQualifier& qualifier = type.getQualifier();
+
+    assert(qualifier.hasXfbOffset() && qualifier.hasXfbBuffer());
+    TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer];
+
+    // compute the range
+    unsigned int size = computeTypeXfbSize(type, buffer.containsDouble);
+    buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size);
+    TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1);
+
+    // check for collisions
+    for (size_t r = 0; r < buffer.ranges.size(); ++r) {
+        if (range.overlap(buffer.ranges[r])) {
+            // there is a collision; pick an example to return
+            return std::max(range.start, buffer.ranges[r].start);
+        }
+    }
+
+    buffer.ranges.push_back(range);
+
+    return -1;  // no collision
+}
+
+// Recursively figure out how many bytes of xfb buffer are used by the given type.
+// Return the size of type, in bytes.
+// Sets containsDouble to true if the type contains a double.
+// N.B. Caller must set containsDouble to false before calling.
+unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& containsDouble) const
+{
+    // "...if applied to an aggregate containing a double, the offset must also be a multiple of 8,
+    // and the space taken in the buffer will be a multiple of 8.
+    // ...within the qualified entity, subsequent components are each
+    // assigned, in order, to the next available offset aligned to a multiple of
+    // that component's size.  Aggregate types are flattened down to the component
+    // level to get this sequence of components."
+
+    if (type.isArray()) {
+        // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
+        assert(type.isExplicitlySizedArray());
+        TType elementType(type, 0);
+        return type.getOuterArraySize() * computeTypeXfbSize(elementType, containsDouble);
+    }
+
+    if (type.isStruct()) {
+        unsigned int size = 0;
+        bool structContainsDouble = false;
+        for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
+            TType memberType(type, member);
+            // "... if applied to
+            // an aggregate containing a double, the offset must also be a multiple of 8,
+            // and the space taken in the buffer will be a multiple of 8."
+            bool memberContainsDouble = false;
+            int memberSize = computeTypeXfbSize(memberType, memberContainsDouble);
+            if (memberContainsDouble) {
+                structContainsDouble = true;
+                RoundToPow2(size, 8);
+            }
+            size += memberSize;
+        }
+
+        if (structContainsDouble) {
+            containsDouble = true;
+            RoundToPow2(size, 8);
+        }
+        return size;
+    }
+
+    int numComponents;
+    if (type.isScalar())
+        numComponents = 1;
+    else if (type.isVector())
+        numComponents = type.getVectorSize();
+    else if (type.isMatrix())
+        numComponents = type.getMatrixCols() * type.getMatrixRows();
+    else {
+        assert(0);
+        numComponents = 1;
+    }
+
+    if (type.getBasicType() == EbtDouble) {
+        containsDouble = true;
+        return 8 * numComponents;
+    } else
+        return 4 * numComponents;
+}
+
+const int baseAlignmentVec4Std140 = 16;
+
+// Return the size and alignment of a scalar.
+// The size is returned in the 'size' parameter
+// Return value is the alignment of the type.
+int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
+{
+    switch (type.getBasicType()) {
+    case EbtInt64:
+    case EbtUint64:
+    case EbtDouble:  size = 8; return 8;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16: size = 2; return 2;
+#endif
+    default:         size = 4; return 4;
+    }
+}
+
+// Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout
+// Operates recursively.
+//
+// If std140 is true, it does the rounding up to vec4 size required by std140,
+// otherwise it does not, yielding std430 rules.
+//
+// The size is returned in the 'size' parameter
+//
+// The stride is only non-0 for arrays or matrices, and is the stride of the
+// top-level object nested within the type.  E.g., for an array of matrices,
+// it is the distances needed between matrices, despite the rules saying the
+// stride comes from the flattening down to vectors.
+//
+// Return value is the alignment of the type.
+int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, bool std140, bool rowMajor)
+{
+    int alignment;
+
+    // When using the std140 storage layout, structures will be laid out in buffer
+    // storage with its members stored in monotonically increasing order based on their
+    // location in the declaration. A structure and each structure member have a base
+    // offset and a base alignment, from which an aligned offset is computed by rounding
+    // the base offset up to a multiple of the base alignment. The base offset of the first
+    // member of a structure is taken from the aligned offset of the structure itself. The
+    // base offset of all other structure members is derived by taking the offset of the
+    // last basic machine unit consumed by the previous member and adding one. Each
+    // structure member is stored in memory at its aligned offset. The members of a top-
+    // level uniform block are laid out in buffer storage by treating the uniform block as
+    // a structure with a base offset of zero.
+    //
+    //   1. If the member is a scalar consuming N basic machine units, the base alignment is N.
+    //
+    //   2. If the member is a two- or four-component vector with components consuming N basic
+    //      machine units, the base alignment is 2N or 4N, respectively.
+    //
+    //   3. If the member is a three-component vector with components consuming N
+    //      basic machine units, the base alignment is 4N.
+    //
+    //   4. If the member is an array of scalars or vectors, the base alignment and array
+    //      stride are set to match the base alignment of a single array element, according
+    //      to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The
+    //      array may have padding at the end; the base offset of the member following
+    //      the array is rounded up to the next multiple of the base alignment.
+    //
+    //   5. If the member is a column-major matrix with C columns and R rows, the
+    //      matrix is stored identically to an array of C column vectors with R
+    //      components each, according to rule (4).
+    //
+    //   6. If the member is an array of S column-major matrices with C columns and
+    //      R rows, the matrix is stored identically to a row of S X C column vectors
+    //      with R components each, according to rule (4).
+    //
+    //   7. If the member is a row-major matrix with C columns and R rows, the matrix
+    //      is stored identically to an array of R row vectors with C components each,
+    //      according to rule (4).
+    //
+    //   8. If the member is an array of S row-major matrices with C columns and R
+    //      rows, the matrix is stored identically to a row of S X R row vectors with C
+    //      components each, according to rule (4).
+    //
+    //   9. If the member is a structure, the base alignment of the structure is N , where
+    //      N is the largest base alignment value of any    of its members, and rounded
+    //      up to the base alignment of a vec4. The individual members of this substructure
+    //      are then assigned offsets by applying this set of rules recursively,
+    //      where the base offset of the first member of the sub-structure is equal to the
+    //      aligned offset of the structure. The structure may have padding at the end;
+    //      the base offset of the member following the sub-structure is rounded up to
+    //      the next multiple of the base alignment of the structure.
+    //
+    //   10. If the member is an array of S structures, the S elements of the array are laid
+    //       out in order, according to rule (9).
+    //
+    //   Assuming, for rule 10:  The stride is the same as the size of an element.
+
+    stride = 0;
+    int dummyStride;
+
+    // rules 4, 6, 8, and 10
+    if (type.isArray()) {
+        // TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
+        TType derefType(type, 0);
+        alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
+        if (std140)
+            alignment = std::max(baseAlignmentVec4Std140, alignment);
+        RoundToPow2(size, alignment);
+        stride = size;  // uses full matrix size for stride of an array of matrices (not quite what rule 6/8, but what's expected)
+                        // uses the assumption for rule 10 in the comment above
+        size = stride * type.getOuterArraySize();
+        return alignment;
+    }
+
+    // rule 9
+    if (type.getBasicType() == EbtStruct) {
+        const TTypeList& memberList = *type.getStruct();
+
+        size = 0;
+        int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;
+        for (size_t m = 0; m < memberList.size(); ++m) {
+            int memberSize;
+            // modify just the children's view of matrix layout, if there is one for this member
+            TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
+            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, std140,
+                                                   (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor);
+            maxAlignment = std::max(maxAlignment, memberAlignment);
+            RoundToPow2(size, memberAlignment);
+            size += memberSize;
+        }
+
+        // The structure may have padding at the end; the base offset of
+        // the member following the sub-structure is rounded up to the next
+        // multiple of the base alignment of the structure.
+        RoundToPow2(size, maxAlignment);
+
+        return maxAlignment;
+    }
+
+    // rule 1
+    if (type.isScalar())
+        return getBaseAlignmentScalar(type, size);
+
+    // rules 2 and 3
+    if (type.isVector()) {
+        int scalarAlign = getBaseAlignmentScalar(type, size);
+        switch (type.getVectorSize()) {
+        case 2:
+            size *= 2;
+            return 2 * scalarAlign;
+        default:
+            size *= type.getVectorSize();
+            return 4 * scalarAlign;
+        }
+    }
+
+    // rules 5 and 7
+    if (type.isMatrix()) {
+        // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows
+        TType derefType(type, 0, rowMajor);
+
+        alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
+        if (std140)
+            alignment = std::max(baseAlignmentVec4Std140, alignment);
+        RoundToPow2(size, alignment);
+        stride = size;  // use intra-matrix stride for stride of a just a matrix
+        if (rowMajor)
+            size = stride * type.getMatrixRows();
+        else
+            size = stride * type.getMatrixCols();
+
+        return alignment;
+    }
+
+    assert(0);  // all cases should be covered above
+    size = baseAlignmentVec4Std140;
+    return baseAlignmentVec4Std140;
+}
+
+} // end namespace glslang

+ 505 - 0
src/libraries/glslang/glslang/MachineIndependent/localintermediate.h

@@ -0,0 +1,505 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2016 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
+#define _LOCAL_INTERMEDIATE_INCLUDED_
+
+#include "../Include/intermediate.h"
+#include "../Public/ShaderLang.h"
+#include "Versions.h"
+
+#include <algorithm>
+#include <set>
+
+class TInfoSink;
+
+namespace glslang {
+
+struct TMatrixSelector {
+    int coord1;  // stay agnostic about column/row; this is parse order
+    int coord2;
+};
+
+typedef int TVectorSelector;
+
+const int MaxSwizzleSelectors = 4;
+
+template<typename selectorType>
+class TSwizzleSelectors {
+public:
+    TSwizzleSelectors() : size_(0) { }
+
+    void push_back(selectorType comp)
+    {
+        if (size_ < MaxSwizzleSelectors)
+            components[size_++] = comp;
+    }
+    void resize(int s)
+    {
+        assert(s <= size_);
+        size_ = s;
+    }
+    int size() const { return size_; }
+    selectorType operator[](int i) const
+    {
+        assert(i < MaxSwizzleSelectors);
+        return components[i];
+    }
+    
+private:
+    int size_;
+    selectorType components[MaxSwizzleSelectors];
+};
+
+//
+// Some helper structures for TIntermediate.  Their contents are encapsulated
+// by TIntermediate.
+//
+
+// Used for call-graph algorithms for detecting recursion, missing bodies, and dead bodies.
+// A "call" is a pair: <caller, callee>.
+// There can be duplicates. General assumption is the list is small.
+struct TCall {
+    TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
+    TString caller;
+    TString callee;
+    bool visited;
+    bool currentPath;
+    bool errorGiven;
+    int calleeBodyPosition;
+};
+
+// A generic 1-D range.
+struct TRange {
+    TRange(int start, int last) : start(start), last(last) { }
+    bool overlap(const TRange& rhs) const
+    {
+        return last >= rhs.start && start <= rhs.last;
+    }
+    int start;
+    int last;
+};
+
+// An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
+// within the same location range, component range, and index value.  Locations don't alias unless
+// all other dimensions of their range overlap.
+struct TIoRange {
+    TIoRange(TRange location, TRange component, TBasicType basicType, int index)
+        : location(location), component(component), basicType(basicType), index(index) { }
+    bool overlap(const TIoRange& rhs) const
+    {
+        return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
+    }
+    TRange location;
+    TRange component;
+    TBasicType basicType;
+    int index;
+};
+
+// An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
+// within the same binding and offset range.
+struct TOffsetRange {
+    TOffsetRange(TRange binding, TRange offset)
+        : binding(binding), offset(offset) { }
+    bool overlap(const TOffsetRange& rhs) const
+    {
+        return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
+    }
+    TRange binding;
+    TRange offset;
+};
+
+// Things that need to be tracked per xfb buffer.
+struct TXfbBuffer {
+    TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
+    std::vector<TRange> ranges;  // byte offsets that have already been assigned
+    unsigned int stride;
+    unsigned int implicitStride;
+    bool containsDouble;
+};
+
+class TSymbolTable;
+class TSymbol;
+class TVariable;
+
+//
+// Set of helper functions to help parse and build the tree.
+//
+class TIntermediate {
+public:
+    explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
+        language(l), source(EShSourceNone), profile(p), version(v), treeRoot(0),
+        numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
+        invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone),
+        pixelCenterInteger(false), originUpperLeft(false),
+        vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0),
+        xfbMode(false), multiStream(false),
+#ifdef NV_EXTENSIONS
+        layoutOverrideCoverage(false),
+        geoPassthroughEXT(false),
+#endif
+        shiftSamplerBinding(0),
+        shiftTextureBinding(0),
+        shiftImageBinding(0),
+        shiftUboBinding(0),
+        autoMapBindings(false),
+        flattenUniformArrays(false),
+        useUnknownFormat(false)
+    {
+        localSize[0] = 1;
+        localSize[1] = 1;
+        localSize[2] = 1;
+        localSizeSpecId[0] = TQualifier::layoutNotSet;
+        localSizeSpecId[1] = TQualifier::layoutNotSet;
+        localSizeSpecId[2] = TQualifier::layoutNotSet;
+        xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
+    }
+    void setLimits(const TBuiltInResource& r) { resources = r; }
+
+    bool postProcess(TIntermNode*, EShLanguage);
+    void output(TInfoSink&, bool tree);
+    void removeTree();
+
+    void setSource(EShSource s) { source = s; }
+    EShSource getSource() const { return source; }
+    void setEntryPointName(const char* ep) { entryPointName = ep; }
+    void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
+    const std::string& getEntryPointName() const { return entryPointName; }
+    const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
+
+    void setShiftSamplerBinding(unsigned int shift) { shiftSamplerBinding = shift; }
+    unsigned int getShiftSamplerBinding() const { return shiftSamplerBinding; }
+    void setShiftTextureBinding(unsigned int shift) { shiftTextureBinding = shift; }
+    unsigned int getShiftTextureBinding() const { return shiftTextureBinding; }
+    void setShiftImageBinding(unsigned int shift) { shiftImageBinding = shift; }
+    unsigned int getShiftImageBinding() const { return shiftImageBinding; }
+    void setShiftUboBinding(unsigned int shift)     { shiftUboBinding = shift; }
+    unsigned int getShiftUboBinding()     const { return shiftUboBinding; }
+    void setAutoMapBindings(bool map)               { autoMapBindings = map; }
+    bool getAutoMapBindings()             const { return autoMapBindings; }
+    void setFlattenUniformArrays(bool flatten)      { flattenUniformArrays = flatten; }
+    bool getFlattenUniformArrays()        const { return flattenUniformArrays; }
+    void setNoStorageFormat(bool b)             { useUnknownFormat = b; }
+    bool getNoStorageFormat()             const { return useUnknownFormat; }
+
+    void setVersion(int v) { version = v; }
+    int getVersion() const { return version; }
+    void setProfile(EProfile p) { profile = p; }
+    EProfile getProfile() const { return profile; }
+    void setSpv(const SpvVersion& s) { spvVersion = s; }
+    const SpvVersion& getSpv() const { return spvVersion; }
+    EShLanguage getStage() const { return language; }
+    void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
+    const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
+
+    void setTreeRoot(TIntermNode* r) { treeRoot = r; }
+    TIntermNode* getTreeRoot() const { return treeRoot; }
+    void incrementEntryPointCount() { ++numEntryPoints; }
+    int getNumEntryPoints() const { return numEntryPoints; }
+    int getNumErrors() const { return numErrors; }
+    void addPushConstantCount() { ++numPushConstants; }
+    bool isRecursive() const { return recursive; }
+
+    TIntermSymbol* addSymbol(const TVariable&);
+    TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
+    TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
+    TIntermSymbol* addSymbol(const TIntermSymbol&);
+    TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
+    TIntermTyped* addShapeConversion(TOperator, const TType&, TIntermTyped*);
+    TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+    TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+    TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
+    TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc);
+    TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
+    bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
+    TOperator mapTypeToConstructorOp(const TType&) const;
+    TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
+    TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
+    TIntermAggregate* makeAggregate(TIntermNode* node);
+    TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
+    TIntermAggregate* makeAggregate(const TSourceLoc&);
+    TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
+    bool areAllChildConst(TIntermAggregate* aggrNode);
+    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&);
+    TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
+    TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
+    TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
+    bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
+    TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
+    TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
+    TIntermBranch* addBranch(TOperator, const TSourceLoc&);
+    TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
+    template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
+
+    // Low level functions to add nodes (no conversions or other higher level transformations)
+    // If a type is provided, the node's type will be set to it.
+    TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const;
+    TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const;
+    TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const;
+    TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const;
+
+    // Add conversion from node's type to given basic type.
+    TIntermTyped* convertToBasicType(TOperator op, TBasicType basicType, TIntermTyped* node) const;
+
+    // Constant folding (in Constant.cpp)
+    TIntermTyped* fold(TIntermAggregate* aggrNode);
+    TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
+    TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
+    TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
+
+    // Tree ops
+    static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay);
+
+    // Linkage related
+    void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
+    void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
+
+    bool setInvocations(int i)
+    {
+        if (invocations != TQualifier::layoutNotSet)
+            return invocations == i;
+        invocations = i;
+        return true;
+    }
+    int getInvocations() const { return invocations; }
+    bool setVertices(int m)
+    {
+        if (vertices != TQualifier::layoutNotSet)
+            return vertices == m;
+        vertices = m;
+        return true;
+    }
+    int getVertices() const { return vertices; }
+    bool setInputPrimitive(TLayoutGeometry p)
+    {
+        if (inputPrimitive != ElgNone)
+            return inputPrimitive == p;
+        inputPrimitive = p;
+        return true;
+    }
+    TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
+    bool setVertexSpacing(TVertexSpacing s)
+    {
+        if (vertexSpacing != EvsNone)
+            return vertexSpacing == s;
+        vertexSpacing = s;
+        return true;
+    }
+    TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
+    bool setVertexOrder(TVertexOrder o)
+    {
+        if (vertexOrder != EvoNone)
+            return vertexOrder == o;
+        vertexOrder = o;
+        return true;
+    }
+    TVertexOrder getVertexOrder() const { return vertexOrder; }
+    void setPointMode() { pointMode = true; }
+    bool getPointMode() const { return pointMode; }
+
+    bool setLocalSize(int dim, int size)
+    {
+        if (localSize[dim] > 1)
+            return size == localSize[dim];
+        localSize[dim] = size;
+        return true;
+    }
+    unsigned int getLocalSize(int dim) const { return localSize[dim]; }
+
+    bool setLocalSizeSpecId(int dim, int id)
+    {
+        if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
+            return id == localSizeSpecId[dim];
+        localSizeSpecId[dim] = id;
+        return true;
+    }
+    int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
+
+    void setXfbMode() { xfbMode = true; }
+    bool getXfbMode() const { return xfbMode; }
+    void setMultiStream() { multiStream = true; }
+    bool isMultiStream() const { return multiStream; }
+    bool setOutputPrimitive(TLayoutGeometry p)
+    {
+        if (outputPrimitive != ElgNone)
+            return outputPrimitive == p;
+        outputPrimitive = p;
+        return true;
+    }
+    TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
+    void setOriginUpperLeft() { originUpperLeft = true; }
+    bool getOriginUpperLeft() const { return originUpperLeft; }
+    void setPixelCenterInteger() { pixelCenterInteger = true; }
+    bool getPixelCenterInteger() const { return pixelCenterInteger; }
+    void setEarlyFragmentTests() { earlyFragmentTests = true; }
+    bool getEarlyFragmentTests() const { return earlyFragmentTests; }
+    bool setDepth(TLayoutDepth d)
+    {
+        if (depthLayout != EldNone)
+            return depthLayout == d;
+        depthLayout = d;
+        return true;
+    }
+    TLayoutDepth getDepth() const { return depthLayout; }
+    void setDepthReplacing() { depthReplacing = true; }
+    bool isDepthReplacing() const { return depthReplacing; }
+
+    void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
+    unsigned int getBlendEquations() const { return blendEquations; }
+
+    void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
+    void merge(TInfoSink&, TIntermediate&);
+    void finalCheck(TInfoSink&, bool keepUncalled);
+
+    void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
+    bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
+
+    int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
+    int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
+    int addUsedOffsets(int binding, int offset, int numOffsets);
+    bool addUsedConstantId(int id);
+    int computeTypeLocationSize(const TType&) const;
+
+    bool setXfbBufferStride(int buffer, unsigned stride)
+    {
+        if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
+            return xfbBuffers[buffer].stride == stride;
+        xfbBuffers[buffer].stride = stride;
+        return true;
+    }
+    int addXfbBufferOffset(const TType&);
+    unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
+    static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
+    bool promote(TIntermOperator*);
+
+#ifdef NV_EXTENSIONS
+    void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
+    bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
+    void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
+    bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
+#endif
+
+protected:
+    TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
+    void error(TInfoSink& infoSink, const char*);
+    void warn(TInfoSink& infoSink, const char*);
+    void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
+    void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
+    void mergeImplicitArraySizes(TType&, const TType&);
+    void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
+    void checkCallGraphCycles(TInfoSink&);
+    void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
+    void inOutLocationCheck(TInfoSink&);
+    TIntermSequence& findLinkerObjects() const;
+    bool userOutputUsed() const;
+    static int getBaseAlignmentScalar(const TType&, int& size);
+    bool isSpecializationOperation(const TIntermOperator&) const;
+    bool promoteUnary(TIntermUnary&);
+    bool promoteBinary(TIntermBinary&);
+    void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
+    bool promoteAggregate(TIntermAggregate&);
+    void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
+    void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
+
+    const EShLanguage language;  // stage, known at construction time
+    EShSource source;            // source language, known a bit later
+    std::string entryPointName;
+    std::string entryPointMangledName;
+
+    EProfile profile;
+    int version;
+    SpvVersion spvVersion;
+    TIntermNode* treeRoot;
+    std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
+    TBuiltInResource resources;
+    int numEntryPoints;
+    int numErrors;
+    int numPushConstants;
+    bool recursive;
+    int invocations;
+    int vertices;
+    TLayoutGeometry inputPrimitive;
+    TLayoutGeometry outputPrimitive;
+    bool pixelCenterInteger;
+    bool originUpperLeft;
+    TVertexSpacing vertexSpacing;
+    TVertexOrder vertexOrder;
+    bool pointMode;
+    int localSize[3];
+    int localSizeSpecId[3];
+    bool earlyFragmentTests;
+    TLayoutDepth depthLayout;
+    bool depthReplacing;
+    int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
+    bool xfbMode;
+    bool multiStream;
+
+#ifdef NV_EXTENSIONS
+    bool layoutOverrideCoverage;
+    bool geoPassthroughEXT;
+#endif
+
+    unsigned int shiftSamplerBinding;
+    unsigned int shiftTextureBinding;
+    unsigned int shiftImageBinding;
+    unsigned int shiftUboBinding;
+    bool autoMapBindings;
+    bool flattenUniformArrays;
+    bool useUnknownFormat;
+
+    typedef std::list<TCall> TGraph;
+    TGraph callGraph;
+
+    std::set<TString> ioAccessed;           // set of names of statically read/written I/O that might need extra checking
+    std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
+    std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
+    std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
+    std::unordered_set<int> usedConstantId; // specialization constant ids used
+
+private:
+    void operator=(TIntermediate&); // prevent assignments
+};
+
+} // end namespace glslang
+
+#endif // _LOCAL_INTERMEDIATE_INCLUDED_

+ 210 - 0
src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp

@@ -0,0 +1,210 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Traverse a tree of constants to create a single folded constant.
+// It should only be used when the whole tree is known to be constant.
+//
+
+#include "ParseHelper.h"
+
+namespace glslang {
+
+class TConstTraverser : public TIntermTraverser {
+public:
+    TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t)
+      : unionArray(cUnion), type(t),
+        constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false),
+        matrixCols(0), matrixRows(0) {  index = 0; tOp = EOpNull; }
+
+    virtual void visitConstantUnion(TIntermConstantUnion* node);
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
+
+    int index;
+    TConstUnionArray unionArray;
+    TOperator tOp;
+    const TType& type;
+    TOperator constructorType;
+    bool singleConstantParam;
+    bool error;
+    int size; // size of the constructor ( 4 for vec4)
+    bool isMatrix;
+    int matrixCols;
+    int matrixRows;
+
+protected:
+    TConstTraverser(TConstTraverser&);
+    TConstTraverser& operator=(TConstTraverser&);
+};
+
+bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
+{
+    if (! node->isConstructor() && node->getOp() != EOpComma) {
+        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().computeNumComponents();
+
+        if (node->getType().isMatrix()) {
+            isMatrix = true;
+            matrixCols = node->getType().getMatrixCols();
+            matrixRows = node->getType().getMatrixRows();
+        }
+    }
+
+    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;
+        matrixCols = 0;
+        matrixRows = 0;
+    }
+
+    return false;
+}
+
+void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+    TConstUnionArray leftUnionArray(unionArray);
+    int instanceSize = type.computeNumComponents();
+
+    if (index >= instanceSize)
+        return;
+
+    if (! singleConstantParam) {
+        int rightUnionSize = node->getType().computeNumComponents();
+
+        const TConstUnionArray& rightUnionArray = node->getConstArray();
+        for (int i = 0; i < rightUnionSize; i++) {
+            if (index >= instanceSize)
+                return;
+            leftUnionArray[index] = rightUnionArray[i];
+
+            index++;
+        }
+    } else {
+        int endIndex = index + size;
+        const TConstUnionArray& rightUnionArray = node->getConstArray();
+        if (! isMatrix) {
+            int count = 0;
+            int nodeComps = node->getType().computeNumComponents();
+            for (int i = index; i < endIndex; i++) {
+                if (i >= instanceSize)
+                    return;
+
+                leftUnionArray[i] = rightUnionArray[count];
+
+                (index)++;
+
+                if (nodeComps > 1)
+                    count++;
+            }
+        } else {
+            // constructing a matrix, but from what?
+            if (node->isMatrix()) {
+                // Matrix from a matrix; this has the outer matrix, node is the argument matrix.
+                // Traverse the outer, potentially bigger matrix, fill in missing pieces with the
+                // identity matrix.
+                for (int c = 0; c < matrixCols; ++c) {
+                    for (int r = 0; r < matrixRows; ++r) {
+                        int targetOffset = index + c * matrixRows + r;
+                        if (r < node->getType().getMatrixRows() && c < node->getType().getMatrixCols()) {
+                            int srcOffset = c * node->getType().getMatrixRows() + r;
+                            leftUnionArray[targetOffset] = rightUnionArray[srcOffset];
+                        } else if (r == c)
+                            leftUnionArray[targetOffset].setDConst(1.0);
+                        else
+                            leftUnionArray[targetOffset].setDConst(0.0);
+                    }
+                }
+            } else {
+                // matrix from vector
+                int count = 0;
+                const int startIndex = index;
+                int nodeComps = node->getType().computeNumComponents();
+                for (int i = startIndex; i < endIndex; i++) {
+                    if (i >= instanceSize)
+                        return;
+                    if (i == startIndex || (i - startIndex) % (matrixRows + 1) == 0 )
+                        leftUnionArray[i] = rightUnionArray[count];
+                    else
+                        leftUnionArray[i].setDConst(0.0);
+
+                    index++;
+
+                    if (nodeComps > 1)
+                        count++;
+                }
+            }
+        }
+    }
+}
+
+bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
+{
+    if (root == 0)
+        return false;
+
+    TConstTraverser it(unionArray, singleConstantParam, constructorType, t);
+
+    root->traverse(&it);
+    if (it.error)
+        return true;
+    else
+        return false;
+}
+
+} // end namespace glslang

+ 138 - 0
src/libraries/glslang/glslang/MachineIndependent/parseVersions.h

@@ -0,0 +1,138 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+// This is implemented in Versions.cpp
+
+#ifndef _PARSE_VERSIONS_INCLUDED_
+#define _PARSE_VERSIONS_INCLUDED_
+
+#include "../Public/ShaderLang.h"
+#include "../Include/InfoSink.h"
+#include "Scan.h"
+
+#include <map>
+
+namespace glslang {
+
+//
+// Base class for parse helpers.
+// This just has version-related information and checking.
+// This class should be sufficient for preprocessing.
+//
+class TParseVersions {
+public:
+    TParseVersions(TIntermediate& interm, int version, EProfile profile,
+                   const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink,
+                   bool forwardCompatible, EShMessages messages)
+        : infoSink(infoSink), version(version), profile(profile), language(language),
+          spvVersion(spvVersion), forwardCompatible(forwardCompatible),
+          intermediate(interm), messages(messages), numErrors(0), currentScanner(0) { }
+    virtual ~TParseVersions() { }
+    virtual void initializeExtensionBehavior();
+    virtual void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc);
+    virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc);
+    virtual void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc);
+    virtual void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc);
+    virtual void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
+    virtual void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
+    virtual void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual TExtensionBehavior getExtensionBehavior(const char*);
+    virtual bool extensionTurnedOn(const char* const extension);
+    virtual bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
+    virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
+    virtual void fullIntegerCheck(const TSourceLoc&, const char* op);
+    virtual void doubleCheck(const TSourceLoc&, const char* op);
+#ifdef AMD_EXTENSIONS
+    virtual void float16Check(const TSourceLoc&, const char* op, bool builtIn = false);
+#endif
+    virtual void int64Check(const TSourceLoc&, const char* op, bool builtIn = false);
+    virtual void spvRemoved(const TSourceLoc&, const char* op);
+    virtual void vulkanRemoved(const TSourceLoc&, const char* op);
+    virtual void requireVulkan(const TSourceLoc&, const char* op);
+    virtual void requireSpv(const TSourceLoc&, const char* op);
+    virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
+
+    virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL  warn(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+
+    void addError() { ++numErrors; }
+    int getNumErrors() const { return numErrors; }
+
+    void setScanner(TInputScanner* scanner) { currentScanner = scanner; }
+    TInputScanner* getScanner() const { return currentScanner; }
+    const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
+    void setCurrentLine(int line) { currentScanner->setLine(line); }
+    void setCurrentColumn(int col) { currentScanner->setColumn(col); }
+    void setCurrentSourceName(const char* name) { currentScanner->setFile(name); }
+    void setCurrentString(int string) { currentScanner->setString(string); }
+
+    void getPreamble(std::string&);
+    bool relaxedErrors()    const { return (messages & EShMsgRelaxedErrors) != 0; }
+    bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
+    bool isReadingHLSL()    const { return (messages & EShMsgReadHlsl) == EShMsgReadHlsl; }
+
+    TInfoSink& infoSink;
+
+    // compilation mode
+    int version;                 // version, updated by #version in the shader
+    EProfile profile;            // the declared profile in the shader (core by default)
+    EShLanguage language;        // really the stage
+    SpvVersion spvVersion;
+    bool forwardCompatible;      // true if errors are to be given for use of deprecated features
+    TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree
+
+protected:
+    TMap<TString, TExtensionBehavior> extensionBehavior;    // for each extension string, what its current behavior is set to
+    EShMessages messages;        // errors/warnings/rule-sets
+    int numErrors;               // number of compile-time errors encountered
+    TInputScanner* currentScanner;
+
+private:
+    explicit TParseVersions(const TParseVersions&);
+    TParseVersions& operator=(const TParseVersions&);
+};
+
+} // end namespace glslang
+
+#endif // _PARSE_VERSIONS_INCLUDED_

+ 1278 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp

@@ -0,0 +1,1278 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <sstream>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+#include "PpContext.h"
+#include "PpTokens.h"
+
+namespace glslang {
+
+// Handle #define
+int TPpContext::CPPdefine(TPpToken* ppToken)
+{
+    MacroSymbol mac;
+
+    // get the macro name
+    int token = scanToken(ppToken);
+    if (token != PpAtomIdentifier) {
+        parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
+        return token;
+    }
+    if (ppToken->loc.string >= 0) {
+        // We are in user code; check for reserved name use:
+        parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
+    }
+
+    // save the macro name
+    const int defAtom = atomStrings.getAddAtom(ppToken->name);
+
+    // gather parameters to the macro, between (...)
+    token = scanToken(ppToken);
+    if (token == '(' && ! ppToken->space) {
+        mac.emptyArgs = 1;
+        do {
+            token = scanToken(ppToken);
+            if (mac.args.size() == 0 && token == ')')
+                break;
+            if (token != PpAtomIdentifier) {
+                parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
+
+                return token;
+            }
+            mac.emptyArgs = 0;
+            const int argAtom = atomStrings.getAddAtom(ppToken->name);
+
+            // check for duplication of parameter name
+            bool duplicate = false;
+            for (size_t a = 0; a < mac.args.size(); ++a) {
+                if (mac.args[a] == argAtom) {
+                    parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
+                    duplicate = true;
+                    break;
+                }
+            }
+            if (! duplicate)
+                mac.args.push_back(argAtom);
+            token = scanToken(ppToken);
+        } while (token == ',');
+        if (token != ')') {
+            parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", "");
+
+            return token;
+        }
+
+        token = scanToken(ppToken);
+    }
+
+    // record the definition of the macro
+    TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
+    while (token != '\n' && token != EndOfInput) {
+        RecordToken(mac.body, token, ppToken);
+        token = scanToken(ppToken);
+        if (token != '\n' && ppToken->space)
+            RecordToken(mac.body, ' ', ppToken);
+    }
+
+    // check for duplicate definition
+    MacroSymbol* existing = lookupMacroDef(defAtom);
+    if (existing != nullptr) {
+        if (! existing->undef) {
+            // Already defined -- need to make sure they are identical:
+            // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
+            // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
+            if (existing->args.size() != mac.args.size() || existing->emptyArgs != mac.emptyArgs)
+                parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom));
+            else {
+                if (existing->args != mac.args)
+                    parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom));
+                RewindTokenStream(existing->body);
+                RewindTokenStream(mac.body);
+                int newToken;
+                do {
+                    int oldToken;
+                    TPpToken oldPpToken;
+                    TPpToken newPpToken;
+                    oldToken = ReadToken(existing->body, &oldPpToken);
+                    newToken = ReadToken(mac.body, &newPpToken);
+                    if (oldToken != newToken || oldPpToken != newPpToken) {
+                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
+                        break;
+                    }
+                } while (newToken > 0);
+            }
+        }
+        *existing = mac;
+    } else
+        addMacroDef(defAtom, mac);
+
+    return '\n';
+}
+
+// Handle #undef
+int TPpContext::CPPundef(TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+    if (token != PpAtomIdentifier) {
+        parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
+
+        return token;
+    }
+
+    parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
+
+    MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
+    if (macro != nullptr)
+        macro->undef = 1;
+    token = scanToken(ppToken);
+    if (token != '\n')
+        parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
+
+    return token;
+}
+
+// Handle #else
+/* Skip forward to appropriate spot.  This is used both
+** to skip to a #endif after seeing an #else, AND to skip to a #else,
+** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
+*/
+int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
+{
+    int depth = 0;
+    int token = scanToken(ppToken);
+
+    while (token != EndOfInput) {
+        if (token != '#') {
+            while (token != '\n' && token != EndOfInput)
+                token = scanToken(ppToken);
+
+            if (token == EndOfInput)
+                return token;
+
+            token = scanToken(ppToken);
+            continue;
+        }
+
+        if ((token = scanToken(ppToken)) != PpAtomIdentifier)
+            continue;
+
+        int nextAtom = atomStrings.getAtom(ppToken->name);
+        if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
+            depth++;
+            ifdepth++;
+            elsetracker++;
+        } else if (nextAtom == PpAtomEndif) {
+            token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
+            elseSeen[elsetracker] = false;
+            --elsetracker;
+            if (depth == 0) {
+                // found the #endif we are looking for
+                if (ifdepth)
+                    --ifdepth;
+                break;
+            }
+            --depth;
+            --ifdepth;
+        } else if (matchelse && depth == 0) {
+            if (nextAtom == PpAtomElse) {
+                elseSeen[elsetracker] = true;
+                token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
+                // found the #else we are looking for
+                break;
+            } else if (nextAtom == PpAtomElif) {
+                if (elseSeen[elsetracker])
+                    parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
+                /* we decrement ifdepth here, because CPPif will increment
+                * it and we really want to leave it alone */
+                if (ifdepth) {
+                    --ifdepth;
+                    elseSeen[elsetracker] = false;
+                    --elsetracker;
+                }
+
+                return CPPif(ppToken);
+            }
+        } else if (nextAtom == PpAtomElse) {
+            if (elseSeen[elsetracker])
+                parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
+            else
+                elseSeen[elsetracker] = true;
+            token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
+        } else if (nextAtom == PpAtomElif) {
+            if (elseSeen[elsetracker])
+                parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
+        }
+    }
+
+    return token;
+}
+
+// Call when there should be no more tokens left on a line.
+int TPpContext::extraTokenCheck(int contextAtom, TPpToken* ppToken, int token)
+{
+    if (token != '\n' && token != EndOfInput) {
+        static const char* message = "unexpected tokens following directive";
+
+        const char* label;
+        if (contextAtom == PpAtomElse)
+            label = "#else";
+        else if (contextAtom == PpAtomElif)
+            label = "#elif";
+        else if (contextAtom == PpAtomEndif)
+            label = "#endif";
+        else if (contextAtom == PpAtomIf)
+            label = "#if";
+        else if (contextAtom == PpAtomLine)
+            label = "#line";
+        else
+            label = "";
+
+        if (parseContext.relaxedErrors())
+            parseContext.ppWarn(ppToken->loc, message, label, "");
+        else
+            parseContext.ppError(ppToken->loc, message, label, "");
+
+        while (token != '\n' && token != EndOfInput)
+            token = scanToken(ppToken);
+    }
+
+    return token;
+}
+
+enum eval_prec {
+    MIN_PRECEDENCE,
+    COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
+    MAX_PRECEDENCE
+};
+
+namespace {
+
+    int op_logor(int a, int b) { return a || b; }
+    int op_logand(int a, int b) { return a && b; }
+    int op_or(int a, int b) { return a | b; }
+    int op_xor(int a, int b) { return a ^ b; }
+    int op_and(int a, int b) { return a & b; }
+    int op_eq(int a, int b) { return a == b; }
+    int op_ne(int a, int b) { return a != b; }
+    int op_ge(int a, int b) { return a >= b; }
+    int op_le(int a, int b) { return a <= b; }
+    int op_gt(int a, int b) { return a > b; }
+    int op_lt(int a, int b) { return a < b; }
+    int op_shl(int a, int b) { return a << b; }
+    int op_shr(int a, int b) { return a >> b; }
+    int op_add(int a, int b) { return a + b; }
+    int op_sub(int a, int b) { return a - b; }
+    int op_mul(int a, int b) { return a * b; }
+    int op_div(int a, int b) { return a / b; }
+    int op_mod(int a, int b) { return a % b; }
+    int op_pos(int a) { return a; }
+    int op_neg(int a) { return -a; }
+    int op_cmpl(int a) { return ~a; }
+    int op_not(int a) { return !a; }
+
+};
+
+struct TBinop {
+    int token, precedence, (*op)(int, int);
+} binop[] = {
+    { PpAtomOr, LOGOR, op_logor },
+    { PpAtomAnd, LOGAND, op_logand },
+    { '|', OR, op_or },
+    { '^', XOR, op_xor },
+    { '&', AND, op_and },
+    { PpAtomEQ, EQUAL, op_eq },
+    { PpAtomNE, EQUAL, op_ne },
+    { '>', RELATION, op_gt },
+    { PpAtomGE, RELATION, op_ge },
+    { '<', RELATION, op_lt },
+    { PpAtomLE, RELATION, op_le },
+    { PpAtomLeft, SHIFT, op_shl },
+    { PpAtomRight, SHIFT, op_shr },
+    { '+', ADD, op_add },
+    { '-', ADD, op_sub },
+    { '*', MUL, op_mul },
+    { '/', MUL, op_div },
+    { '%', MUL, op_mod },
+};
+
+struct TUnop {
+    int token, (*op)(int);
+} unop[] = {
+    { '+', op_pos },
+    { '-', op_neg },
+    { '~', op_cmpl },
+    { '!', op_not },
+};
+
+#define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
+
+int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
+{
+    TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
+    if (token == PpAtomIdentifier) {
+        if (strcmp("defined", ppToken->name) == 0) {
+            bool needclose = 0;
+            token = scanToken(ppToken);
+            if (token == '(') {
+                needclose = true;
+                token = scanToken(ppToken);
+            }
+            if (token != PpAtomIdentifier) {
+                parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
+                err = true;
+                res = 0;
+
+                return token;
+            }
+
+            MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
+            res = macro != nullptr ? !macro->undef : 0;
+            token = scanToken(ppToken);
+            if (needclose) {
+                if (token != ')') {
+                    parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
+                    err = true;
+                    res = 0;
+
+                    return token;
+                }
+                token = scanToken(ppToken);
+            }
+        } else {
+            token = evalToToken(token, shortCircuit, res, err, ppToken);
+            return eval(token, precedence, shortCircuit, res, err, ppToken);
+        }
+    } else if (token == PpAtomConstInt) {
+        res = ppToken->ival;
+        token = scanToken(ppToken);
+    } else if (token == '(') {
+        token = scanToken(ppToken);
+        token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
+        if (! err) {
+            if (token != ')') {
+                parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
+                err = true;
+                res = 0;
+
+                return token;
+            }
+            token = scanToken(ppToken);
+        }
+    } else {
+        int op = NUM_ELEMENTS(unop) - 1;
+        for (; op >= 0; op--) {
+            if (unop[op].token == token)
+                break;
+        }
+        if (op >= 0) {
+            token = scanToken(ppToken);
+            token = eval(token, UNARY, shortCircuit, res, err, ppToken);
+            res = unop[op].op(res);
+        } else {
+            parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
+            err = true;
+            res = 0;
+
+            return token;
+        }
+    }
+
+    token = evalToToken(token, shortCircuit, res, err, ppToken);
+
+    // Perform evaluation of binary operation, if there is one, otherwise we are done.
+    while (! err) {
+        if (token == ')' || token == '\n')
+            break;
+        int op;
+        for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
+            if (binop[op].token == token)
+                break;
+        }
+        if (op < 0 || binop[op].precedence <= precedence)
+            break;
+        int leftSide = res;
+
+        // Setup short-circuiting, needed for ES, unless already in a short circuit.
+        // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
+        if (! shortCircuit) {
+            if ((token == PpAtomOr  && leftSide == 1) ||
+                (token == PpAtomAnd && leftSide == 0))
+                shortCircuit = true;
+        }
+
+        token = scanToken(ppToken);
+        token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
+
+        if (binop[op].op == op_div || binop[op].op == op_mod) {
+            if (res == 0) {
+                parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
+                res = 1;
+            }
+        }
+        res = binop[op].op(leftSide, res);
+    }
+
+    return token;
+}
+
+// Expand macros, skipping empty expansions, to get to the first real token in those expansions.
+int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
+{
+    while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
+        int macroReturn = MacroExpand(ppToken, true, false);
+        if (macroReturn == 0) {
+            parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
+            err = true;
+            res = 0;
+            token = scanToken(ppToken);
+            break;
+        }
+        if (macroReturn == -1) {
+            if (! shortCircuit && parseContext.profile == EEsProfile) {
+                const char* message = "undefined macro in expression not allowed in es profile";
+                if (parseContext.relaxedErrors())
+                    parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
+                else
+                    parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
+            }
+        }
+        token = scanToken(ppToken);
+    }
+
+    return token;
+}
+
+// Handle #if
+int TPpContext::CPPif(TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+    elsetracker++;
+    ifdepth++;
+    if (ifdepth > maxIfNesting) {
+        parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
+        return 0;
+    }
+    int res = 0;
+    bool err = false;
+    token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
+    token = extraTokenCheck(PpAtomIf, ppToken, token);
+    if (!res && !err)
+        token = CPPelse(1, ppToken);
+
+    return token;
+}
+
+// Handle #ifdef
+int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+    if (++ifdepth > maxIfNesting) {
+        parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
+        return 0;
+    }
+    elsetracker++;
+    if (token != PpAtomIdentifier) {
+        if (defined)
+            parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
+        else
+            parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
+    } else {
+        MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
+        token = scanToken(ppToken);
+        if (token != '\n') {
+            parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
+            while (token != '\n' && token != EndOfInput)
+                token = scanToken(ppToken);
+        }
+        if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
+            token = CPPelse(1, ppToken);
+    }
+
+    return token;
+}
+
+// Handle #include ...
+// TODO: Handle macro expansions for the header name
+int TPpContext::CPPinclude(TPpToken* ppToken)
+{
+    const TSourceLoc directiveLoc = ppToken->loc;
+    bool startWithLocalSearch = true; // to additionally include the extra "" paths
+    int token = scanToken(ppToken);
+
+    // handle <header-name>-style #include
+    if (token == '<') {
+        startWithLocalSearch = false;
+        token = scanHeaderName(ppToken, '>');
+    }
+    // otherwise ppToken already has the header name and it was "header-name" style
+
+    if (token != PpAtomConstString) {
+        parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
+        return token;
+    }
+
+    // Make a copy of the name because it will be overwritten by the next token scan.
+    const std::string filename = ppToken->name;
+
+    // See if the directive was well formed
+    token = scanToken(ppToken);
+    if (token != '\n') {
+        if (token == EndOfInput)
+            parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
+        else
+            parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
+        return token;
+    }
+
+    // Process well-formed directive
+
+    // Find the inclusion, first look in "Local" ("") paths, if requested,
+    // otherwise, only search the "System" (<>) paths.
+    TShader::Includer::IncludeResult* res = nullptr;
+    if (startWithLocalSearch)
+        res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
+    if (! res || res->headerName.empty()) {
+        includer.releaseInclude(res);
+        res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
+    }
+
+    // Process the results
+    if (res && !res->headerName.empty()) {
+        if (res->headerData && res->headerLength) {
+            // path for processing one or more tokens from an included header, hand off 'res'
+            const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
+            std::ostringstream prologue;
+            std::ostringstream epilogue;
+            prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
+            epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
+                "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
+            pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
+            // There's no "current" location anymore.
+            parseContext.setCurrentColumn(0);
+        } else {
+            // things are okay, but there is nothing to process
+            includer.releaseInclude(res);
+        }
+    } else {
+        // error path, clean up
+        std::string message =
+            res ? std::string(res->headerData, res->headerLength)
+                : std::string("Could not process include directive");
+        parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
+        includer.releaseInclude(res);
+    }
+
+    return token;
+}
+
+// Handle #line
+int TPpContext::CPPline(TPpToken* ppToken)
+{
+    // "#line must have, after macro substitution, one of the following forms:
+    // "#line line
+    // "#line line source-string-number"
+
+    int token = scanToken(ppToken);
+    const TSourceLoc directiveLoc = ppToken->loc;
+    if (token == '\n') {
+        parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
+        return token;
+    }
+
+    int lineRes = 0; // Line number after macro expansion.
+    int lineToken = 0;
+    bool hasFile = false;
+    int fileRes = 0; // Source file number after macro expansion.
+    const char* sourceName = nullptr; // Optional source file name.
+    bool lineErr = false;
+    bool fileErr = false;
+    token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
+    if (! lineErr) {
+        lineToken = lineRes;
+        if (token == '\n')
+            ++lineRes;
+
+        if (parseContext.lineDirectiveShouldSetNextLine())
+            --lineRes;
+        parseContext.setCurrentLine(lineRes);
+
+        if (token != '\n') {
+            if (token == PpAtomConstString) {
+                parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
+                // We need to save a copy of the string instead of pointing
+                // to the name field of the token since the name field
+                // will likely be overwritten by the next token scan.
+                sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
+                parseContext.setCurrentSourceName(sourceName);
+                hasFile = true;
+                token = scanToken(ppToken);
+            } else {
+                token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
+                if (! fileErr) {
+                    parseContext.setCurrentString(fileRes);
+                    hasFile = true;
+                }
+            }
+        }
+    }
+    if (!fileErr && !lineErr) {
+        parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
+    }
+    token = extraTokenCheck(PpAtomLine, ppToken, token);
+
+    return token;
+}
+
+// Handle #error
+int TPpContext::CPPerror(TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+    std::string message;
+    TSourceLoc loc = ppToken->loc;
+
+    while (token != '\n' && token != EndOfInput) {
+        if (token == PpAtomConstInt   || token == PpAtomConstUint   ||
+            token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
+#ifdef AMD_EXTENSIONS
+            token == PpAtomConstFloat16 ||
+#endif
+            token == PpAtomConstFloat || token == PpAtomConstDouble) {
+                message.append(ppToken->name);
+        } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
+            message.append(ppToken->name);
+        } else {
+            message.append(atomStrings.getString(token));
+        }
+        message.append(" ");
+        token = scanToken(ppToken);
+    }
+    parseContext.notifyErrorDirective(loc.line, message.c_str());
+    // store this msg into the shader's information log..set the Compile Error flag!!!!
+    parseContext.ppError(loc, message.c_str(), "#error", "");
+
+    return '\n';
+}
+
+// Handle #pragma
+int TPpContext::CPPpragma(TPpToken* ppToken)
+{
+    char SrcStrName[2];
+    TVector<TString> tokens;
+
+    TSourceLoc loc = ppToken->loc;  // because we go to the next line before processing
+    int token = scanToken(ppToken);
+    while (token != '\n' && token != EndOfInput) {
+        switch (token) {
+        case PpAtomIdentifier:
+        case PpAtomConstInt:
+        case PpAtomConstUint:
+        case PpAtomConstInt64:
+        case PpAtomConstUint64:
+        case PpAtomConstFloat:
+        case PpAtomConstDouble:
+#ifdef AMD_EXTENSIONS
+        case PpAtomConstFloat16:
+#endif
+            tokens.push_back(ppToken->name);
+            break;
+        default:
+            SrcStrName[0] = (char)token;
+            SrcStrName[1] = '\0';
+            tokens.push_back(SrcStrName);
+        }
+        token = scanToken(ppToken);
+    }
+
+    if (token == EndOfInput)
+        parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
+    else
+        parseContext.handlePragma(loc, tokens);
+
+    return token;
+}
+
+// #version: This is just for error checking: the version and profile are decided before preprocessing starts
+int TPpContext::CPPversion(TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+
+    if (errorOnVersion || versionSeen)
+        parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
+    versionSeen = true;
+
+    if (token == '\n') {
+        parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
+
+        return token;
+    }
+
+    if (token != PpAtomConstInt)
+        parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
+
+    ppToken->ival = atoi(ppToken->name);
+    int versionNumber = ppToken->ival;
+    int line = ppToken->loc.line;
+    token = scanToken(ppToken);
+
+    if (token == '\n') {
+        parseContext.notifyVersion(line, versionNumber, nullptr);
+        return token;
+    } else {
+        int profileAtom = atomStrings.getAtom(ppToken->name);
+        if (profileAtom != PpAtomCore &&
+            profileAtom != PpAtomCompatibility &&
+            profileAtom != PpAtomEs)
+            parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
+        parseContext.notifyVersion(line, versionNumber, ppToken->name);
+        token = scanToken(ppToken);
+
+        if (token == '\n')
+            return token;
+        else
+            parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
+    }
+
+    return token;
+}
+
+// Handle #extension
+int TPpContext::CPPextension(TPpToken* ppToken)
+{
+    int line = ppToken->loc.line;
+    int token = scanToken(ppToken);
+    char extensionName[MaxTokenLength + 1];
+
+    if (token=='\n') {
+        parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
+        return token;
+    }
+
+    if (token != PpAtomIdentifier)
+        parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
+
+    assert(strlen(ppToken->name) <= MaxTokenLength);
+    strcpy(extensionName, ppToken->name);
+
+    token = scanToken(ppToken);
+    if (token != ':') {
+        parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
+        return token;
+    }
+
+    token = scanToken(ppToken);
+    if (token != PpAtomIdentifier) {
+        parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
+        return token;
+    }
+
+    parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
+    parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
+
+    token = scanToken(ppToken);
+    if (token == '\n')
+        return token;
+    else
+        parseContext.ppError(ppToken->loc,  "extra tokens -- expected newline", "#extension","");
+
+    return token;
+}
+
+int TPpContext::readCPPline(TPpToken* ppToken)
+{
+    int token = scanToken(ppToken);
+
+    if (token == PpAtomIdentifier) {
+        switch (atomStrings.getAtom(ppToken->name)) {
+        case PpAtomDefine:
+            token = CPPdefine(ppToken);
+            break;
+        case PpAtomElse:
+            if (elsetracker[elseSeen])
+                parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
+            elsetracker[elseSeen] = true;
+            if (! ifdepth)
+                parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
+            token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
+            token = CPPelse(0, ppToken);
+            break;
+        case PpAtomElif:
+            if (! ifdepth)
+                parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
+            if (elseSeen[elsetracker])
+                parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
+            // this token is really a dont care, but we still need to eat the tokens
+            token = scanToken(ppToken);
+            while (token != '\n' && token != EndOfInput)
+                token = scanToken(ppToken);
+            token = CPPelse(0, ppToken);
+            break;
+        case PpAtomEndif:
+            if (! ifdepth)
+                parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
+            else {
+                elseSeen[elsetracker] = false;
+                --elsetracker;
+                --ifdepth;
+            }
+            token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
+            break;
+        case PpAtomIf:
+            token = CPPif(ppToken);
+            break;
+        case PpAtomIfdef:
+            token = CPPifdef(1, ppToken);
+            break;
+        case PpAtomIfndef:
+            token = CPPifdef(0, ppToken);
+            break;
+        case PpAtomInclude:
+            if(!parseContext.isReadingHLSL()) {
+                parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
+            }
+            token = CPPinclude(ppToken);
+            break;
+        case PpAtomLine:
+            token = CPPline(ppToken);
+            break;
+        case PpAtomPragma:
+            token = CPPpragma(ppToken);
+            break;
+        case PpAtomUndef:
+            token = CPPundef(ppToken);
+            break;
+        case PpAtomError:
+            token = CPPerror(ppToken);
+            break;
+        case PpAtomVersion:
+            token = CPPversion(ppToken);
+            break;
+        case PpAtomExtension:
+            token = CPPextension(ppToken);
+            break;
+        default:
+            parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
+            break;
+        }
+    } else if (token != '\n' && token != EndOfInput)
+        parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
+
+    while (token != '\n' && token != EndOfInput)
+        token = scanToken(ppToken);
+
+    return token;
+}
+
+// Context-dependent parsing of a #include <header-name>.
+// Assumes no macro expansions etc. are being done; the name is just on the current input.
+// Always creates a name and returns PpAtomicConstString, unless we run out of input.
+int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
+{
+    bool tooLong = false;
+
+    if (inputStack.empty())
+        return EndOfInput;
+
+    int len = 0;
+    ppToken->name[0] = '\0';
+    do {
+        int ch = inputStack.back()->getch();
+
+        // done yet?
+        if (ch == delimit) {
+            ppToken->name[len] = '\0';
+            if (tooLong)
+                parseContext.ppError(ppToken->loc, "header name too long", "", "");
+            return PpAtomConstString;
+        } else if (ch == EndOfInput)
+            return EndOfInput;
+
+        // found a character to expand the name with
+        if (len < MaxTokenLength)
+            ppToken->name[len++] = (char)ch;
+        else
+            tooLong = true;
+    } while (true);
+}
+
+// Macro-expand a macro argument 'arg' to create 'expandedArg'.
+// Does not replace 'arg'.
+// Returns nullptr if no expanded argument is created.
+TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
+{
+    // pre-check, to see if anything in the argument needs to be expanded,
+    // to see if we can kick out early
+    int token;
+    RewindTokenStream(arg);
+    do {
+        token = ReadToken(arg, ppToken);
+        if (token == PpAtomIdentifier && lookupMacroDef(atomStrings.getAtom(ppToken->name)) != nullptr)
+            break;
+    } while (token != EndOfInput);
+
+    // if nothing needs to be expanded, kick out early
+    if (token == EndOfInput)
+        return nullptr;
+
+    // expand the argument
+    TokenStream* expandedArg = new TokenStream;
+    pushInput(new tMarkerInput(this));
+    pushTokenStreamInput(arg);
+    while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
+        if (token == PpAtomIdentifier && MacroExpand(ppToken, false, newLineOkay) != 0)
+            continue;
+        RecordToken(*expandedArg, token, ppToken);
+    }
+
+    if (token == EndOfInput) {
+        // MacroExpand ate the marker, so had bad input, recover
+        delete expandedArg;
+        expandedArg = nullptr;
+    } else {
+        // remove the marker
+        popInput();
+    }
+
+    return expandedArg;
+}
+
+//
+// Return the next token for a macro expansion, handling macro arguments,
+// whose semantics are dependent on being adjacent to ##.
+//
+int TPpContext::tMacroInput::scan(TPpToken* ppToken)
+{
+    int token;
+    do {
+        token = pp->ReadToken(mac->body, ppToken);
+    } while (token == ' ');  // handle white space in macro
+
+    // Hash operators basically turn off a round of macro substitution
+    // (the round done on the argument before the round done on the RHS of the
+    // macro definition):
+    //
+    // "A parameter in the replacement list, unless preceded by a # or ##
+    // preprocessing token or followed by a ## preprocessing token (see below),
+    // is replaced by the corresponding argument after all macros contained
+    // therein have been expanded."
+    //
+    // "If, in the replacement list, a parameter is immediately preceded or
+    // followed by a ## preprocessing token, the parameter is replaced by the
+    // corresponding argument's preprocessing token sequence."
+
+    bool pasting = false;
+    if (postpaste) {
+        // don't expand next token
+        pasting = true;
+        postpaste = false;
+    }
+
+    if (prepaste) {
+        // already know we should be on a ##, verify
+        assert(token == PpAtomPaste);
+        prepaste = false;
+        postpaste = true;
+    }
+
+    // see if are preceding a ##
+    if (peekMacPasting()) {
+        prepaste = true;
+        pasting = true;
+    }
+
+    // TODO: preprocessor:  properly handle whitespace (or lack of it) between tokens when expanding
+    if (token == PpAtomIdentifier) {
+        int i;
+        for (i = mac->args.size() - 1; i >= 0; i--)
+            if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
+                break;
+        if (i >= 0) {
+            TokenStream* arg = expandedArgs[i];
+            if (arg == nullptr || pasting)
+                arg = args[i];
+            pp->pushTokenStreamInput(*arg, prepaste);
+
+            return pp->scanToken(ppToken);
+        }
+    }
+
+    if (token == EndOfInput)
+        mac->busy = 0;
+
+    return token;
+}
+
+// See if the next non-white-space token in the macro is ##
+bool TPpContext::tMacroInput::peekMacPasting()
+{
+    // don't return early, have to restore this
+    size_t savePos = mac->body.current;
+
+    // skip white-space
+    int ltoken;
+    do {
+        ltoken = pp->lReadByte(mac->body);
+    } while (ltoken == ' ');
+
+    // check for ##
+    bool pasting = false;
+    if (ltoken == '#') {
+        ltoken = pp->lReadByte(mac->body);
+        if (ltoken == '#')
+            pasting = true;
+    }
+
+    mac->body.current = savePos;
+
+    return pasting;
+}
+
+// return a textual zero, for scanning a macro that was never defined
+int TPpContext::tZeroInput::scan(TPpToken* ppToken)
+{
+    if (done)
+        return EndOfInput;
+
+    strcpy(ppToken->name, "0");
+    ppToken->ival = 0;
+    ppToken->space = false;
+    done = true;
+
+    return PpAtomConstInt;
+}
+
+//
+// Check a token to see if it is a macro that should be expanded.
+// If it is, and defined, push a tInput that will produce the appropriate expansion
+// and return 1.
+// If it is, but undefined, and expandUndef is requested, push a tInput that will
+// expand to 0 and return -1.
+// Otherwise, return 0 to indicate no expansion, which is not necessarily an error.
+//
+int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
+{
+    ppToken->space = false;
+    int macroAtom = atomStrings.getAtom(ppToken->name);
+    switch (macroAtom) {
+    case PpAtomLineMacro:
+        ppToken->ival = parseContext.getCurrentLoc().line;
+        snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
+        UngetToken(PpAtomConstInt, ppToken);
+        return 1;
+
+    case PpAtomFileMacro: {
+        if (parseContext.getCurrentLoc().name)
+            parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
+        ppToken->ival = parseContext.getCurrentLoc().string;
+        snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
+        UngetToken(PpAtomConstInt, ppToken);
+        return 1;
+    }
+
+    case PpAtomVersionMacro:
+        ppToken->ival = parseContext.version;
+        snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
+        UngetToken(PpAtomConstInt, ppToken);
+        return 1;
+
+    default:
+        break;
+    }
+
+    MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
+    int token;
+    int depth = 0;
+
+    // no recursive expansions
+    if (macro != nullptr && macro->busy)
+        return 0;
+
+    // not expanding undefined macros
+    if ((macro == nullptr || macro->undef) && ! expandUndef)
+        return 0;
+
+    // 0 is the value of an undefined macro
+    if ((macro == nullptr || macro->undef) && expandUndef) {
+        pushInput(new tZeroInput(this));
+        return -1;
+    }
+
+    tMacroInput *in = new tMacroInput(this);
+
+    TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
+    in->mac = macro;
+    if (macro->args.size() > 0 || macro->emptyArgs) {
+        token = scanToken(ppToken);
+        if (newLineOkay) {
+            while (token == '\n')
+                token = scanToken(ppToken);
+        }
+        if (token != '(') {
+            parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom));
+            UngetToken(token, ppToken);
+            delete in;
+            return 0;
+        }
+        in->args.resize(in->mac->args.size());
+        for (size_t i = 0; i < in->mac->args.size(); i++)
+            in->args[i] = new TokenStream;
+        in->expandedArgs.resize(in->mac->args.size());
+        for (size_t i = 0; i < in->mac->args.size(); i++)
+            in->expandedArgs[i] = nullptr;
+        size_t arg = 0;
+        bool tokenRecorded = false;
+        do {
+            depth = 0;
+            while (1) {
+                token = scanToken(ppToken);
+                if (token == EndOfInput || token == tMarkerInput::marker) {
+                    parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
+                    delete in;
+                    return 0;
+                }
+                if (token == '\n') {
+                    if (! newLineOkay) {
+                        parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
+                        delete in;
+                        return 0;
+                    }
+                    continue;
+                }
+                if (token == '#') {
+                    parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
+                    delete in;
+                    return 0;
+                }
+                if (in->mac->args.size() == 0 && token != ')')
+                    break;
+                if (depth == 0 && (token == ',' || token == ')'))
+                    break;
+                if (token == '(')
+                    depth++;
+                if (token == ')')
+                    depth--;
+                RecordToken(*in->args[arg], token, ppToken);
+                tokenRecorded = true;
+            }
+            if (token == ')') {
+                if (in->mac->args.size() == 1 && tokenRecorded == 0)
+                    break;
+                arg++;
+                break;
+            }
+            arg++;
+        } while (arg < in->mac->args.size());
+
+        if (arg < in->mac->args.size())
+            parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
+        else if (token != ')') {
+            depth=0;
+            while (token != EndOfInput && (depth > 0 || token != ')')) {
+                if (token == ')')
+                    depth--;
+                token = scanToken(ppToken);
+                if (token == '(')
+                    depth++;
+            }
+
+            if (token == EndOfInput) {
+                parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
+                delete in;
+                return 0;
+            }
+            parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
+        }
+
+        // We need both expanded and non-expanded forms of the argument, for whether or
+        // not token pasting is in play.
+        for (size_t i = 0; i < in->mac->args.size(); i++)
+            in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
+    }
+
+    pushInput(in);
+    macro->busy = 1;
+    RewindTokenStream(macro->body);
+
+    return 1;
+}
+
+} // end namespace glslang

+ 177 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp

@@ -0,0 +1,177 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+#include "PpContext.h"
+#include "PpTokens.h"
+
+namespace {
+
+using namespace glslang;
+
+const struct {
+    int val;
+    const char* str;
+} tokens[] = {
+
+    { PPAtomAddAssign,      "+=" },
+    { PPAtomSubAssign,      "-=" },
+    { PPAtomMulAssign,      "*=" },
+    { PPAtomDivAssign,      "/=" },
+    { PPAtomModAssign,      "%=" },
+
+    { PpAtomRight,          ">>" },
+    { PpAtomLeft,           "<<" },
+    { PpAtomAnd,            "&&" },
+    { PpAtomOr,             "||" },
+    { PpAtomXor,            "^^" },
+
+    { PpAtomRightAssign,    ">>=" },
+    { PpAtomLeftAssign,     "<<=" },
+    { PpAtomAndAssign,      "&=" },
+    { PpAtomOrAssign,       "|=" },
+    { PpAtomXorAssign,      "^=" },
+
+    { PpAtomEQ,             "==" },
+    { PpAtomNE,             "!=" },
+    { PpAtomGE,             ">=" },
+    { PpAtomLE,             "<=" },
+
+    { PpAtomDecrement,      "--" },
+    { PpAtomIncrement,      "++" },
+
+    { PpAtomDefine,         "define" },
+    { PpAtomUndef,          "undef" },
+    { PpAtomIf,             "if" },
+    { PpAtomElif,           "elif" },
+    { PpAtomElse,           "else" },
+    { PpAtomEndif,          "endif" },
+    { PpAtomIfdef,          "ifdef" },
+    { PpAtomIfndef,         "ifndef" },
+    { PpAtomLine,           "line" },
+    { PpAtomPragma,         "pragma" },
+    { PpAtomError,          "error" },
+
+    { PpAtomVersion,        "version" },
+    { PpAtomCore,           "core" },
+    { PpAtomCompatibility,  "compatibility" },
+    { PpAtomEs,             "es" },
+    { PpAtomExtension,      "extension" },
+
+    { PpAtomLineMacro,       "__LINE__" },
+    { PpAtomFileMacro,       "__FILE__" },
+    { PpAtomVersionMacro,    "__VERSION__" },
+
+    { PpAtomInclude,         "include" },
+};
+
+} // end anonymous namespace
+
+namespace glslang {
+
+//
+// Initialize the atom table.
+//
+TStringAtomMap::TStringAtomMap()
+{
+    badToken.assign("<bad token>");
+
+    // Add single character tokens to the atom table:
+    const char* s = "~!%^&*()-+=|,.<>/?;:[]{}#\\";
+    char t[2];
+
+    t[1] = '\0';
+    while (*s) {
+        t[0] = *s;
+        addAtomFixed(t, s[0]);
+        s++;
+    }
+
+    // Add multiple character scanner tokens :
+    for (size_t ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
+        addAtomFixed(tokens[ii].str, tokens[ii].val);
+
+    nextAtom = PpAtomLast;
+}
+
+} // end namespace glslang

+ 115 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp

@@ -0,0 +1,115 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#include <cstdlib>
+
+#include "PpContext.h"
+
+namespace glslang {
+
+TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) :
+    preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false),
+    rootFileName(rootFileName),
+    currentSourceFile(rootFileName)
+{
+    ifdepth = 0;
+    for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
+        elseSeen[elsetracker] = false;
+    elsetracker = 0;
+}
+
+TPpContext::~TPpContext()
+{
+    delete [] preamble;
+
+    // free up the inputStack
+    while (! inputStack.empty())
+        popInput();
+}
+
+void TPpContext::setInput(TInputScanner& input, bool versionWillBeError)
+{
+    assert(inputStack.size() == 0);
+
+    pushInput(new tStringInput(this, input));
+
+    errorOnVersion = versionWillBeError;
+    versionSeen = false;
+}
+
+} // end namespace glslang

+ 603 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h

@@ -0,0 +1,603 @@
+//
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#ifndef PPCONTEXT_H
+#define PPCONTEXT_H
+
+#include <stack>
+#include <unordered_map>
+
+#include "../ParseHelper.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+    #pragma warning(disable : 4127)
+#endif
+
+namespace glslang {
+
+class TPpToken {
+public:
+    TPpToken() : space(false), ival(0), dval(0.0), i64val(0)
+    {
+        loc.init();
+        name[0] = 0;
+    }
+
+    // This is used for comparing macro definitions, so checks what is relevant for that.
+    bool operator==(const TPpToken& right)
+    {
+        return space == right.space &&
+               ival == right.ival && dval == right.dval && i64val == right.i64val &&
+               strncmp(name, right.name, MaxTokenLength) == 0;
+    }
+    bool operator!=(const TPpToken& right) { return ! operator==(right); }
+
+    TSourceLoc loc;
+    bool   space;  // true if a space (for white space or a removed comment) should also be recognized, in front of the token returned
+    int    ival;
+    double dval;
+    long long i64val;
+    char   name[MaxTokenLength + 1];
+};
+
+class TStringAtomMap {
+//
+// Implementation is in PpAtom.cpp
+//
+// Maintain a bi-directional mapping between relevant preprocessor strings and
+// "atoms" which a unique integers (small, contiguous, not hash-like) per string.
+//
+public:
+    TStringAtomMap();
+
+    // Map string -> atom.
+    // Return 0 if no existing string.
+    int getAtom(const char* s) const
+    {
+        auto it = atomMap.find(s);
+        return it == atomMap.end() ? 0 : it->second;
+    }
+
+    // Map a new or existing string -> atom, inventing a new atom if necessary.
+    int getAddAtom(const char* s)
+    {
+        int atom = getAtom(s);
+        if (atom == 0) {
+            atom = nextAtom++;
+            addAtomFixed(s, atom);
+        }
+        return atom;
+    }
+
+    // Map atom -> string.
+    const char* getString(int atom) const { return stringMap[atom]->c_str(); }
+
+protected:
+    TStringAtomMap(TStringAtomMap&);
+    TStringAtomMap& operator=(TStringAtomMap&);
+
+    TUnorderedMap<TString, int> atomMap;
+    TVector<const TString*> stringMap;    // these point into the TString in atomMap
+    int nextAtom;
+
+    // Bad source characters can lead to bad atoms, so gracefully handle those by
+    // pre-filling the table with them (to avoid if tests later).
+    TString badToken;
+
+    // Add bi-directional mappings:
+    //  - string -> atom
+    //  - atom -> string
+    void addAtomFixed(const char* s, int atom)
+    {
+        auto it = atomMap.insert(std::pair<TString, int>(s, atom)).first;
+        if (stringMap.size() < (size_t)atom + 1)
+            stringMap.resize(atom + 100, &badToken);
+        stringMap[atom] = &it->first;
+    }
+};
+
+class TInputScanner;
+
+// This class is the result of turning a huge pile of C code communicating through globals
+// into a class.  This was done to allowing instancing to attain thread safety.
+// Don't expect too much in terms of OO design.
+class TPpContext {
+public:
+    TPpContext(TParseContextBase&, const std::string& rootFileName, TShader::Includer&);
+    virtual ~TPpContext();
+
+    void setPreamble(const char* preamble, size_t length);
+
+    int tokenize(TPpToken& ppToken);
+    int tokenPaste(int token, TPpToken&);
+
+    class tInput {
+    public:
+        tInput(TPpContext* p) : done(false), pp(p) { }
+        virtual ~tInput() { }
+
+        virtual int scan(TPpToken*) = 0;
+        virtual int getch() = 0;
+        virtual void ungetch() = 0;
+        virtual bool peekPasting() { return false; }          // true when about to see ##
+        virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
+
+        // Will be called when we start reading tokens from this instance
+        virtual void notifyActivated() {}
+        // Will be called when we do not read tokens from this instance anymore
+        virtual void notifyDeleted() {}
+    protected:
+        bool done;
+        TPpContext* pp;
+    };
+
+    void setInput(TInputScanner& input, bool versionWillBeError);
+
+    void pushInput(tInput* in)
+    {
+        inputStack.push_back(in);
+        in->notifyActivated();
+    }
+    void popInput()
+    {
+        inputStack.back()->notifyDeleted();
+        delete inputStack.back();
+        inputStack.pop_back();
+    }
+
+    struct TokenStream {
+        TokenStream() : current(0) { }
+        TVector<unsigned char> data;
+        size_t current;
+    };
+
+    //
+    // From Pp.cpp
+    //
+
+    struct MacroSymbol {
+        MacroSymbol() : emptyArgs(0), busy(0), undef(0) { }
+        TVector<int> args;
+        TokenStream body;
+        unsigned emptyArgs : 1;
+        unsigned busy      : 1;
+        unsigned undef     : 1;
+    };
+
+    typedef TMap<int, MacroSymbol> TSymbolMap;
+    TSymbolMap macroDefs;  // map atoms to macro definitions
+    MacroSymbol* lookupMacroDef(int atom)
+    {
+        auto existingMacroIt = macroDefs.find(atom);
+        return (existingMacroIt == macroDefs.end()) ? nullptr : &(existingMacroIt->second);
+    }
+    void addMacroDef(int atom, MacroSymbol& macroDef) { macroDefs[atom] = macroDef; }
+
+protected:
+    TPpContext(TPpContext&);
+    TPpContext& operator=(TPpContext&);
+
+    TStringAtomMap atomStrings;
+    char*   preamble;               // string to parse, all before line 1 of string 0, it is 0 if no preamble
+    int     preambleLength;
+    char**  strings;                // official strings of shader, starting a string 0 line 1
+    size_t* lengths;
+    int     numStrings;             // how many official strings there are
+    int     currentString;          // which string we're currently parsing  (-1 for preamble)
+
+    // Scanner data:
+    int previous_token;
+    TParseContextBase& parseContext;
+
+    // Get the next token from *stack* of input sources, popping input sources
+    // that are out of tokens, down until an input source is found that has a token.
+    // Return EndOfInput when there are no more tokens to be found by doing this.
+    int scanToken(TPpToken* ppToken)
+    {
+        int token = EndOfInput;
+
+        while (! inputStack.empty()) {
+            token = inputStack.back()->scan(ppToken);
+            if (token != EndOfInput || inputStack.empty())
+                break;
+            popInput();
+        }
+
+        return token;
+    }
+    int  getChar() { return inputStack.back()->getch(); }
+    void ungetChar() { inputStack.back()->ungetch(); }
+    bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
+    bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
+
+    static const int maxIfNesting = 64;
+
+    int ifdepth;                  // current #if-#else-#endif nesting in the cpp.c file (pre-processor)
+    bool elseSeen[maxIfNesting];  // Keep a track of whether an else has been seen at a particular depth
+    int elsetracker;              // #if-#else and #endif constructs...Counter.
+
+    class tMacroInput : public tInput {
+    public:
+        tMacroInput(TPpContext* pp) : tInput(pp), prepaste(false), postpaste(false) { }
+        virtual ~tMacroInput()
+        {
+            for (size_t i = 0; i < args.size(); ++i)
+                delete args[i];
+            for (size_t i = 0; i < expandedArgs.size(); ++i)
+                delete expandedArgs[i];
+        }
+
+        virtual int scan(TPpToken*) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
+        bool peekPasting() override { return prepaste; }
+        bool endOfReplacementList() override { return mac->body.current >= mac->body.data.size(); }
+
+        MacroSymbol *mac;
+        TVector<TokenStream*> args;
+        TVector<TokenStream*> expandedArgs;
+
+    protected:
+        bool peekMacPasting();
+        bool prepaste;         // true if we are just before ##
+        bool postpaste;        // true if we are right after ##
+    };
+
+    class tMarkerInput : public tInput {
+    public:
+        tMarkerInput(TPpContext* pp) : tInput(pp) { }
+        virtual int scan(TPpToken*) override
+        {
+            if (done)
+                return EndOfInput;
+            done = true;
+
+            return marker;
+        }
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
+        static const int marker = -3;
+    };
+
+    class tZeroInput : public tInput {
+    public:
+        tZeroInput(TPpContext* pp) : tInput(pp) { }
+        virtual int scan(TPpToken*) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
+    };
+
+    std::vector<tInput*> inputStack;
+    bool errorOnVersion;
+    bool versionSeen;
+
+    //
+    // from Pp.cpp
+    //
+
+    // Used to obtain #include content.
+    TShader::Includer& includer;
+
+    int CPPdefine(TPpToken * ppToken);
+    int CPPundef(TPpToken * ppToken);
+    int CPPelse(int matchelse, TPpToken * ppToken);
+    int extraTokenCheck(int atom, TPpToken* ppToken, int token);
+    int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
+    int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
+    int CPPif (TPpToken * ppToken);
+    int CPPifdef(int defined, TPpToken * ppToken);
+    int CPPinclude(TPpToken * ppToken);
+    int CPPline(TPpToken * ppToken);
+    int CPPerror(TPpToken * ppToken);
+    int CPPpragma(TPpToken * ppToken);
+    int CPPversion(TPpToken * ppToken);
+    int CPPextension(TPpToken * ppToken);
+    int readCPPline(TPpToken * ppToken);
+    int scanHeaderName(TPpToken* ppToken, char delimit);
+    TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay);
+    int MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay);
+
+    //
+    // From PpTokens.cpp
+    //
+    void lAddByte(TokenStream&, unsigned char fVal);
+    int lReadByte(TokenStream&);
+    void lUnreadByte(TokenStream&);
+    void RecordToken(TokenStream&, int token, TPpToken* ppToken);
+    void RewindTokenStream(TokenStream&);
+    int ReadToken(TokenStream&, TPpToken*);
+    void pushTokenStreamInput(TokenStream&, bool pasting = false);
+    void UngetToken(int token, TPpToken*);
+
+    class tTokenInput : public tInput {
+    public:
+        tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { }
+        virtual int scan(TPpToken *) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
+        virtual bool peekPasting() override;
+    protected:
+        TokenStream* tokens;
+        bool lastTokenPastes;     // true if the last token in the input is to be pasted, rather than consumed as a token
+    };
+
+    class tUngotTokenInput : public tInput {
+    public:
+        tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { }
+        virtual int scan(TPpToken *) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
+    protected:
+        int token;
+        TPpToken lval;
+    };
+
+    //
+    // From PpScanner.cpp
+    //
+    class tStringInput : public tInput {
+    public:
+        tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { }
+        virtual int scan(TPpToken*) override;
+
+        // Scanner used to get source stream characters.
+        //  - Escaped newlines are handled here, invisibly to the caller.
+        //  - All forms of newline are handled, and turned into just a '\n'.
+        int getch() override
+        {
+            int ch = input->get();
+
+            if (ch == '\\') {
+                // Move past escaped newlines, as many as sequentially exist
+                do {
+                    if (input->peek() == '\r' || input->peek() == '\n') {
+                        bool allowed = pp->parseContext.lineContinuationCheck(input->getSourceLoc(), pp->inComment);
+                        if (! allowed && pp->inComment)
+                            return '\\';
+
+                        // escape one newline now
+                        ch = input->get();
+                        int nextch = input->get();
+                        if (ch == '\r' && nextch == '\n')
+                            ch = input->get();
+                        else
+                            ch = nextch;
+                    } else
+                        return '\\';
+                } while (ch == '\\');
+            }
+
+            // handle any non-escaped newline
+            if (ch == '\r' || ch == '\n') {
+                if (ch == '\r' && input->peek() == '\n')
+                    input->get();
+                return '\n';
+            }
+
+            return ch;
+        }
+
+        // Scanner used to backup the source stream characters.  Newlines are
+        // handled here, invisibly to the caller, meaning have to undo exactly
+        // what getch() above does (e.g., don't leave things in the middle of a
+        // sequence of escaped newlines).
+        void ungetch() override
+        {
+            input->unget();
+
+            do {
+                int ch = input->peek();
+                if (ch == '\r' || ch == '\n') {
+                    if (ch == '\n') {
+                        // correct for two-character newline
+                        input->unget();
+                        if (input->peek() != '\r')
+                            input->get();
+                    }
+                    // now in front of a complete newline, move past an escape character
+                    input->unget();
+                    if (input->peek() == '\\')
+                        input->unget();
+                    else {
+                        input->get();
+                        break;
+                    }
+                } else
+                    break;
+            } while (true);
+        }
+
+    protected:
+        TInputScanner* input;
+    };
+
+    // Holds a reference to included file data, as well as a
+    // prologue and an epilogue string. This can be scanned using the tInput
+    // interface and acts as a single source string.
+    class TokenizableIncludeFile : public tInput {
+    public:
+        // Copies prologue and epilogue. The includedFile must remain valid
+        // until this TokenizableIncludeFile is no longer used.
+        TokenizableIncludeFile(const TSourceLoc& startLoc,
+                          const std::string& prologue,
+                          TShader::Includer::IncludeResult* includedFile,
+                          const std::string& epilogue,
+                          TPpContext* pp)
+            : tInput(pp),
+              prologue_(prologue),
+              epilogue_(epilogue),
+              includedFile_(includedFile),
+              scanner(3, strings, lengths, names, 0, 0, true),
+              prevScanner(nullptr),
+              stringInput(pp, scanner)
+        {
+              strings[0] = prologue_.data();
+              strings[1] = includedFile_->headerData;
+              strings[2] = epilogue_.data();
+
+              lengths[0] = prologue_.size();
+              lengths[1] = includedFile_->headerLength;
+              lengths[2] = epilogue_.size();
+
+              scanner.setLine(startLoc.line);
+              scanner.setString(startLoc.string);
+
+              scanner.setFile(startLoc.name, 0);
+              scanner.setFile(startLoc.name, 1);
+              scanner.setFile(startLoc.name, 2);
+        }
+
+        // tInput methods:
+        int scan(TPpToken* t) override { return stringInput.scan(t); }
+        int getch() override { return stringInput.getch(); }
+        void ungetch() override { stringInput.ungetch(); }
+
+        void notifyActivated() override
+        {
+            prevScanner = pp->parseContext.getScanner();
+            pp->parseContext.setScanner(&scanner);
+            pp->push_include(includedFile_);
+        }
+
+        void notifyDeleted() override
+        {
+            pp->parseContext.setScanner(prevScanner);
+            pp->pop_include();
+        }
+
+    private:
+        TokenizableIncludeFile& operator=(const TokenizableIncludeFile&);
+
+        // Stores the prologue for this string.
+        const std::string prologue_;
+
+        // Stores the epilogue for this string.
+        const std::string epilogue_;
+
+        // Points to the IncludeResult that this TokenizableIncludeFile represents.
+        TShader::Includer::IncludeResult* includedFile_;
+
+        // Will point to prologue_, includedFile_->headerData and epilogue_
+        // This is passed to scanner constructor.
+        // These do not own the storage and it must remain valid until this
+        // object has been destroyed.
+        const char* strings[3];
+        // Length of str_, passed to scanner constructor.
+        size_t lengths[3];
+        // String names
+        const char* names[3];
+        // Scans over str_.
+        TInputScanner scanner;
+        // The previous effective scanner before the scanner in this instance
+        // has been activated.
+        TInputScanner* prevScanner;
+        // Delegate object implementing the tInput interface.
+        tStringInput stringInput;
+    };
+
+    int ScanFromString(char* s);
+    void missingEndifCheck();
+    int lFloatConst(int len, int ch, TPpToken* ppToken);
+
+    void push_include(TShader::Includer::IncludeResult* result)
+    {
+        currentSourceFile = result->headerName;
+        includeStack.push(result);
+    }
+
+    void pop_include()
+    {
+        TShader::Includer::IncludeResult* include = includeStack.top();
+        includeStack.pop();
+        includer.releaseInclude(include);
+        if (includeStack.empty()) {
+            currentSourceFile = rootFileName;
+        } else {
+            currentSourceFile = includeStack.top()->headerName;
+        }
+    }
+
+    bool inComment;
+    std::string rootFileName;
+    std::stack<TShader::Includer::IncludeResult*> includeStack;
+    std::string currentSourceFile;
+};
+
+} // end namespace glslang
+
+#endif  // PPCONTEXT_H

+ 81 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp

@@ -0,0 +1,81 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+namespace glslang {
+
+} // end namespace glslang

+ 840 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp

@@ -0,0 +1,840 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <cstdlib>
+#include <cstring>
+
+#include "PpContext.h"
+#include "PpTokens.h"
+#include "../Scan.h"
+
+namespace glslang {
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Floating point constants: /////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+* lFloatConst() - Scan a single- or double-precision floating point constant.  Assumes that the scanner
+*         has seen at least one digit, followed by either a decimal '.' or the
+*         letter 'e', or a precision ending (e.g., F or LF).
+*/
+
+int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
+{
+    bool HasDecimalOrExponent = false;
+    int isDouble = 0;
+#ifdef AMD_EXTENSIONS
+    int isFloat16 = 0;
+    bool enableFloat16 = parseContext.version >= 450 && parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float);
+#endif
+
+    const auto saveName = [&](int ch) {
+        if (len <= MaxTokenLength)
+            ppToken->name[len++] = static_cast<char>(ch);
+    };
+
+    // Decimal:
+
+    if (ch == '.') {
+        HasDecimalOrExponent = true;
+        saveName(ch);
+        ch = getChar();
+        while (ch >= '0' && ch <= '9') {
+            saveName(ch);
+            ch = getChar();
+        }
+    }
+
+    // Exponent:
+
+    if (ch == 'e' || ch == 'E') {
+        HasDecimalOrExponent = true;
+        saveName(ch);
+        ch = getChar();
+        if (ch == '+' || ch == '-') {
+            saveName(ch);
+            ch = getChar();
+        }
+        if (ch >= '0' && ch <= '9') {
+            while (ch >= '0' && ch <= '9') {
+                saveName(ch);
+                ch = getChar();
+            }
+        } else {
+            parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
+        }
+    }
+
+    // Suffix:
+
+    if (ch == 'l' || ch == 'L') {
+        parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
+        if (! HasDecimalOrExponent)
+            parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+        int ch2 = getChar();
+        if (ch2 != 'f' && ch2 != 'F') {
+            ungetChar();
+            ungetChar();
+        } else {
+            saveName(ch);
+            saveName(ch2);
+            isDouble = 1;
+        }
+#ifdef AMD_EXTENSIONS
+    } else if (enableFloat16 && (ch == 'h' || ch == 'H')) {
+        parseContext.float16Check(ppToken->loc, "half floating-point suffix");
+        if (!HasDecimalOrExponent)
+            parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+        int ch2 = getChar();
+        if (ch2 != 'f' && ch2 != 'F') {
+            ungetChar();
+            ungetChar();
+        } else {
+            saveName(ch);
+            saveName(ch2);
+            isFloat16 = 1;
+        }
+#endif
+    } else if (ch == 'f' || ch == 'F') {
+        parseContext.profileRequires(ppToken->loc,  EEsProfile, 300, nullptr, "floating-point suffix");
+        if (! parseContext.relaxedErrors())
+            parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
+        if (! HasDecimalOrExponent)
+            parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+        saveName(ch);
+    } else
+        ungetChar();
+
+    // Patch up the name, length, etc.
+
+    if (len > MaxTokenLength) {
+        len = MaxTokenLength;
+        parseContext.ppError(ppToken->loc, "float literal too long", "", "");
+    }
+    ppToken->name[len] = '\0';
+
+    // Get the numerical value
+    ppToken->dval = strtod(ppToken->name, nullptr);
+
+    // Return the right token type
+    if (isDouble)
+        return PpAtomConstDouble;
+#ifdef AMD_EXTENSIONS
+    else if (isFloat16)
+        return PpAtomConstFloat16;
+#endif
+    else
+        return PpAtomConstFloat;
+}
+
+//
+// Scanner used to tokenize source stream.
+//
+int TPpContext::tStringInput::scan(TPpToken* ppToken)
+{
+    int AlreadyComplained = 0;
+    int len = 0;
+    int ch = 0;
+    int ii = 0;
+    unsigned long long ival = 0;
+    bool enableInt64 = pp->parseContext.version >= 450 && pp->parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64);
+
+    ppToken->ival = 0;
+    ppToken->i64val = 0;
+    ppToken->space = false;
+    ch = getch();
+    for (;;) {
+        while (ch == ' ' || ch == '\t') {
+            ppToken->space = true;
+            ch = getch();
+        }
+
+        ppToken->loc = pp->parseContext.getCurrentLoc();
+        len = 0;
+        switch (ch) {
+        default:
+            // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
+            return ch;
+
+        case 'A': case 'B': case 'C': case 'D': case 'E':
+        case 'F': case 'G': case 'H': case 'I': case 'J':
+        case 'K': case 'L': case 'M': case 'N': case 'O':
+        case 'P': case 'Q': case 'R': case 'S': case 'T':
+        case 'U': case 'V': case 'W': case 'X': case 'Y':
+        case 'Z': case '_':
+        case 'a': case 'b': case 'c': case 'd': case 'e':
+        case 'f': case 'g': case 'h': case 'i': case 'j':
+        case 'k': case 'l': case 'm': case 'n': case 'o':
+        case 'p': case 'q': case 'r': case 's': case 't':
+        case 'u': case 'v': case 'w': case 'x': case 'y':
+        case 'z':
+            do {
+                if (len < MaxTokenLength) {
+                    ppToken->name[len++] = (char)ch;
+                    ch = getch();
+                } else {
+                    if (! AlreadyComplained) {
+                        pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
+                        AlreadyComplained = 1;
+                    }
+                    ch = getch();
+                }
+            } while ((ch >= 'a' && ch <= 'z') ||
+                     (ch >= 'A' && ch <= 'Z') ||
+                     (ch >= '0' && ch <= '9') ||
+                     ch == '_');
+
+            // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
+            if (len == 0)
+                continue;
+
+            ppToken->name[len] = '\0';
+            ungetch();
+            return PpAtomIdentifier;
+        case '0':
+            ppToken->name[len++] = (char)ch;
+            ch = getch();
+            if (ch == 'x' || ch == 'X') {
+                // must be hexadecimal
+
+                bool isUnsigned = false;
+                bool isInt64 = false;
+                ppToken->name[len++] = (char)ch;
+                ch = getch();
+                if ((ch >= '0' && ch <= '9') ||
+                    (ch >= 'A' && ch <= 'F') ||
+                    (ch >= 'a' && ch <= 'f')) {
+
+                    ival = 0;
+                    do {
+                        if (ival <= 0x0fffffff || (enableInt64 && ival <= 0x0fffffffffffffffull)) {
+                            ppToken->name[len++] = (char)ch;
+                            if (ch >= '0' && ch <= '9') {
+                                ii = ch - '0';
+                            } else if (ch >= 'A' && ch <= 'F') {
+                                ii = ch - 'A' + 10;
+                            } else if (ch >= 'a' && ch <= 'f') {
+                                ii = ch - 'a' + 10;
+                            } else
+                                pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
+                            ival = (ival << 4) | ii;
+                        } else {
+                            if (! AlreadyComplained) {
+                                pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
+                                AlreadyComplained = 1;
+                            }
+                            ival = 0xffffffffffffffffull;
+                        }
+                        ch = getch();
+                    } while ((ch >= '0' && ch <= '9') ||
+                             (ch >= 'A' && ch <= 'F') ||
+                             (ch >= 'a' && ch <= 'f'));
+                } else {
+                    pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
+                }
+                if (ch == 'u' || ch == 'U') {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isUnsigned = true;
+
+                    if (enableInt64) {
+                        int nextCh = getch();
+                        if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
+                            if (len < MaxTokenLength)
+                                ppToken->name[len++] = (char)nextCh;
+                            isInt64 = true;
+                        } else
+                            ungetch();
+                    }
+                }
+                else if (enableInt64 && (ch == 'l' || ch == 'L')) {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isInt64 = true;
+                } else
+                    ungetch();
+                ppToken->name[len] = '\0';
+
+                if (isInt64) {
+                    ppToken->i64val = ival;
+                    return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+                } else {
+                    ppToken->ival = (int)ival;
+                    return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
+                }
+            } else {
+                // could be octal integer or floating point, speculative pursue octal until it must be floating point
+
+                bool isUnsigned = false;
+                bool isInt64 = false;
+                bool octalOverflow = false;
+                bool nonOctal = false;
+                ival = 0;
+
+                // see how much octal-like stuff we can read
+                while (ch >= '0' && ch <= '7') {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    else if (! AlreadyComplained) {
+                        pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
+                        AlreadyComplained = 1;
+                    }
+                    if (ival <= 0x1fffffff || (enableInt64 && ival <= 0x1fffffffffffffffull)) {
+                        ii = ch - '0';
+                        ival = (ival << 3) | ii;
+                    } else
+                        octalOverflow = true;
+                    ch = getch();
+                }
+
+                // could be part of a float...
+                if (ch == '8' || ch == '9') {
+                    nonOctal = true;
+                    do {
+                        if (len < MaxTokenLength)
+                            ppToken->name[len++] = (char)ch;
+                        else if (! AlreadyComplained) {
+                            pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
+                            AlreadyComplained = 1;
+                        }
+                        ch = getch();
+                    } while (ch >= '0' && ch <= '9');
+                }
+                if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F')
+                    return pp->lFloatConst(len, ch, ppToken);
+
+                // wasn't a float, so must be octal...
+                if (nonOctal)
+                    pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
+
+                if (ch == 'u' || ch == 'U') {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isUnsigned = true;
+
+                    if (enableInt64) {
+                        int nextCh = getch();
+                        if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
+                            if (len < MaxTokenLength)
+                                ppToken->name[len++] = (char)nextCh;
+                            isInt64 = true;
+                        } else
+                            ungetch();
+                    }
+                }
+                else if (enableInt64 && (ch == 'l' || ch == 'L')) {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isInt64 = true;
+                } else
+                    ungetch();
+                ppToken->name[len] = '\0';
+
+                if (octalOverflow)
+                    pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
+
+                if (isInt64) {
+                    ppToken->i64val = ival;
+                    return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+                } else {
+                    ppToken->ival = (int)ival;
+                    return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
+                }
+            }
+            break;
+        case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            // can't be hexadecimal or octal, is either decimal or floating point
+
+            do {
+                if (len < MaxTokenLength)
+                    ppToken->name[len++] = (char)ch;
+                else if (! AlreadyComplained) {
+                    pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
+                    AlreadyComplained = 1;
+                }
+                ch = getch();
+            } while (ch >= '0' && ch <= '9');
+            if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') {
+                return pp->lFloatConst(len, ch, ppToken);
+            } else {
+                // Finish handling signed and unsigned integers
+                int numericLen = len;
+                bool isUnsigned = false;
+                bool isInt64 = false;
+                if (ch == 'u' || ch == 'U') {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isUnsigned = true;
+
+                    if (enableInt64) {
+                        int nextCh = getch();
+                        if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
+                            if (len < MaxTokenLength)
+                                ppToken->name[len++] = (char)nextCh;
+                            isInt64 = true;
+                        } else
+                            ungetch();
+                    }
+                } else if (enableInt64 && (ch == 'l' || ch == 'L')) {
+                    if (len < MaxTokenLength)
+                        ppToken->name[len++] = (char)ch;
+                    isInt64 = true;
+                } else
+                    ungetch();
+
+                ppToken->name[len] = '\0';
+                ival = 0;
+                const unsigned oneTenthMaxInt  = 0xFFFFFFFFu / 10;
+                const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
+                const unsigned long long oneTenthMaxInt64  = 0xFFFFFFFFFFFFFFFFull / 10;
+                const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64;
+                for (int i = 0; i < numericLen; i++) {
+                    ch = ppToken->name[i] - '0';
+                    if ((enableInt64 == false && ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt))) ||
+                        (enableInt64 && ((ival > oneTenthMaxInt64) || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)))) {
+                        pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
+                        ival = 0xFFFFFFFFFFFFFFFFull;
+                        break;
+                    } else
+                        ival = ival * 10 + ch;
+                }
+
+                if (isInt64) {
+                    ppToken->i64val = ival;
+                    return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+                } else {
+                    ppToken->ival = (int)ival;
+                    return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
+                }
+            }
+            break;
+        case '-':
+            ch = getch();
+            if (ch == '-') {
+                return PpAtomDecrement;
+            } else if (ch == '=') {
+                return PPAtomSubAssign;
+            } else {
+                ungetch();
+                return '-';
+            }
+        case '+':
+            ch = getch();
+            if (ch == '+') {
+                return PpAtomIncrement;
+            } else if (ch == '=') {
+                return PPAtomAddAssign;
+            } else {
+                ungetch();
+                return '+';
+            }
+        case '*':
+            ch = getch();
+            if (ch == '=') {
+                return PPAtomMulAssign;
+            } else {
+                ungetch();
+                return '*';
+            }
+        case '%':
+            ch = getch();
+            if (ch == '=') {
+                return PPAtomModAssign;
+            } else {
+                ungetch();
+                return '%';
+            }
+        case '^':
+            ch = getch();
+            if (ch == '^') {
+                return PpAtomXor;
+            } else {
+                if (ch == '=')
+                    return PpAtomXorAssign;
+                else{
+                    ungetch();
+                    return '^';
+                }
+            }
+
+        case '=':
+            ch = getch();
+            if (ch == '=') {
+                return PpAtomEQ;
+            } else {
+                ungetch();
+                return '=';
+            }
+        case '!':
+            ch = getch();
+            if (ch == '=') {
+                return PpAtomNE;
+            } else {
+                ungetch();
+                return '!';
+            }
+        case '|':
+            ch = getch();
+            if (ch == '|') {
+                return PpAtomOr;
+            } else if (ch == '=') {
+                return PpAtomOrAssign;
+            } else {
+                ungetch();
+                return '|';
+            }
+        case '&':
+            ch = getch();
+            if (ch == '&') {
+                return PpAtomAnd;
+            } else if (ch == '=') {
+                return PpAtomAndAssign;
+            } else {
+                ungetch();
+                return '&';
+            }
+        case '<':
+            ch = getch();
+            if (ch == '<') {
+                ch = getch();
+                if (ch == '=')
+                    return PpAtomLeftAssign;
+                else {
+                    ungetch();
+                    return PpAtomLeft;
+                }
+            } else if (ch == '=') {
+                return PpAtomLE;
+            } else {
+                ungetch();
+                return '<';
+            }
+        case '>':
+            ch = getch();
+            if (ch == '>') {
+                ch = getch();
+                if (ch == '=')
+                    return PpAtomRightAssign;
+                else {
+                    ungetch();
+                    return PpAtomRight;
+                }
+            } else if (ch == '=') {
+                return PpAtomGE;
+            } else {
+                ungetch();
+                return '>';
+            }
+        case '.':
+            ch = getch();
+            if (ch >= '0' && ch <= '9') {
+                ungetch();
+                return pp->lFloatConst(0, '.', ppToken);
+            } else {
+                ungetch();
+                return '.';
+            }
+        case '/':
+            ch = getch();
+            if (ch == '/') {
+                pp->inComment = true;
+                do {
+                    ch = getch();
+                } while (ch != '\n' && ch != EndOfInput);
+                ppToken->space = true;
+                pp->inComment = false;
+
+                return ch;
+            } else if (ch == '*') {
+                ch = getch();
+                do {
+                    while (ch != '*') {
+                        if (ch == EndOfInput) {
+                            pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
+                            return ch;
+                        }
+                        ch = getch();
+                    }
+                    ch = getch();
+                    if (ch == EndOfInput) {
+                        pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
+                        return ch;
+                    }
+                } while (ch != '/');
+                ppToken->space = true;
+                // loop again to get the next token...
+                break;
+            } else if (ch == '=') {
+                return PPAtomDivAssign;
+            } else {
+                ungetch();
+                return '/';
+            }
+            break;
+        case '"':
+            // TODO: If this gets enhanced to handle escape sequences, or
+            // anything that is different than what #include needs, then
+            // #include needs to use scanHeaderName() for this.
+            ch = getch();
+            while (ch != '"' && ch != '\n' && ch != EndOfInput) {
+                if (len < MaxTokenLength) {
+                    ppToken->name[len] = (char)ch;
+                    len++;
+                    ch = getch();
+                } else
+                    break;
+            };
+            ppToken->name[len] = '\0';
+            if (ch != '"') {
+                ungetch();
+                pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
+            }
+            return PpAtomConstString;
+        }
+
+        ch = getch();
+    }
+}
+
+//
+// The main functional entry point into the preprocessor, which will
+// scan the source strings to figure out and return the next processing token.
+//
+// Return the token, or EndOfInput when no more tokens.
+//
+int TPpContext::tokenize(TPpToken& ppToken)
+{
+    for(;;) {
+        int token = scanToken(&ppToken);
+
+        // Handle token-pasting logic
+        token = tokenPaste(token, ppToken);
+
+        if (token == EndOfInput) {
+            missingEndifCheck();
+            return EndOfInput;
+        }
+        if (token == '#') {
+            if (previous_token == '\n') {
+                token = readCPPline(&ppToken);
+                if (token == EndOfInput) {
+                    missingEndifCheck();
+                    return EndOfInput;
+                }
+                continue;
+            } else {
+                parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", "");
+                return EndOfInput;
+            }
+        }
+        previous_token = token;
+
+        if (token == '\n')
+            continue;
+
+        // expand macros
+        if (token == PpAtomIdentifier && MacroExpand(&ppToken, false, true) != 0)
+            continue;
+
+        switch (token) {
+        case PpAtomIdentifier:
+        case PpAtomConstInt:
+        case PpAtomConstUint:
+        case PpAtomConstFloat:
+        case PpAtomConstInt64:
+        case PpAtomConstUint64:
+        case PpAtomConstDouble:
+#ifdef AMD_EXTENSIONS
+        case PpAtomConstFloat16:
+#endif
+            if (ppToken.name[0] == '\0')
+                continue;
+            break;
+        case PpAtomConstString:
+            if (parseContext.intermediate.getSource() != EShSourceHlsl) {
+                // HLSL allows string literals.
+                parseContext.ppError(ppToken.loc, "string literals not supported", "\"\"", "");
+                continue;
+            }
+            break;
+        case '\'':
+            parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
+            continue;
+        default:
+            strcpy(ppToken.name, atomStrings.getString(token));
+            break;
+        }
+
+        return token;
+    }
+}
+
+//
+// Do all token-pasting related combining of two pasted tokens when getting a
+// stream of tokens from a replacement list. Degenerates to no processing if a
+// replacement list is not the source of the token stream.
+//
+int TPpContext::tokenPaste(int token, TPpToken& ppToken)
+{
+    // starting with ## is illegal, skip to next token
+    if (token == PpAtomPaste) {
+        parseContext.ppError(ppToken.loc, "unexpected location", "##", "");
+        return scanToken(&ppToken);
+    }
+
+    int resultToken = token; // "foo" pasted with "35" is an identifier, not a number
+
+    // ## can be chained, process all in the chain at once
+    while (peekPasting()) {
+        TPpToken pastedPpToken;
+
+        // next token has to be ##
+        token = scanToken(&pastedPpToken);
+        assert(token == PpAtomPaste);
+
+        if (endOfReplacementList()) {
+            parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", "");
+            break;
+        }
+
+        // get the token after the ##
+        token = scanToken(&pastedPpToken);
+
+        // get the token text
+        switch (resultToken) {
+        case PpAtomIdentifier:
+            // already have the correct text in token.names
+            break;
+        case '=':
+        case '!':
+        case '-':
+        case '~':
+        case '+':
+        case '*':
+        case '/':
+        case '%':
+        case '<':
+        case '>':
+        case '|':
+        case '^':
+        case '&':
+        case PpAtomRight:
+        case PpAtomLeft:
+        case PpAtomAnd:
+        case PpAtomOr:
+        case PpAtomXor:
+            strcpy(ppToken.name, atomStrings.getString(resultToken));
+            strcpy(pastedPpToken.name, atomStrings.getString(token));
+            break;
+        default:
+            parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
+            return resultToken;
+        }
+
+        // combine the tokens
+        if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
+            parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
+            return resultToken;
+        }
+        strncat(ppToken.name, pastedPpToken.name, MaxTokenLength - strlen(ppToken.name));
+
+        // correct the kind of token we are making, if needed (identifiers stay identifiers)
+        if (resultToken != PpAtomIdentifier) {
+            int newToken = atomStrings.getAtom(ppToken.name);
+            if (newToken > 0)
+                resultToken = newToken;
+            else
+                parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
+        }
+    }
+
+    return resultToken;
+}
+
+// Checks if we've seen balanced #if...#endif
+void TPpContext::missingEndifCheck()
+{
+    if (ifdepth > 0)
+        parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
+}
+
+} // end namespace glslang

+ 77 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp

@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/

+ 326 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp

@@ -0,0 +1,326 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+//
+// For recording and playing back the stream of tokens in a macro definition.
+//
+
+#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
+#define _CRT_SECURE_NO_WARNINGS
+#define snprintf sprintf_s
+#endif
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+#include "PpContext.h"
+#include "PpTokens.h"
+
+namespace glslang {
+
+void TPpContext::lAddByte(TokenStream& fTok, unsigned char fVal)
+{
+    fTok.data.push_back(fVal);
+}
+
+/*
+* Get the next byte from a stream.
+*/
+int TPpContext::lReadByte(TokenStream& pTok)
+{
+    if (pTok.current < pTok.data.size())
+        return pTok.data[pTok.current++];
+    else
+        return EndOfInput;
+}
+
+void TPpContext::lUnreadByte(TokenStream& pTok)
+{
+    if (pTok.current > 0)
+        --pTok.current;
+}
+
+/*
+* Add a token to the end of a list for later playback.
+*/
+void TPpContext::RecordToken(TokenStream& pTok, int token, TPpToken* ppToken)
+{
+    const char* s;
+    char* str = NULL;
+
+    if (token > PpAtomMaxSingle)
+        lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80));
+    else
+        lAddByte(pTok, (unsigned char)(token & 0x7f));
+
+    switch (token) {
+    case PpAtomIdentifier:
+    case PpAtomConstString:
+        s = ppToken->name;
+        while (*s)
+            lAddByte(pTok, (unsigned char) *s++);
+        lAddByte(pTok, 0);
+        break;
+    case PpAtomConstInt:
+    case PpAtomConstUint:
+    case PpAtomConstInt64:
+    case PpAtomConstUint64:
+    case PpAtomConstFloat:
+    case PpAtomConstDouble:
+#ifdef AMD_EXTENSIONS
+    case PpAtomConstFloat16:
+#endif
+        str = ppToken->name;
+        while (*str) {
+            lAddByte(pTok, (unsigned char) *str);
+            str++;
+        }
+        lAddByte(pTok, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+/*
+* Reset a token stream in preparation for reading.
+*/
+void TPpContext::RewindTokenStream(TokenStream& pTok)
+{
+    pTok.current = 0;
+}
+
+/*
+* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro).
+*/
+int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
+{
+    int ltoken, len;
+    int ch;
+
+    ltoken = lReadByte(pTok);
+    ppToken->loc = parseContext.getCurrentLoc();
+    if (ltoken > 127)
+        ltoken += 128;
+    switch (ltoken) {
+    case '#':
+        // Check for ##, unless the current # is the last character
+        if (pTok.current < pTok.data.size()) {
+            if (lReadByte(pTok) == '#') {
+                parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
+                parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
+                ltoken = PpAtomPaste;
+            } else
+                lUnreadByte(pTok);
+        }
+        break;
+    case PpAtomConstString:
+    case PpAtomIdentifier:
+    case PpAtomConstFloat:
+    case PpAtomConstDouble:
+#ifdef AMD_EXTENSIONS
+    case PpAtomConstFloat16:
+#endif
+    case PpAtomConstInt:
+    case PpAtomConstUint:
+    case PpAtomConstInt64:
+    case PpAtomConstUint64:
+        len = 0;
+        ch = lReadByte(pTok);
+        while (ch != 0 && ch != EndOfInput) {
+            if (len < MaxTokenLength) {
+                ppToken->name[len] = (char)ch;
+                len++;
+                ch = lReadByte(pTok);
+            } else {
+                parseContext.error(ppToken->loc, "token too long", "", "");
+                break;
+            }
+        }
+        ppToken->name[len] = 0;
+
+        switch (ltoken) {
+        case PpAtomIdentifier:
+            break;
+        case PpAtomConstString:
+            break;
+        case PpAtomConstFloat:
+        case PpAtomConstDouble:
+#ifdef AMD_EXTENSIONS
+        case PpAtomConstFloat16:
+#endif
+            ppToken->dval = atof(ppToken->name);
+            break;
+        case PpAtomConstInt:
+            if (len > 0 && ppToken->name[0] == '0') {
+                if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
+                    ppToken->ival = (int)strtol(ppToken->name, 0, 16);
+                else
+                    ppToken->ival = (int)strtol(ppToken->name, 0, 8);
+            } else
+                ppToken->ival = atoi(ppToken->name);
+            break;
+        case PpAtomConstUint:
+            if (len > 0 && ppToken->name[0] == '0') {
+                if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
+                    ppToken->ival = (int)strtoul(ppToken->name, 0, 16);
+                else
+                    ppToken->ival = (int)strtoul(ppToken->name, 0, 8);
+            } else
+                ppToken->ival = (int)strtoul(ppToken->name, 0, 10);
+            break;
+        case PpAtomConstInt64:
+            if (len > 0 && ppToken->name[0] == '0') {
+                if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
+                    ppToken->i64val = strtoll(ppToken->name, nullptr, 16);
+                else
+                    ppToken->i64val = strtoll(ppToken->name, nullptr, 8);
+            } else
+                ppToken->i64val = atoll(ppToken->name);
+            break;
+        case PpAtomConstUint64:
+            if (len > 0 && ppToken->name[0] == '0') {
+                if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
+                    ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 16);
+                else
+                    ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 8);
+            } else
+                ppToken->i64val = (long long)strtoull(ppToken->name, 0, 10);
+            break;
+        }
+    }
+
+    return ltoken;
+}
+
+int TPpContext::tTokenInput::scan(TPpToken* ppToken)
+{
+    return pp->ReadToken(*tokens, ppToken);
+}
+
+// We are pasting if the entire macro is preceding a pasting operator
+// (lastTokenPastes) and we are also on the last token.
+bool TPpContext::tTokenInput::peekPasting()
+{
+    if (! lastTokenPastes)
+        return false;
+    // Getting here means the last token will be pasted.
+
+    // Are we at the last non-whitespace token?
+    size_t savePos = tokens->current;
+    bool moreTokens = false;
+    do {
+        int byte = pp->lReadByte(*tokens);
+        if (byte == EndOfInput)
+            break;
+        if (byte != ' ') {
+            moreTokens = true;
+            break;
+        }
+    } while (true);
+    tokens->current = savePos;
+
+    return !moreTokens;
+}
+
+void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting)
+{
+    pushInput(new tTokenInput(this, &ts, prepasting));
+    RewindTokenStream(ts);
+}
+
+int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken)
+{
+    if (done)
+        return EndOfInput;
+
+    int ret = token;
+    *ppToken = lval;
+    done = true;
+
+    return ret;
+}
+
+void TPpContext::UngetToken(int token, TPpToken* ppToken)
+{
+    pushInput(new tUngotTokenInput(this, token, ppToken));
+}
+
+} // end namespace glslang

+ 173 - 0
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h

@@ -0,0 +1,173 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms.  If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#ifndef PARSER_H
+#define PARSER_H
+
+namespace glslang {
+
+// Multi-character tokens
+enum EFixedAtoms {
+    PpAtomMaxSingle = 256, // single character tokens get their own char value as their token, skip them
+
+    // Operators
+
+    PPAtomAddAssign,
+    PPAtomSubAssign,
+    PPAtomMulAssign,
+    PPAtomDivAssign,
+    PPAtomModAssign,
+
+    PpAtomRight,
+    PpAtomLeft,
+
+    PpAtomRightAssign,
+    PpAtomLeftAssign,
+    PpAtomAndAssign,
+    PpAtomOrAssign,
+    PpAtomXorAssign,
+
+    PpAtomAnd,
+    PpAtomOr,
+    PpAtomXor,
+
+    PpAtomEQ,
+    PpAtomNE,
+    PpAtomGE,
+    PpAtomLE,
+
+    PpAtomDecrement,
+    PpAtomIncrement,
+
+    PpAtomPaste,
+
+    // Constants
+
+    PpAtomConstInt,
+    PpAtomConstUint,
+    PpAtomConstInt64,
+    PpAtomConstUint64,
+    PpAtomConstFloat,
+    PpAtomConstDouble,
+#ifdef AMD_EXTENSIONS
+    PpAtomConstFloat16,
+#endif
+    PpAtomConstString,
+
+    // Identifiers
+    PpAtomIdentifier,
+
+    // preprocessor "keywords"
+
+    PpAtomDefine,
+    PpAtomUndef,
+
+    PpAtomIf,
+    PpAtomIfdef,
+    PpAtomIfndef,
+    PpAtomElse,
+    PpAtomElif,
+    PpAtomEndif,
+
+    PpAtomLine,
+    PpAtomPragma,
+    PpAtomError,
+
+    // #version ...
+    PpAtomVersion,
+    PpAtomCore,
+    PpAtomCompatibility,
+    PpAtomEs,
+
+    // #extension
+    PpAtomExtension,
+
+    // __LINE__, __FILE__, __VERSION__
+
+    PpAtomLineMacro,
+    PpAtomFileMacro,
+    PpAtomVersionMacro,
+
+    // #include
+    PpAtomInclude,
+
+    PpAtomLast,
+};
+
+} // end namespace glslang
+
+#endif /* not PARSER_H */

+ 866 - 0
src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp

@@ -0,0 +1,866 @@
+//
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of Google Inc. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Visit the nodes in the glslang intermediate tree representation to
+// propagate the 'noContraction' qualifier.
+//
+
+#include "propagateNoContraction.h"
+
+#include <cstdlib>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "localintermediate.h"
+namespace {
+
+// Use a string to hold the access chain information, as in most cases the
+// access chain is short and may contain only one element, which is the symbol
+// ID.
+// Example: struct {float a; float b;} s;
+//  Object s.a will be represented with: <symbol ID of s>/0
+//  Object s.b will be represented with: <symbol ID of s>/1
+//  Object s will be represented with: <symbol ID of s>
+// For members of vector, matrix and arrays, they will be represented with the
+// same symbol ID of their container symbol objects. This is because their
+// preciseness is always the same as their container symbol objects.
+typedef std::string ObjectAccessChain;
+
+// The delimiter used in the ObjectAccessChain string to separate symbol ID and
+// different level of struct indices.
+const char ObjectAccesschainDelimiter = '/';
+
+// Mapping from Symbol IDs of symbol nodes, to their defining operation
+// nodes.
+typedef std::unordered_multimap<ObjectAccessChain, glslang::TIntermOperator*> NodeMapping;
+// Mapping from object nodes to their access chain info string.
+typedef std::unordered_map<glslang::TIntermTyped*, ObjectAccessChain> AccessChainMapping;
+
+// Set of object IDs.
+typedef std::unordered_set<ObjectAccessChain> ObjectAccesschainSet;
+// Set of return branch nodes.
+typedef std::unordered_set<glslang::TIntermBranch*> ReturnBranchNodeSet;
+
+// A helper function to tell whether a node is 'noContraction'. Returns true if
+// the node has 'noContraction' qualifier, otherwise false.
+bool isPreciseObjectNode(glslang::TIntermTyped* node)
+{
+    return node->getType().getQualifier().noContraction;
+}
+
+// Returns true if the opcode is a dereferencing one.
+bool isDereferenceOperation(glslang::TOperator op)
+{
+    switch (op) {
+    case glslang::EOpIndexDirect:
+    case glslang::EOpIndexDirectStruct:
+    case glslang::EOpIndexIndirect:
+    case glslang::EOpVectorSwizzle:
+    case glslang::EOpMatrixSwizzle:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// Returns true if the opcode leads to an assignment operation.
+bool isAssignOperation(glslang::TOperator op)
+{
+    switch (op) {
+    case glslang::EOpAssign:
+    case glslang::EOpAddAssign:
+    case glslang::EOpSubAssign:
+    case glslang::EOpMulAssign:
+    case glslang::EOpVectorTimesMatrixAssign:
+    case glslang::EOpVectorTimesScalarAssign:
+    case glslang::EOpMatrixTimesScalarAssign:
+    case glslang::EOpMatrixTimesMatrixAssign:
+    case glslang::EOpDivAssign:
+    case glslang::EOpModAssign:
+    case glslang::EOpAndAssign:
+    case glslang::EOpLeftShiftAssign:
+    case glslang::EOpRightShiftAssign:
+    case glslang::EOpInclusiveOrAssign:
+    case glslang::EOpExclusiveOrAssign:
+
+    case glslang::EOpPostIncrement:
+    case glslang::EOpPostDecrement:
+    case glslang::EOpPreIncrement:
+    case glslang::EOpPreDecrement:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// A helper function to get the unsigned int from a given constant union node.
+// Note the node should only hold a uint scalar.
+unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped* node)
+{
+    assert(node->getAsConstantUnion() && node->getAsConstantUnion()->isScalar());
+    unsigned struct_dereference_index = node->getAsConstantUnion()->getConstArray()[0].getUConst();
+    return struct_dereference_index;
+}
+
+// A helper function to generate symbol_label.
+ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node)
+{
+    ObjectAccessChain symbol_id =
+        std::to_string(node->getId()) + "(" + node->getName().c_str() + ")";
+    return symbol_id;
+}
+
+// Returns true if the operation is an arithmetic operation and valid for
+// the 'NoContraction' decoration.
+bool isArithmeticOperation(glslang::TOperator op)
+{
+    switch (op) {
+    case glslang::EOpAddAssign:
+    case glslang::EOpSubAssign:
+    case glslang::EOpMulAssign:
+    case glslang::EOpVectorTimesMatrixAssign:
+    case glslang::EOpVectorTimesScalarAssign:
+    case glslang::EOpMatrixTimesScalarAssign:
+    case glslang::EOpMatrixTimesMatrixAssign:
+    case glslang::EOpDivAssign:
+    case glslang::EOpModAssign:
+
+    case glslang::EOpNegative:
+
+    case glslang::EOpAdd:
+    case glslang::EOpSub:
+    case glslang::EOpMul:
+    case glslang::EOpDiv:
+    case glslang::EOpMod:
+
+    case glslang::EOpVectorTimesScalar:
+    case glslang::EOpVectorTimesMatrix:
+    case glslang::EOpMatrixTimesVector:
+    case glslang::EOpMatrixTimesScalar:
+    case glslang::EOpMatrixTimesMatrix:
+
+    case glslang::EOpDot:
+
+    case glslang::EOpPostIncrement:
+    case glslang::EOpPostDecrement:
+    case glslang::EOpPreIncrement:
+    case glslang::EOpPreDecrement:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// A helper class to help manage the populating_initial_no_contraction_ flag.
+template <typename T> class StateSettingGuard {
+public:
+    StateSettingGuard(T* state_ptr, T new_state_value)
+        : state_ptr_(state_ptr), previous_state_(*state_ptr)
+    {
+        *state_ptr = new_state_value;
+    }
+    StateSettingGuard(T* state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {}
+    void setState(T new_state_value) { *state_ptr_ = new_state_value; }
+    ~StateSettingGuard() { *state_ptr_ = previous_state_; }
+
+private:
+    T* state_ptr_;
+    T previous_state_;
+};
+
+// A helper function to get the front element from a given ObjectAccessChain
+ObjectAccessChain getFrontElement(const ObjectAccessChain& chain)
+{
+    size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
+    return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter);
+}
+
+// A helper function to get the access chain starting from the second element.
+ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain)
+{
+    size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
+    return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1);
+}
+
+// A helper function to get the access chain after removing a given prefix.
+ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain,
+                                               const ObjectAccessChain& prefix)
+{
+    size_t pos = chain.find(prefix);
+    if (pos != 0)
+        return chain;
+    return chain.substr(prefix.length() + sizeof(ObjectAccesschainDelimiter));
+}
+
+//
+// A traverser which traverses the whole AST and populates:
+//  1) A mapping from symbol nodes' IDs to their defining operation nodes.
+//  2) A set of access chains of the initial precise object nodes.
+//
+class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser {
+public:
+    TSymbolDefinitionCollectingTraverser(NodeMapping* symbol_definition_mapping,
+                                         AccessChainMapping* accesschain_mapping,
+                                         ObjectAccesschainSet* precise_objects,
+                                         ReturnBranchNodeSet* precise_return_nodes);
+
+    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*) override;
+    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*) override;
+    void visitSymbol(glslang::TIntermSymbol*) override;
+    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*) override;
+    bool visitBranch(glslang::TVisit, glslang::TIntermBranch*) override;
+
+protected:
+    TSymbolDefinitionCollectingTraverser& operator=(const TSymbolDefinitionCollectingTraverser&);
+
+    // The mapping from symbol node IDs to their defining nodes. This should be
+    // populated along traversing the AST.
+    NodeMapping& symbol_definition_mapping_;
+    // The set of symbol node IDs for precise symbol nodes, the ones marked as
+    // 'noContraction'.
+    ObjectAccesschainSet& precise_objects_;
+    // The set of precise return nodes.
+    ReturnBranchNodeSet& precise_return_nodes_;
+    // A temporary cache of the symbol node whose defining node is to be found
+    // currently along traversing the AST.
+    ObjectAccessChain current_object_;
+    // A map from object node to its access chain. This traverser stores
+    // the built access chains into this map for each object node it has
+    // visited.
+    AccessChainMapping& accesschain_mapping_;
+    // The pointer to the Function Definition node, so we can get the
+    // preciseness of the return expression from it when we traverse the
+    // return branch node.
+    glslang::TIntermAggregate* current_function_definition_node_;
+};
+
+TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser(
+    NodeMapping* symbol_definition_mapping, AccessChainMapping* accesschain_mapping,
+    ObjectAccesschainSet* precise_objects,
+    std::unordered_set<glslang::TIntermBranch*>* precise_return_nodes)
+    : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping),
+      precise_objects_(*precise_objects), precise_return_nodes_(*precise_return_nodes),
+      current_object_(), accesschain_mapping_(*accesschain_mapping),
+      current_function_definition_node_(nullptr) {}
+
+// Visits a symbol node, set the current_object_ to the
+// current node symbol ID, and record a mapping from this node to the current
+// current_object_, which is the just obtained symbol
+// ID.
+void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node)
+{
+    current_object_ = generateSymbolLabel(node);
+    accesschain_mapping_[node] = current_object_;
+}
+
+// Visits an aggregate node, traverses all of its children.
+bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit,
+                                                          glslang::TIntermAggregate* node)
+{
+    // This aggregate node might be a function definition node, in which case we need to
+    // cache this node, so we can get the preciseness information of the return value
+    // of this function later.
+    StateSettingGuard<glslang::TIntermAggregate*> current_function_definition_node_setting_guard(
+        &current_function_definition_node_);
+    if (node->getOp() == glslang::EOpFunction) {
+        // This is function definition node, we need to cache this node so that we can
+        // get the preciseness of the return value later.
+        current_function_definition_node_setting_guard.setState(node);
+    }
+    // Traverse the items in the sequence.
+    glslang::TIntermSequence& seq = node->getSequence();
+    for (int i = 0; i < (int)seq.size(); ++i) {
+        current_object_.clear();
+        seq[i]->traverse(this);
+    }
+    return false;
+}
+
+bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit,
+                                                       glslang::TIntermBranch* node)
+{
+    if (node->getFlowOp() == glslang::EOpReturn && node->getExpression() &&
+        current_function_definition_node_ &&
+        current_function_definition_node_->getType().getQualifier().noContraction) {
+        // This node is a return node with an expression, and its function has a
+        // precise return value. We need to find the involved objects in its
+        // expression and add them to the set of initial precise objects.
+        precise_return_nodes_.insert(node);
+        node->getExpression()->traverse(this);
+    }
+    return false;
+}
+
+// Visits a unary node. This might be an implicit assignment like i++, i--. etc.
+bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */,
+                                                      glslang::TIntermUnary* node)
+{
+    current_object_.clear();
+    node->getOperand()->traverse(this);
+    if (isAssignOperation(node->getOp())) {
+        // We should always be able to get an access chain of the operand node.
+        assert(!current_object_.empty());
+
+        // If the operand node object is 'precise', we collect its access chain
+        // for the initial set of 'precise' objects.
+        if (isPreciseObjectNode(node->getOperand())) {
+            // The operand node is an 'precise' object node, add its
+            // access chain to the set of 'precise' objects. This is to collect
+            // the initial set of 'precise' objects.
+            precise_objects_.insert(current_object_);
+        }
+        // Gets the symbol ID from the object's access chain.
+        ObjectAccessChain id_symbol = getFrontElement(current_object_);
+        // Add a mapping from the symbol ID to this assignment operation node.
+        symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
+    }
+    // A unary node is not a dereference node, so we clear the access chain which
+    // is under construction.
+    current_object_.clear();
+    return false;
+}
+
+// Visits a binary node and updates the mapping from symbol IDs to the definition
+// nodes. Also collects the access chains for the initial precise objects.
+bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */,
+                                                       glslang::TIntermBinary* node)
+{
+    // Traverses the left node to build the access chain info for the object.
+    current_object_.clear();
+    node->getLeft()->traverse(this);
+
+    if (isAssignOperation(node->getOp())) {
+        // We should always be able to get an access chain for the left node.
+        assert(!current_object_.empty());
+
+        // If the left node object is 'precise', it is an initial precise object
+        // specified in the shader source. Adds it to the initial work list to
+        // process later.
+        if (isPreciseObjectNode(node->getLeft())) {
+            // The left node is an 'precise' object node, add its access chain to
+            // the set of 'precise' objects. This is to collect the initial set
+            // of 'precise' objects.
+            precise_objects_.insert(current_object_);
+        }
+        // Gets the symbol ID from the object access chain, which should be the
+        // first element recorded in the access chain.
+        ObjectAccessChain id_symbol = getFrontElement(current_object_);
+        // Adds a mapping from the symbol ID to this assignment operation node.
+        symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
+
+        // Traverses the right node, there may be other 'assignment'
+        // operations in the right.
+        current_object_.clear();
+        node->getRight()->traverse(this);
+
+    } else if (isDereferenceOperation(node->getOp())) {
+        // The left node (parent node) is a struct type object. We need to
+        // record the access chain information of the current node into its
+        // object id.
+        if (node->getOp() == glslang::EOpIndexDirectStruct) {
+            unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight());
+            current_object_.push_back(ObjectAccesschainDelimiter);
+            current_object_.append(std::to_string(struct_dereference_index));
+        }
+        accesschain_mapping_[node] = current_object_;
+
+        // For a dereference node, there is no need to traverse the right child
+        // node as the right node should always be an integer type object.
+
+    } else {
+        // For other binary nodes, still traverse the right node.
+        current_object_.clear();
+        node->getRight()->traverse(this);
+    }
+    return false;
+}
+
+// Traverses the AST and returns a tuple of four members:
+// 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols.
+// 2) a mapping from object nodes in the AST to the access chains of these objects.
+// 3) a set of access chains of precise objects.
+// 4) a set of return nodes with precise expressions.
+std::tuple<NodeMapping, AccessChainMapping, ObjectAccesschainSet, ReturnBranchNodeSet>
+getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate)
+{
+    auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(),
+                                        ReturnBranchNodeSet());
+
+    TIntermNode* root = intermediate.getTreeRoot();
+    if (root == 0)
+        return result_tuple;
+
+    NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple);
+    AccessChainMapping& accesschain_mapping = std::get<1>(result_tuple);
+    ObjectAccesschainSet& precise_objects = std::get<2>(result_tuple);
+    ReturnBranchNodeSet& precise_return_nodes = std::get<3>(result_tuple);
+
+    // Traverses the AST and populate the results.
+    TSymbolDefinitionCollectingTraverser collector(&symbol_definition_mapping, &accesschain_mapping,
+                                                   &precise_objects, &precise_return_nodes);
+    root->traverse(&collector);
+
+    return result_tuple;
+}
+
+//
+// A traverser that determine whether the left node (or operand node for unary
+// node) of an assignment node is 'precise', containing 'precise' or not,
+// according to the access chain a given precise object which share the same
+// symbol as the left node.
+//
+// Post-orderly traverses the left node subtree of an binary assignment node and:
+//
+//  1) Propagates the 'precise' from the left object nodes to this object node.
+//
+//  2) Builds object access chain along the traversal, and also compares with
+//  the access chain of the given 'precise' object along with the traversal to
+//  tell if the node to be defined is 'precise' or not.
+//
+class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser {
+
+    enum DecisionStatus {
+        // The object node to be assigned to may contain 'precise' objects and also not 'precise' objects.
+        Mixed = 0,
+        // The object node to be assigned to is either a 'precise' object or a struct objects whose members are all 'precise'.
+        Precise = 1,
+        // The object node to be assigned to is not a 'precise' object.
+        NotPreicse = 2,
+    };
+
+public:
+    TNoContractionAssigneeCheckingTraverser(const AccessChainMapping& accesschain_mapping)
+        : TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping),
+          precise_object_(nullptr) {}
+
+    // Checks the preciseness of a given assignment node with a precise object
+    // represented as access chain. The precise object shares the same symbol
+    // with the assignee of the given assignment node. Return a tuple of two:
+    //
+    //  1) The preciseness of the assignee node of this assignment node. True
+    //  if the assignee contains 'precise' objects or is 'precise', false if
+    //  the assignee is not 'precise' according to the access chain of the given
+    //  precise object.
+    //
+    //  2) The incremental access chain from the assignee node to its nested
+    //  'precise' object, according to the access chain of the given precise
+    //  object. This incremental access chain can be empty, which means the
+    //  assignee is 'precise'. Otherwise it shows the path to the nested
+    //  precise object.
+    std::tuple<bool, ObjectAccessChain>
+    getPrecisenessAndRemainedAccessChain(glslang::TIntermOperator* node,
+                                         const ObjectAccessChain& precise_object)
+    {
+        assert(isAssignOperation(node->getOp()));
+        precise_object_ = &precise_object;
+        ObjectAccessChain assignee_object;
+        if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) {
+            // This is a binary assignment node, we need to check the
+            // preciseness of the left node.
+            assert(accesschain_mapping_.count(BN->getLeft()));
+            // The left node (assignee node) is an object node, traverse the
+            // node to let the 'precise' of nesting objects being transfered to
+            // nested objects.
+            BN->getLeft()->traverse(this);
+            // After traversing the left node, if the left node is 'precise',
+            // we can conclude this assignment should propagate 'precise'.
+            if (isPreciseObjectNode(BN->getLeft())) {
+                return make_tuple(true, ObjectAccessChain());
+            }
+            // If the preciseness of the left node (assignee node) can not
+            // be determined by now, we need to compare the access chain string
+            // of the assignee object with the given precise object.
+            assignee_object = accesschain_mapping_.at(BN->getLeft());
+
+        } else if (glslang::TIntermUnary* UN = node->getAsUnaryNode()) {
+            // This is a unary assignment node, we need to check the
+            // preciseness of the operand node. For unary assignment node, the
+            // operand node should always be an object node.
+            assert(accesschain_mapping_.count(UN->getOperand()));
+            // Traverse the operand node to let the 'precise' being propagated
+            // from lower nodes to upper nodes.
+            UN->getOperand()->traverse(this);
+            // After traversing the operand node, if the operand node is
+            // 'precise', this assignment should propagate 'precise'.
+            if (isPreciseObjectNode(UN->getOperand())) {
+                return make_tuple(true, ObjectAccessChain());
+            }
+            // If the preciseness of the operand node (assignee node) can not
+            // be determined by now, we need to compare the access chain string
+            // of the assignee object with the given precise object.
+            assignee_object = accesschain_mapping_.at(UN->getOperand());
+        } else {
+            // Not a binary or unary node, should not happen.
+            assert(false);
+        }
+
+        // Compare the access chain string of the assignee node with the given
+        // precise object to determine if this assignment should propagate
+        // 'precise'.
+        if (assignee_object.find(precise_object) == 0) {
+            // The access chain string of the given precise object is a prefix
+            // of assignee's access chain string. The assignee should be
+            // 'precise'.
+            return make_tuple(true, ObjectAccessChain());
+        } else if (precise_object.find(assignee_object) == 0) {
+            // The assignee's access chain string is a prefix of the given
+            // precise object, the assignee object contains 'precise' object,
+            // and we need to pass the remained access chain to the object nodes
+            // in the right.
+            return make_tuple(true, getSubAccessChainAfterPrefix(precise_object, assignee_object));
+        } else {
+            // The access chain strings do not match, the assignee object can
+            // not be labeled as 'precise' according to the given precise
+            // object.
+            return make_tuple(false, ObjectAccessChain());
+        }
+    }
+
+protected:
+    TNoContractionAssigneeCheckingTraverser& operator=(const TNoContractionAssigneeCheckingTraverser&);
+
+    bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override;
+    void visitSymbol(glslang::TIntermSymbol* node) override;
+
+    // A map from object nodes to their access chain string (used as object ID).
+    const AccessChainMapping& accesschain_mapping_;
+    // A given precise object, represented in it access chain string. This
+    // precise object is used to be compared with the assignee node to tell if
+    // the assignee node is 'precise', contains 'precise' object or not
+    // 'precise'.
+    const ObjectAccessChain* precise_object_;
+};
+
+// Visits a binary node. If the node is an object node, it must be a dereference
+// node. In such cases, if the left node is 'precise', this node should also be
+// 'precise'.
+bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit,
+                                                          glslang::TIntermBinary* node)
+{
+    // Traverses the left so that we transfer the 'precise' from nesting object
+    // to its nested object.
+    node->getLeft()->traverse(this);
+    // If this binary node is an object node, we should have it in the
+    // accesschain_mapping_.
+    if (accesschain_mapping_.count(node)) {
+        // A binary object node must be a dereference node.
+        assert(isDereferenceOperation(node->getOp()));
+        // If the left node is 'precise', this node should also be precise,
+        // otherwise, compare with the given precise_object_. If the
+        // access chain of this node matches with the given precise_object_,
+        // this node should be marked as 'precise'.
+        if (isPreciseObjectNode(node->getLeft())) {
+            node->getWritableType().getQualifier().noContraction = true;
+        } else if (accesschain_mapping_.at(node) == *precise_object_) {
+            node->getWritableType().getQualifier().noContraction = true;
+        }
+    }
+    return false;
+}
+
+// Visits a symbol node, if the symbol node ID (its access chain string) matches
+// with the given precise object, this node should be 'precise'.
+void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node)
+{
+    // A symbol node should always be an object node, and should have been added
+    // to the map from object nodes to their access chain strings.
+    assert(accesschain_mapping_.count(node));
+    if (accesschain_mapping_.at(node) == *precise_object_) {
+        node->getWritableType().getQualifier().noContraction = true;
+    }
+}
+
+//
+// A traverser that only traverses the right side of binary assignment nodes
+// and the operand node of unary assignment nodes.
+//
+// 1) Marks arithmetic operations as 'NoContraction'.
+//
+// 2) Find the object which should be marked as 'precise' in the right and
+//    update the 'precise' object work list.
+//
+class TNoContractionPropagator : public glslang::TIntermTraverser {
+public:
+    TNoContractionPropagator(ObjectAccesschainSet* precise_objects,
+                             const AccessChainMapping& accesschain_mapping)
+        : TIntermTraverser(true, false, false),
+          precise_objects_(*precise_objects), added_precise_object_ids_(),
+          remained_accesschain_(), accesschain_mapping_(accesschain_mapping) {}
+
+    // Propagates 'precise' in the right nodes of a given assignment node with
+    // access chain record from the assignee node to a 'precise' object it
+    // contains.
+    void
+    propagateNoContractionInOneExpression(glslang::TIntermTyped* defining_node,
+                                          const ObjectAccessChain& assignee_remained_accesschain)
+    {
+        remained_accesschain_ = assignee_remained_accesschain;
+        if (glslang::TIntermBinary* BN = defining_node->getAsBinaryNode()) {
+            assert(isAssignOperation(BN->getOp()));
+            BN->getRight()->traverse(this);
+            if (isArithmeticOperation(BN->getOp())) {
+                BN->getWritableType().getQualifier().noContraction = true;
+            }
+        } else if (glslang::TIntermUnary* UN = defining_node->getAsUnaryNode()) {
+            assert(isAssignOperation(UN->getOp()));
+            UN->getOperand()->traverse(this);
+            if (isArithmeticOperation(UN->getOp())) {
+                UN->getWritableType().getQualifier().noContraction = true;
+            }
+        }
+    }
+
+    // Propagates 'precise' in a given precise return node.
+    void propagateNoContractionInReturnNode(glslang::TIntermBranch* return_node)
+    {
+        remained_accesschain_ = "";
+        assert(return_node->getFlowOp() == glslang::EOpReturn && return_node->getExpression());
+        return_node->getExpression()->traverse(this);
+    }
+
+protected:
+    TNoContractionPropagator& operator=(const TNoContractionPropagator&);
+
+    // Visits an aggregate node. The node can be a initializer list, in which
+    // case we need to find the 'precise' or 'precise' containing object node
+    // with the access chain record. In other cases, just need to traverse all
+    // the children nodes.
+    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) override
+    {
+        if (!remained_accesschain_.empty() && node->getOp() == glslang::EOpConstructStruct) {
+            // This is a struct initializer node, and the remained
+            // access chain is not empty, we need to refer to the
+            // assignee_remained_access_chain_ to find the nested
+            // 'precise' object. And we don't need to visit other nodes in this
+            // aggregate node.
+
+            // Gets the struct dereference index that leads to 'precise' object.
+            ObjectAccessChain precise_accesschain_index_str =
+                getFrontElement(remained_accesschain_);
+            unsigned precise_accesschain_index = (unsigned)strtoul(precise_accesschain_index_str.c_str(), nullptr, 10);
+            // Gets the node pointed by the access chain index extracted before.
+            glslang::TIntermTyped* potential_precise_node =
+                node->getSequence()[precise_accesschain_index]->getAsTyped();
+            assert(potential_precise_node);
+            // Pop the front access chain index from the path, and visit the nested node.
+            {
+                ObjectAccessChain next_level_accesschain =
+                    subAccessChainFromSecondElement(remained_accesschain_);
+                StateSettingGuard<ObjectAccessChain> setup_remained_accesschain_for_next_level(
+                    &remained_accesschain_, next_level_accesschain);
+                potential_precise_node->traverse(this);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    // Visits a binary node. A binary node can be an object node, e.g. a dereference node.
+    // As only the top object nodes in the right side of an assignment needs to be visited
+    // and added to 'precise' work list, this traverser won't visit the children nodes of
+    // an object node. If the binary node does not represent an object node, it should
+    // go on to traverse its children nodes and if it is an arithmetic operation node, this
+    // operation should be marked as 'noContraction'.
+    bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override
+    {
+        if (isDereferenceOperation(node->getOp())) {
+            // This binary node is an object node. Need to update the precise
+            // object set with the access chain of this node + remained
+            // access chain .
+            ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
+            if (remained_accesschain_.empty()) {
+                node->getWritableType().getQualifier().noContraction = true;
+            } else {
+                new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
+            }
+            // Cache the access chain as added precise object, so we won't add the
+            // same object to the work list again.
+            if (!added_precise_object_ids_.count(new_precise_accesschain)) {
+                precise_objects_.insert(new_precise_accesschain);
+                added_precise_object_ids_.insert(new_precise_accesschain);
+            }
+            // Only the upper-most object nodes should be visited, so do not
+            // visit children of this object node.
+            return false;
+        }
+        // If this is an arithmetic operation, marks this node as 'noContraction'.
+        if (isArithmeticOperation(node->getOp()) && node->getBasicType() != glslang::EbtInt) {
+            node->getWritableType().getQualifier().noContraction = true;
+        }
+        // As this node is not an object node, need to traverse the children nodes.
+        return true;
+    }
+
+    // Visits a unary node. A unary node can not be an object node. If the operation
+    // is an arithmetic operation, need to mark this node as 'noContraction'.
+    bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) override
+    {
+        // If this is an arithmetic operation, marks this with 'noContraction'
+        if (isArithmeticOperation(node->getOp())) {
+            node->getWritableType().getQualifier().noContraction = true;
+        }
+        return true;
+    }
+
+    // Visits a symbol node. A symbol node is always an object node. So we
+    // should always be able to find its in our collected mapping from object
+    // nodes to access chains.  As an object node, a symbol node can be either
+    // 'precise' or containing 'precise' objects according to unused
+    // access chain information we have when we visit this node.
+    void visitSymbol(glslang::TIntermSymbol* node) override
+    {
+        // Symbol nodes are object nodes and should always have an
+        // access chain collected before matches with it.
+        assert(accesschain_mapping_.count(node));
+        ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
+        // If the unused access chain is empty, this symbol node should be
+        // marked as 'precise'.  Otherwise, the unused access chain should be
+        // appended to the symbol ID to build a new access chain which points to
+        // the nested 'precise' object in this symbol object.
+        if (remained_accesschain_.empty()) {
+            node->getWritableType().getQualifier().noContraction = true;
+        } else {
+            new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
+        }
+        // Add the new 'precise' access chain to the work list and make sure we
+        // don't visit it again.
+        if (!added_precise_object_ids_.count(new_precise_accesschain)) {
+            precise_objects_.insert(new_precise_accesschain);
+            added_precise_object_ids_.insert(new_precise_accesschain);
+        }
+    }
+
+    // A set of precise objects, represented as access chains.
+    ObjectAccesschainSet& precise_objects_;
+    // Visited symbol nodes, should not revisit these nodes.
+    ObjectAccesschainSet added_precise_object_ids_;
+    // The left node of an assignment operation might be an parent of 'precise' objects.
+    // This means the left node might not be an 'precise' object node, but it may contains
+    // 'precise' qualifier which should be propagated to the corresponding child node in
+    // the right. So we need the path from the left node to its nested 'precise' node to
+    // tell us how to find the corresponding 'precise' node in the right.
+    ObjectAccessChain remained_accesschain_;
+    // A map from node pointers to their access chains.
+    const AccessChainMapping& accesschain_mapping_;
+};
+}
+
+namespace glslang {
+
+void PropagateNoContraction(const glslang::TIntermediate& intermediate)
+{
+    // First, traverses the AST, records symbols with their defining operations
+    // and collects the initial set of precise symbols (symbol nodes that marked
+    // as 'noContraction') and precise return nodes.
+    auto mappings_and_precise_objects =
+        getSymbolToDefinitionMappingAndPreciseSymbolIDs(intermediate);
+
+    // The mapping of symbol node IDs to their defining nodes. This enables us
+    // to get the defining node directly from a given symbol ID without
+    // traversing the tree again.
+    NodeMapping& symbol_definition_mapping = std::get<0>(mappings_and_precise_objects);
+
+    // The mapping of object nodes to their access chains recorded.
+    AccessChainMapping& accesschain_mapping = std::get<1>(mappings_and_precise_objects);
+
+    // The initial set of 'precise' objects which are represented as the
+    // access chain toward them.
+    ObjectAccesschainSet& precise_object_accesschains = std::get<2>(mappings_and_precise_objects);
+
+    // The set of 'precise' return nodes.
+    ReturnBranchNodeSet& precise_return_nodes = std::get<3>(mappings_and_precise_objects);
+
+    // Second, uses the initial set of precise objects as a work list, pops an
+    // access chain, extract the symbol ID from it. Then:
+    //  1) Check the assignee object, see if it is 'precise' object node or
+    //  contains 'precise' object. Obtain the incremental access chain from the
+    //  assignee node to its nested 'precise' node (if any).
+    //  2) If the assignee object node is 'precise' or it contains 'precise'
+    //  objects, traverses the right side of the assignment operation
+    //  expression to mark arithmetic operations as 'noContration' and update
+    //  'precise' access chain work list with new found object nodes.
+    // Repeat above steps until the work list is empty.
+    TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping);
+    TNoContractionPropagator propagator(&precise_object_accesschains, accesschain_mapping);
+
+    // We have two initial precise work lists to handle:
+    //  1) precise return nodes
+    //  2) precise object access chains
+    // We should process the precise return nodes first and the involved
+    // objects in the return expression should be added to the precise object
+    // access chain set.
+    while (!precise_return_nodes.empty()) {
+        glslang::TIntermBranch* precise_return_node = *precise_return_nodes.begin();
+        propagator.propagateNoContractionInReturnNode(precise_return_node);
+        precise_return_nodes.erase(precise_return_node);
+    }
+
+    while (!precise_object_accesschains.empty()) {
+        // Get the access chain of a precise object from the work list.
+        ObjectAccessChain precise_object_accesschain = *precise_object_accesschains.begin();
+        // Get the symbol id from the access chain.
+        ObjectAccessChain symbol_id = getFrontElement(precise_object_accesschain);
+        // Get all the defining nodes of that symbol ID.
+        std::pair<NodeMapping::iterator, NodeMapping::iterator> range =
+            symbol_definition_mapping.equal_range(symbol_id);
+        // Visits all the assignment nodes of that symbol ID and
+        //  1) Check if the assignee node is 'precise' or contains 'precise'
+        //  objects.
+        //  2) Propagate the 'precise' to the top layer object nodes
+        //  in the right side of the assignment operation, update the 'precise'
+        //  work list with new access chains representing the new 'precise'
+        //  objects, and mark arithmetic operations as 'noContraction'.
+        for (NodeMapping::iterator defining_node_iter = range.first;
+             defining_node_iter != range.second; defining_node_iter++) {
+            TIntermOperator* defining_node = defining_node_iter->second;
+            // Check the assignee node.
+            auto checker_result = checker.getPrecisenessAndRemainedAccessChain(
+                defining_node, precise_object_accesschain);
+            bool& contain_precise = std::get<0>(checker_result);
+            ObjectAccessChain& remained_accesschain = std::get<1>(checker_result);
+            // If the assignee node is 'precise' or contains 'precise', propagate the
+            // 'precise' to the right. Otherwise just skip this assignment node.
+            if (contain_precise) {
+                propagator.propagateNoContractionInOneExpression(defining_node,
+                                                                 remained_accesschain);
+            }
+        }
+        // Remove the last processed 'precise' object from the work list.
+        precise_object_accesschains.erase(precise_object_accesschain);
+    }
+}
+};

+ 53 - 0
src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h

@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of Google Inc. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Visit the nodes in the glslang intermediate tree representation to
+// propagate 'noContraction' qualifier.
+//
+
+#include "../Include/intermediate.h"
+
+namespace glslang {
+
+// Propagates the 'precise' qualifier for objects (objects marked with
+// 'noContraction' qualifier) from the shader source specified 'precise'
+// variables to all the involved objects, and add 'noContraction' qualifier for
+// the involved arithmetic operations.
+// Note that the same qualifier: 'noContraction' is used in both object nodes
+// and arithmetic operation nodes, but has different meaning. For object nodes,
+// 'noContraction' means the object is 'precise'; and for arithmetic operation
+// nodes, it means the operation should not be contracted.
+void PropagateNoContraction(const glslang::TIntermediate& intermediate);
+};

+ 745 - 0
src/libraries/glslang/glslang/MachineIndependent/reflection.cpp

@@ -0,0 +1,745 @@
+//
+// Copyright (C) 2013-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "reflection.h"
+#include "LiveTraverser.h"
+#include "localintermediate.h"
+
+#include "gl_types.h"
+
+//
+// Grow the reflection database through a friend traverser class of TReflection and a
+// collection of functions to do a liveness traversal that note what uniforms are used
+// in semantically non-dead code.
+//
+// Can be used multiple times, once per stage, to grow a program reflection.
+//
+// High-level algorithm for one stage:
+//
+// 1. Put the entry point on the list of live functions.
+//
+// 2. Traverse any live function, while skipping if-tests with a compile-time constant
+//    condition of false, and while adding any encountered function calls to the live
+//    function list.
+//
+//    Repeat until the live function list is empty.
+//
+// 3. Add any encountered uniform variables and blocks to the reflection database.
+//
+// Can be attempted with a failed link, but will return false if recursion had been detected, or
+// there wasn't exactly one entry point.
+//
+
+namespace glslang {
+
+//
+// The traverser: mostly pass through, except
+//  - processing binary nodes to see if they are dereferences of an aggregates to track
+//  - processing symbol nodes to see if they are non-aggregate objects to track
+//
+// This ignores semantically dead code by using TLiveTraverser.
+//
+// This is in the glslang namespace directly so it can be a friend of TReflection.
+//
+
+class TReflectionTraverser : public TLiveTraverser {
+public:
+    TReflectionTraverser(const TIntermediate& i, TReflection& r) :
+         TLiveTraverser(i), reflection(r) { }
+
+    virtual bool visitBinary(TVisit, TIntermBinary* node);
+    virtual void visitSymbol(TIntermSymbol* base);
+
+    // Add a simple reference to a uniform variable to the uniform database, no dereference involved.
+    // However, no dereference doesn't mean simple... it could be a complex aggregate.
+    void addUniform(const TIntermSymbol& base)
+    {
+        if (processedDerefs.find(&base) == processedDerefs.end()) {
+            processedDerefs.insert(&base);
+
+            // Use a degenerate (empty) set of dereferences to immediately put as at the end of
+            // the dereference change expected by blowUpActiveAggregate.
+            TList<TIntermBinary*> derefs;
+            blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0);
+        }
+    }
+
+    void addAttribute(const TIntermSymbol& base)
+    {
+        if (processedDerefs.find(&base) == processedDerefs.end()) {
+            processedDerefs.insert(&base);
+
+            const TString &name = base.getName();
+            const TType &type = base.getType();
+
+            TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
+            if (it == reflection.nameToIndex.end()) {
+                reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
+                reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0));
+            }
+        }
+    }
+
+    // Lookup or calculate the offset of a block member, using the recursively
+    // defined block offset rules.
+    int getOffset(const TType& type, int index)
+    {
+        const TTypeList& memberList = *type.getStruct();
+
+        // Don't calculate offset if one is present, it could be user supplied
+        // and different than what would be calculated.  That is, this is faster,
+        // but not just an optimization.
+        if (memberList[index].type->getQualifier().hasOffset())
+            return memberList[index].type->getQualifier().layoutOffset;
+
+        int memberSize;
+        int dummyStride;
+        int offset = 0;
+        for (int m = 0; m <= index; ++m) {
+            // modify just the children's view of matrix layout, if there is one for this member
+            TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
+            int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, type.getQualifier().layoutPacking == ElpStd140,
+                                                                subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : type.getQualifier().layoutMatrix == ElmRowMajor);
+            RoundToPow2(offset, memberAlignment);
+            if (m < index)
+                offset += memberSize;
+        }
+
+        return offset;
+    }
+
+    // Calculate the block data size.
+    // Block arrayness is not taken into account, each element is backed by a separate buffer.
+    int getBlockSize(const TType& blockType)
+    {
+        const TTypeList& memberList = *blockType.getStruct();
+        int lastIndex = (int)memberList.size() - 1;
+        int lastOffset = getOffset(blockType, lastIndex);
+
+        int lastMemberSize;
+        int dummyStride;
+        intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, blockType.getQualifier().layoutPacking == ElpStd140,
+                                      blockType.getQualifier().layoutMatrix == ElmRowMajor);
+
+        return lastOffset + lastMemberSize;
+    }
+
+    // Traverse the provided deref chain, including the base, and
+    // - build a full reflection-granularity name, array size, etc. entry out of it, if it goes down to that granularity
+    // - recursively expand any variable array index in the middle of that traversal
+    // - recursively expand what's left at the end if the deref chain did not reach down to reflection granularity
+    //
+    // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
+    // A value of 0 for arraySize will mean to use the full array's size.
+    void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
+                               TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
+    {
+        // process the part of the derefence chain that was explicit in the shader
+        TString name = baseName;
+        const TType* terminalType = &baseType;
+        for (; deref != derefs.end(); ++deref) {
+            TIntermBinary* visitNode = *deref;
+            terminalType = &visitNode->getType();
+            int index;
+            switch (visitNode->getOp()) {
+            case EOpIndexIndirect:
+                // Visit all the indices of this array, and for each one add on the remaining dereferencing
+                for (int i = 0; i < visitNode->getLeft()->getType().getOuterArraySize(); ++i) {
+                    TString newBaseName = name;
+                    if (baseType.getBasicType() != EbtBlock)
+                        newBaseName.append(TString("[") + String(i) + "]");
+                    TList<TIntermBinary*>::const_iterator nextDeref = deref;
+                    ++nextDeref;
+                    TType derefType(*terminalType, 0);
+                    blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize);
+                }
+
+                // it was all completed in the recursive calls above
+                return;
+            case EOpIndexDirect:
+                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+                if (baseType.getBasicType() != EbtBlock)
+                    name.append(TString("[") + String(index) + "]");
+                break;
+            case EOpIndexDirectStruct:
+                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+                if (offset >= 0)
+                    offset += getOffset(visitNode->getLeft()->getType(), index);
+                if (name.size() > 0)
+                    name.append(".");
+                name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
+                break;
+            default:
+                break;
+            }
+        }
+
+        // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
+        if (! isReflectionGranularity(*terminalType)) {
+            if (terminalType->isArray()) {
+                // Visit all the indices of this array, and for each one,
+                // fully explode the remaining aggregate to dereference
+                for (int i = 0; i < terminalType->getOuterArraySize(); ++i) {
+                    TString newBaseName = name;
+                    newBaseName.append(TString("[") + String(i) + "]");
+                    TType derefType(*terminalType, 0);
+                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
+                }
+            } else {
+                // Visit all members of this aggregate, and for each one,
+                // fully explode the remaining aggregate to dereference
+                const TTypeList& typeList = *terminalType->getStruct();
+                for (int i = 0; i < (int)typeList.size(); ++i) {
+                    TString newBaseName = name;
+                    newBaseName.append(TString(".") + typeList[i].type->getFieldName());
+                    TType derefType(*terminalType, i);
+                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
+                }
+            }
+
+            // it was all completed in the recursive calls above
+            return;
+        }
+
+        // Finally, add a full string to the reflection database, and update the array size if necessary.
+        // If the derefenced entity to record is an array, compute the size and update the maximum size.
+
+        // there might not be a final array dereference, it could have been copied as an array object
+        if (arraySize == 0)
+            arraySize = mapToGlArraySize(*terminalType);
+
+        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
+        if (it == reflection.nameToIndex.end()) {
+            reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
+            reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset, mapToGlType(*terminalType),
+                                                                  arraySize, blockIndex));
+        } else if (arraySize > 1) {
+            int& reflectedArraySize = reflection.indexToUniform[it->second].size;
+            reflectedArraySize = std::max(arraySize, reflectedArraySize);
+        }
+    }
+
+    // Add a uniform dereference where blocks/struct/arrays are involved in the access.
+    // Handles the situation where the left node is at the correct or too coarse a
+    // granularity for reflection.  (That is, further dereferences up the tree will be
+    // skipped.) Earlier dereferences, down the tree, will be handled
+    // at the same time, and logged to prevent reprocessing as the tree is traversed.
+    //
+    // Note: Other things like the following must be caught elsewhere:
+    //  - a simple non-array, non-struct variable (no dereference even conceivable)
+    //  - an aggregrate consumed en masse, without a dereference
+    //
+    // So, this code is for cases like
+    //   - a struct/block dereferencing a member (whether the member is array or not)
+    //   - an array of struct
+    //   - structs/arrays containing the above
+    //
+    void addDereferencedUniform(TIntermBinary* topNode)
+    {
+        // See if too fine-grained to process (wait to get further down the tree)
+        const TType& leftType = topNode->getLeft()->getType();
+        if ((leftType.isVector() || leftType.isMatrix()) && ! leftType.isArray())
+            return;
+
+        // We have an array or structure or block dereference, see if it's a uniform
+        // based dereference (if not, skip it).
+        TIntermSymbol* base = findBase(topNode);
+        if (! base || ! base->getQualifier().isUniformOrBuffer())
+            return;
+
+        // See if we've already processed this (e.g., in the middle of something
+        // we did earlier), and if so skip it
+        if (processedDerefs.find(topNode) != processedDerefs.end())
+            return;
+
+        // Process this uniform dereference
+
+        int offset = -1;
+        int blockIndex = -1;
+        bool anonymous = false;
+
+        // See if we need to record the block itself
+        bool block = base->getBasicType() == EbtBlock;
+        if (block) {
+            offset = 0;
+            anonymous = IsAnonymous(base->getName());
+
+            const TString& blockName = base->getType().getTypeName();
+
+            if (base->getType().isArray()) {
+                TType derefType(base->getType(), 0);
+
+                assert(! anonymous);
+                for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
+                    blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
+                                              getBlockSize(base->getType()));
+            } else
+                blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
+        }
+
+        // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
+        // If the topNode is a reflection-granularity-array dereference, don't include that last dereference.
+        TList<TIntermBinary*> derefs;
+        for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
+            if (isReflectionGranularity(visitNode->getLeft()->getType()))
+                continue;
+
+            derefs.push_front(visitNode);
+            processedDerefs.insert(visitNode);
+        }
+        processedDerefs.insert(base);
+
+        // See if we have a specific array size to stick to while enumerating the explosion of the aggregate
+        int arraySize = 0;
+        if (isReflectionGranularity(topNode->getLeft()->getType()) && topNode->getLeft()->isArray()) {
+            if (topNode->getOp() == EOpIndexDirect)
+                arraySize = topNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst() + 1;
+        }
+
+        // Put the dereference chain together, forward
+        TString baseName;
+        if (! anonymous) {
+            if (block)
+                baseName = base->getType().getTypeName();
+            else
+                baseName = base->getName();
+        }
+        blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
+    }
+
+    int addBlockName(const TString& name, const TType& type, int size)
+    {
+        int blockIndex;
+        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
+        if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
+            blockIndex = (int)reflection.indexToUniformBlock.size();
+            reflection.nameToIndex[name] = blockIndex;
+            reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1));
+        } else
+            blockIndex = it->second;
+
+        return blockIndex;
+    }
+
+    // Are we at a level in a dereference chain at which individual active uniform queries are made?
+    bool isReflectionGranularity(const TType& type)
+    {
+        return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct;
+    }
+
+    // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
+    // Return 0 if the topology does not fit this situation.
+    TIntermSymbol* findBase(const TIntermBinary* node)
+    {
+        TIntermSymbol *base = node->getLeft()->getAsSymbolNode();
+        if (base)
+            return base;
+        TIntermBinary* left = node->getLeft()->getAsBinaryNode();
+        if (! left)
+            return nullptr;
+
+        return findBase(left);
+    }
+
+    //
+    // Translate a glslang sampler type into the GL API #define number.
+    //
+    int mapSamplerToGlType(TSampler sampler)
+    {
+        if (! sampler.image) {
+            // a sampler...
+            switch (sampler.type) {
+            case EbtFloat:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    switch ((int)sampler.shadow) {
+                    case false: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
+                    case true:  return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW;
+                    }
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:
+                        switch ((int)sampler.shadow) {
+                        case false: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
+                        case true:  return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW;
+                        }
+                    case true:      return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_SAMPLER_3D;
+                case EsdCube:
+                    switch ((int)sampler.shadow) {
+                    case false: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
+                    case true:  return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW;
+                    }
+                case EsdRect:
+                    return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
+                case EsdBuffer:
+                    return GL_SAMPLER_BUFFER;
+                }
+            case EbtInt:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D;
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:  return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
+                    case true:   return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_INT_SAMPLER_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_INT_SAMPLER_3D;
+                case EsdCube:
+                    return sampler.arrayed ? GL_INT_SAMPLER_CUBE_MAP_ARRAY : GL_INT_SAMPLER_CUBE;
+                case EsdRect:
+                    return GL_INT_SAMPLER_2D_RECT;
+                case EsdBuffer:
+                    return GL_INT_SAMPLER_BUFFER;
+                }
+            case EbtUint:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D;
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:  return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
+                    case true:   return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_UNSIGNED_INT_SAMPLER_3D;
+                case EsdCube:
+                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_SAMPLER_CUBE;
+                case EsdRect:
+                    return GL_UNSIGNED_INT_SAMPLER_2D_RECT;
+                case EsdBuffer:
+                    return GL_UNSIGNED_INT_SAMPLER_BUFFER;
+                }
+            default:
+                return 0;
+            }
+        } else {
+            // an image...
+            switch (sampler.type) {
+            case EbtFloat:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D;
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:     return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D;
+                    case true:      return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_IMAGE_3D;
+                case EsdCube:
+                    return sampler.arrayed ? GL_IMAGE_CUBE_MAP_ARRAY : GL_IMAGE_CUBE;
+                case EsdRect:
+                    return GL_IMAGE_2D_RECT;
+                case EsdBuffer:
+                    return GL_IMAGE_BUFFER;
+                }
+            case EbtInt:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D;
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:  return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D;
+                    case true:   return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_INT_IMAGE_3D;
+                case EsdCube:
+                    return sampler.arrayed ? GL_INT_IMAGE_CUBE_MAP_ARRAY : GL_INT_IMAGE_CUBE;
+                case EsdRect:
+                    return GL_INT_IMAGE_2D_RECT;
+                case EsdBuffer:
+                    return GL_INT_IMAGE_BUFFER;
+                }
+            case EbtUint:
+                switch ((int)sampler.dim) {
+                case Esd1D:
+                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D;
+                case Esd2D:
+                    switch ((int)sampler.ms) {
+                    case false:  return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
+                    case true:   return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
+                    }
+                case Esd3D:
+                    return GL_UNSIGNED_INT_IMAGE_3D;
+                case EsdCube:
+                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_IMAGE_CUBE;
+                case EsdRect:
+                    return GL_UNSIGNED_INT_IMAGE_2D_RECT;
+                case EsdBuffer:
+                    return GL_UNSIGNED_INT_IMAGE_BUFFER;
+                }
+            default:
+                return 0;
+            }
+        }
+    }
+
+    //
+    // Translate a glslang type into the GL API #define number.
+    // Ignores arrayness.
+    //
+    int mapToGlType(const TType& type)
+    {
+        switch (type.getBasicType()) {
+        case EbtSampler:
+            return mapSamplerToGlType(type.getSampler());
+        case EbtStruct:
+        case EbtBlock:
+        case EbtVoid:
+            return 0;
+        default:
+            break;
+        }
+
+        if (type.isVector()) {
+            int offset = type.getVectorSize() - 2;
+            switch (type.getBasicType()) {
+            case EbtFloat:      return GL_FLOAT_VEC2                  + offset;
+            case EbtDouble:     return GL_DOUBLE_VEC2                 + offset;
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:    return GL_FLOAT16_VEC2_NV             + offset;
+#endif
+            case EbtInt:        return GL_INT_VEC2                    + offset;
+            case EbtUint:       return GL_UNSIGNED_INT_VEC2           + offset;
+            case EbtInt64:      return GL_INT64_ARB                   + offset;
+            case EbtUint64:     return GL_UNSIGNED_INT64_ARB          + offset;
+            case EbtBool:       return GL_BOOL_VEC2                   + offset;
+            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset;
+            default:            return 0;
+            }
+        }
+        if (type.isMatrix()) {
+            switch (type.getBasicType()) {
+            case EbtFloat:
+                switch (type.getMatrixCols()) {
+                case 2:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT_MAT2;
+                    case 3:    return GL_FLOAT_MAT2x3;
+                    case 4:    return GL_FLOAT_MAT2x4;
+                    default:   return 0;
+                    }
+                case 3:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT_MAT3x2;
+                    case 3:    return GL_FLOAT_MAT3;
+                    case 4:    return GL_FLOAT_MAT3x4;
+                    default:   return 0;
+                    }
+                case 4:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT_MAT4x2;
+                    case 3:    return GL_FLOAT_MAT4x3;
+                    case 4:    return GL_FLOAT_MAT4;
+                    default:   return 0;
+                    }
+                }
+            case EbtDouble:
+                switch (type.getMatrixCols()) {
+                case 2:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_DOUBLE_MAT2;
+                    case 3:    return GL_DOUBLE_MAT2x3;
+                    case 4:    return GL_DOUBLE_MAT2x4;
+                    default:   return 0;
+                    }
+                case 3:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_DOUBLE_MAT3x2;
+                    case 3:    return GL_DOUBLE_MAT3;
+                    case 4:    return GL_DOUBLE_MAT3x4;
+                    default:   return 0;
+                    }
+                case 4:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_DOUBLE_MAT4x2;
+                    case 3:    return GL_DOUBLE_MAT4x3;
+                    case 4:    return GL_DOUBLE_MAT4;
+                    default:   return 0;
+                    }
+                }
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+                switch (type.getMatrixCols()) {
+                case 2:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT16_MAT2_AMD;
+                    case 3:    return GL_FLOAT16_MAT2x3_AMD;
+                    case 4:    return GL_FLOAT16_MAT2x4_AMD;
+                    default:   return 0;
+                    }
+                case 3:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT16_MAT3x2_AMD;
+                    case 3:    return GL_FLOAT16_MAT3_AMD;
+                    case 4:    return GL_FLOAT16_MAT3x4_AMD;
+                    default:   return 0;
+                    }
+                case 4:
+                    switch (type.getMatrixRows()) {
+                    case 2:    return GL_FLOAT16_MAT4x2_AMD;
+                    case 3:    return GL_FLOAT16_MAT4x3_AMD;
+                    case 4:    return GL_FLOAT16_MAT4_AMD;
+                    default:   return 0;
+                    }
+                }
+#endif
+            default:
+                return 0;
+            }
+        }
+        if (type.getVectorSize() == 1) {
+            switch (type.getBasicType()) {
+            case EbtFloat:      return GL_FLOAT;
+            case EbtDouble:     return GL_DOUBLE;
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:    return GL_FLOAT16_NV;
+#endif
+            case EbtInt:        return GL_INT;
+            case EbtUint:       return GL_UNSIGNED_INT;
+            case EbtInt64:      return GL_INT64_ARB;
+            case EbtUint64:     return GL_UNSIGNED_INT64_ARB;
+            case EbtBool:       return GL_BOOL;
+            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER;
+            default:            return 0;
+            }
+        }
+
+        return 0;
+    }
+
+    int mapToGlArraySize(const TType& type)
+    {
+        return type.isArray() ? type.getOuterArraySize() : 1;
+    }
+
+    TReflection& reflection;
+    std::set<const TIntermNode*> processedDerefs;
+
+protected:
+    TReflectionTraverser(TReflectionTraverser&);
+    TReflectionTraverser& operator=(TReflectionTraverser&);
+};
+
+//
+// Implement the traversal functions of interest.
+//
+
+// To catch dereferenced aggregates that must be reflected.
+// This catches them at the highest level possible in the tree.
+bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
+{
+    switch (node->getOp()) {
+    case EOpIndexDirect:
+    case EOpIndexIndirect:
+    case EOpIndexDirectStruct:
+        addDereferencedUniform(node);
+        break;
+    default:
+        break;
+    }
+
+    // still need to visit everything below, which could contain sub-expressions
+    // containing different uniforms
+    return true;
+}
+
+// To reflect non-dereferenced objects.
+void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
+{
+    if (base->getQualifier().storage == EvqUniform)
+        addUniform(*base);
+
+    if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
+        addAttribute(*base);
+}
+
+//
+// Implement TReflection methods.
+//
+
+// Merge live symbols from 'intermediate' into the existing reflection database.
+//
+// Returns false if the input is too malformed to do this.
+bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
+{
+    if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
+        return false;
+
+    TReflectionTraverser it(intermediate, *this);
+
+    // put the entry point on the list of functions to process
+    it.pushFunction(intermediate.getEntryPointMangledName().c_str());
+
+    // process all the functions
+    while (! it.functions.empty()) {
+        TIntermNode* function = it.functions.back();
+        it.functions.pop_back();
+        function->traverse(&it);
+    }
+
+    return true;
+}
+
+void TReflection::dump()
+{
+    printf("Uniform reflection:\n");
+    for (size_t i = 0; i < indexToUniform.size(); ++i)
+        indexToUniform[i].dump();
+    printf("\n");
+
+    printf("Uniform block reflection:\n");
+    for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
+        indexToUniformBlock[i].dump();
+    printf("\n");
+
+    printf("Vertex attribute reflection:\n");
+    for (size_t i = 0; i < indexToAttribute.size(); ++i)
+        indexToAttribute[i].dump();
+    printf("\n");
+
+    // printf("Live names\n");
+    // for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
+    //    printf("%s: %d\n", it->first.c_str(), it->second);
+    // printf("\n");
+}
+
+} // end namespace glslang

+ 156 - 0
src/libraries/glslang/glslang/MachineIndependent/reflection.h

@@ -0,0 +1,156 @@
+//
+// Copyright (C) 2013-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _REFLECTION_INCLUDED
+#define _REFLECTION_INCLUDED
+
+#include "../Public/ShaderLang.h"
+#include "../Include/Types.h"
+
+#include <list>
+#include <set>
+
+//
+// A reflection database and its interface, consistent with the OpenGL API reflection queries.
+//
+
+namespace glslang {
+
+class TIntermediate;
+class TIntermAggregate;
+class TReflectionTraverser;
+
+// Data needed for just a single object at the granularity exchanged by the reflection API
+class TObjectReflection {
+public:
+    TObjectReflection(const TString& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex) :
+        name(pName), offset(pOffset),
+        glDefineType(pGLDefineType), size(pSize), index(pIndex), type(pType.clone()) { }
+
+    void dump() const {
+        printf("%s: offset %d, type %x, size %d, index %d, binding %d\n",
+               name.c_str(), offset, glDefineType, size, index, getBinding() );
+    }
+
+    const TType* const getType() const { return type; }
+
+    TString name;
+    int offset;
+    int glDefineType;
+    int size;         // data size in bytes for a block, array size for a (non-block) object that's an array
+    int index;
+
+    static TObjectReflection badReflection() { return TObjectReflection(); }
+
+protected:
+    int getBinding() const {
+        if (type == nullptr || type->getQualifier().layoutBinding == TQualifier::layoutBindingEnd)
+            return -1;
+        return type->getQualifier().layoutBinding;
+    }
+
+    TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
+
+    const TType* type;
+};
+
+// The full reflection database
+class TReflection {
+public:
+    TReflection() : badReflection(TObjectReflection::badReflection()) { }
+    virtual ~TReflection() {}
+
+    // grow the reflection stage by stage
+    bool addStage(EShLanguage, const TIntermediate&);
+
+    // for mapping a uniform index to a uniform object's description
+    int getNumUniforms() { return (int)indexToUniform.size(); }
+    const TObjectReflection& getUniform(int i) const
+    {
+        if (i >= 0 && i < (int)indexToUniform.size())
+            return indexToUniform[i];
+        else
+            return badReflection;
+    }
+
+    // for mapping a block index to the block's description
+    int getNumUniformBlocks() const { return (int)indexToUniformBlock.size(); }
+    const TObjectReflection& getUniformBlock(int i) const
+    {
+        if (i >= 0 && i < (int)indexToUniformBlock.size())
+            return indexToUniformBlock[i];
+        else
+            return badReflection;
+    }
+
+    // for mapping an attribute index to the attribute's description
+    int getNumAttributes() { return (int)indexToAttribute.size(); }
+    const TObjectReflection& getAttribute(int i) const
+    {
+        if (i >= 0 && i < (int)indexToAttribute.size())
+            return indexToAttribute[i];
+        else
+            return badReflection;
+    }
+
+    // for mapping any name to its index (block names, uniform names and attribute names)
+    int getIndex(const char* name) const
+    {
+        TNameToIndex::const_iterator it = nameToIndex.find(name);
+        if (it == nameToIndex.end())
+            return -1;
+        else
+            return it->second;
+    }
+
+    void dump();
+
+protected:
+    friend class glslang::TReflectionTraverser;
+
+    // Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
+    typedef std::map<TString, int> TNameToIndex;
+    typedef std::vector<TObjectReflection> TMapIndexToReflection;
+
+    TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
+    TNameToIndex nameToIndex;        // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
+    TMapIndexToReflection indexToUniform;
+    TMapIndexToReflection indexToUniformBlock;
+    TMapIndexToReflection indexToAttribute;
+};
+
+} // end namespace glslang
+
+#endif // _REFLECTION_INCLUDED

+ 205 - 0
src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp

@@ -0,0 +1,205 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// This file contains the Linux-specific functions
+//
+#include "../osinclude.h"
+#include "../../../OGLCompilersDLL/InitializeDll.h"
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+namespace glslang {
+
+//
+// Thread cleanup
+//
+
+//
+// Wrapper for Linux call to DetachThread.  This is required as pthread_cleanup_push() expects
+// the cleanup routine to return void.
+//
+static void DetachThreadLinux(void *)
+{
+    DetachThread();
+}
+
+//
+// Registers cleanup handler, sets cancel type and state, and executes the thread specific
+// cleanup handler.  This function will be called in the Standalone.cpp for regression
+// testing.  When OpenGL applications are run with the driver code, Linux OS does the
+// thread cleanup.
+//
+void OS_CleanupThreadData(void)
+{
+#ifdef __ANDROID__
+    DetachThreadLinux(NULL);
+#else
+    int old_cancel_state, old_cancel_type;
+    void *cleanupArg = NULL;
+
+    //
+    // Set thread cancel state and push cleanup handler.
+    //
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
+    pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
+
+    //
+    // Put the thread in deferred cancellation mode.
+    //
+    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
+
+    //
+    // Pop cleanup handler and execute it prior to unregistering the cleanup handler.
+    //
+    pthread_cleanup_pop(1);
+
+    //
+    // Restore the thread's previous cancellation mode.
+    //
+    pthread_setcanceltype(old_cancel_state, NULL);
+#endif
+}
+
+//
+// Thread Local Storage Operations
+//
+inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key)
+{
+    return (OS_TLSIndex)((uintptr_t)key + 1);
+}
+
+inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex)
+{
+    return (pthread_key_t)((uintptr_t)nIndex - 1);
+}
+
+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 OS_INVALID_TLS_INDEX;
+    }
+    else
+        return PthreadKeyToTLSIndex(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(TLSIndexToPthreadKey(nIndex), lpvValue) == 0)
+        return true;
+    else
+        return false;
+}
+
+void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+    //
+    // This function should return 0 if nIndex is invalid.
+    //
+    assert(nIndex != OS_INVALID_TLS_INDEX);
+    return pthread_getspecific(TLSIndexToPthreadKey(nIndex));
+}
+
+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(TLSIndexToPthreadKey(nIndex)) == 0)
+        return true;
+    else
+        return false;
+}
+
+namespace {
+    pthread_mutex_t gMutex;
+}
+
+void InitGlobalLock()
+{
+  pthread_mutexattr_t mutexattr;
+  pthread_mutexattr_init(&mutexattr);
+  pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+  pthread_mutex_init(&gMutex, &mutexattr);
+}
+
+void GetGlobalLock()
+{
+  pthread_mutex_lock(&gMutex);
+}
+
+void ReleaseGlobalLock()
+{
+  pthread_mutex_unlock(&gMutex);
+}
+
+// TODO: non-windows: if we need these on linux, flesh them out
+void* OS_CreateThread(TThreadEntrypoint /*entry*/)
+{
+    return 0;
+}
+
+void OS_WaitForAllThreads(void* /*threads*/, int /*numThreads*/)
+{
+}
+
+void OS_Sleep(int /*milliseconds*/)
+{
+}
+
+void OS_DumpMemoryCounters()
+{
+}
+
+} // end namespace glslang

+ 74 - 0
src/libraries/glslang/glslang/OSDependent/Windows/main.cpp

@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "InitializeDll.h"
+
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#include <assert.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+	switch (fdwReason)
+	{
+		case DLL_PROCESS_ATTACH:
+
+            if (! glslang::InitProcess())
+                return FALSE;
+            break;
+		case DLL_THREAD_ATTACH:
+
+            if (! glslang::InitThread())
+                return FALSE;
+            break;
+
+		case DLL_THREAD_DETACH:
+
+			if (! glslang::DetachThread())
+				return FALSE;
+			break;
+
+		case DLL_PROCESS_DETACH:
+
+			glslang::DetachProcess();
+			break;
+
+		default:
+			assert(0 && "DllMain(): Reason for calling DLL Main is unknown");
+			return FALSE;
+	}
+
+	return TRUE;
+}

+ 162 - 0
src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp

@@ -0,0 +1,162 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../osinclude.h"
+
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#include <cassert>
+#include <process.h>
+#include <psapi.h>
+#include <cstdio>
+#include <cstdint>
+
+//
+// This file contains the Window-OS-specific functions
+//
+
+#if !(defined(_WIN32) || defined(_WIN64))
+#error Trying to build a windows specific file in a non windows build.
+#endif
+
+namespace glslang {
+
+inline OS_TLSIndex ToGenericTLSIndex (DWORD handle)
+{
+    return (OS_TLSIndex)((uintptr_t)handle + 1);
+}
+
+inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex)
+{
+    return (DWORD)((uintptr_t)nIndex - 1);
+}
+
+//
+// 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 ToGenericTLSIndex(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(ToNativeTLSIndex(nIndex), lpvValue))
+        return true;
+    else
+        return false;
+}
+
+void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+    assert(nIndex != OS_INVALID_TLS_INDEX);
+    return TlsGetValue(ToNativeTLSIndex(nIndex));
+}
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+    if (nIndex == OS_INVALID_TLS_INDEX) {
+        assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+        return false;
+    }
+
+    if (TlsFree(ToNativeTLSIndex(nIndex)))
+        return true;
+    else
+        return false;
+}
+
+HANDLE GlobalLock;
+
+void InitGlobalLock()
+{
+    GlobalLock = CreateMutex(0, false, 0);
+}
+
+void GetGlobalLock()
+{
+    WaitForSingleObject(GlobalLock, INFINITE);
+}
+
+void ReleaseGlobalLock()
+{
+    ReleaseMutex(GlobalLock);
+}
+
+unsigned int __stdcall EnterGenericThread (void* entry)
+{
+    return ((TThreadEntrypoint)entry)(0);
+}
+
+void* OS_CreateThread(TThreadEntrypoint entry)
+{
+    return (void*)_beginthreadex(0, 0, EnterGenericThread, (void*)entry, 0, 0);
+}
+
+void OS_WaitForAllThreads(void* threads, int numThreads)
+{
+    WaitForMultipleObjects(numThreads, (HANDLE*)threads, true, INFINITE);
+}
+
+void OS_Sleep(int milliseconds)
+{
+    Sleep(milliseconds);
+}
+
+//#define DUMP_COUNTERS
+
+void OS_DumpMemoryCounters()
+{
+#ifdef DUMP_COUNTERS
+    PROCESS_MEMORY_COUNTERS counters;
+    GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
+    printf("Working set size: %d\n", counters.WorkingSetSize);
+#else
+    printf("Recompile with DUMP_COUNTERS defined to see counters.\n");
+#endif
+}
+
+} // namespace glslang

+ 66 - 0
src/libraries/glslang/glslang/OSDependent/osinclude.h

@@ -0,0 +1,66 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef __OSINCLUDE_H
+#define __OSINCLUDE_H
+
+namespace glslang {
+
+//
+// Thread Local Storage Operations
+//
+typedef void* OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX ((void*)0)
+
+OS_TLSIndex OS_AllocTLSIndex();
+bool        OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
+bool        OS_FreeTLSIndex(OS_TLSIndex nIndex);
+void*       OS_GetTLSValue(OS_TLSIndex nIndex);
+
+void InitGlobalLock();
+void GetGlobalLock();
+void ReleaseGlobalLock();
+
+typedef unsigned int (*TThreadEntrypoint)(void*);
+void* OS_CreateThread(TThreadEntrypoint);
+void OS_WaitForAllThreads(void* threads, int numThreads);
+
+void OS_CleanupThreadData(void);
+void OS_Sleep(int milliseconds);
+
+void OS_DumpMemoryCounters();
+
+} // end namespace glslang
+
+#endif // __OSINCLUDE_H

+ 548 - 0
src/libraries/glslang/glslang/Public/ShaderLang.h

@@ -0,0 +1,548 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef _COMPILER_INTERFACE_INCLUDED_
+#define _COMPILER_INTERFACE_INCLUDED_
+
+#include "../Include/ResourceLimits.h"
+#include "../MachineIndependent/Versions.h"
+
+#include <cstring>
+
+#ifdef _WIN32
+#define C_DECL __cdecl
+//#ifdef SH_EXPORTING
+//    #define SH_IMPORT_EXPORT __declspec(dllexport)
+//#else
+//    #define SH_IMPORT_EXPORT __declspec(dllimport)
+//#endif
+#define SH_IMPORT_EXPORT
+#else
+#define SH_IMPORT_EXPORT
+#ifndef __fastcall
+#define __fastcall
+#endif
+#define C_DECL
+#endif
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler/linker.
+//
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+//
+// Driver must call this first, once, before doing any other
+// compiler/linker operations.
+//
+// (Call once per process, not once per thread.)
+//
+SH_IMPORT_EXPORT int ShInitialize();
+
+//
+// Driver should call this at process shutdown.
+//
+SH_IMPORT_EXPORT int __fastcall ShFinalize();
+
+//
+// Types of languages the compiler can consume.
+//
+typedef enum {
+    EShLangVertex,
+    EShLangTessControl,
+    EShLangTessEvaluation,
+    EShLangGeometry,
+    EShLangFragment,
+    EShLangCompute,
+    EShLangCount,
+} EShLanguage;         // would be better as stage, but this is ancient now
+
+typedef enum {
+    EShLangVertexMask         = (1 << EShLangVertex),
+    EShLangTessControlMask    = (1 << EShLangTessControl),
+    EShLangTessEvaluationMask = (1 << EShLangTessEvaluation),
+    EShLangGeometryMask       = (1 << EShLangGeometry),
+    EShLangFragmentMask       = (1 << EShLangFragment),
+    EShLangComputeMask        = (1 << EShLangCompute),
+} EShLanguageMask;
+
+namespace glslang {
+
+class TType;
+
+typedef enum {
+    EShSourceNone,
+    EShSourceGlsl,
+    EShSourceHlsl,
+} EShSource;          // if EShLanguage were EShStage, this could be EShLanguage instead
+
+const char* StageName(EShLanguage);
+
+} // end namespace glslang
+
+//
+// Types of output the linker will create.
+//
+typedef enum {
+    EShExVertexFragment,
+    EShExFragment
+} EShExecutable;
+
+//
+// Optimization level for the compiler.
+//
+typedef enum {
+    EShOptNoGeneration,
+    EShOptNone,
+    EShOptSimple,       // Optimizations that can be done quickly
+    EShOptFull,         // Optimizations that will take more time
+} EShOptimizationLevel;
+
+//
+// Message choices for what errors and warnings are given.
+//
+enum EShMessages {
+    EShMsgDefault          = 0,         // default is to give all required errors and extra warnings
+    EShMsgRelaxedErrors    = (1 << 0),  // be liberal in accepting input
+    EShMsgSuppressWarnings = (1 << 1),  // suppress all warnings, except those required by the specification
+    EShMsgAST              = (1 << 2),  // print the AST intermediate representation
+    EShMsgSpvRules         = (1 << 3),  // issue messages for SPIR-V generation
+    EShMsgVulkanRules      = (1 << 4),  // issue messages for Vulkan-requirements of GLSL for SPIR-V
+    EShMsgOnlyPreprocessor = (1 << 5),  // only print out errors produced by the preprocessor
+    EShMsgReadHlsl         = (1 << 6),  // use HLSL parsing rules and semantics
+    EShMsgCascadingErrors  = (1 << 7),  // get cascading errors; risks error-recovery issues, instead of an early exit
+    EShMsgKeepUncalled     = (1 << 8),  // for testing, don't eliminate uncalled functions
+};
+
+//
+// Build a table for bindings.  This can be used for locating
+// attributes, uniforms, globals, etc., as needed.
+//
+typedef struct {
+    const char* name;
+    int binding;
+} ShBinding;
+
+typedef struct {
+    int numBindings;
+    ShBinding* bindings;  // array of bindings
+} ShBindingTable;
+
+//
+// ShHandle held by but opaque to the driver.  It is allocated,
+// managed, and de-allocated by the compiler/linker. It's contents
+// are defined by and used by the compiler and linker.  For example,
+// symbol table information and object code passed from the compiler
+// to the linker can be stored where ShHandle points.
+//
+// If handle creation fails, 0 will be returned.
+//
+typedef void* ShHandle;
+
+//
+// Driver calls these to create and destroy compiler/linker
+// objects.
+//
+SH_IMPORT_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions);  // one per shader
+SH_IMPORT_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions);  // one per shader pair
+SH_IMPORT_EXPORT ShHandle ShConstructUniformMap();                 // one per uniform namespace (currently entire program object)
+SH_IMPORT_EXPORT void ShDestruct(ShHandle);
+
+//
+// The return value of ShCompile is boolean, non-zero indicating
+// success.
+//
+// The info-log should be written by ShCompile into
+// ShHandle, so it can answer future queries.
+//
+SH_IMPORT_EXPORT int ShCompile(
+    const ShHandle,
+    const char* const shaderStrings[],
+    const int numStrings,
+    const int* lengths,
+    const EShOptimizationLevel,
+    const TBuiltInResource *resources,
+    int debugOptions,
+    int defaultVersion = 110,            // use 100 for ES environment, overridden by #version in shader
+    bool forwardCompatible = false,      // give errors for use of deprecated features
+    EShMessages messages = EShMsgDefault // warnings and errors
+    );
+
+SH_IMPORT_EXPORT int ShLink(
+    const ShHandle,               // linker object
+    const ShHandle h[],           // compiler objects to link together
+    const int numHandles,
+    ShHandle uniformMap,          // updated with new uniforms
+    short int** uniformsAccessed,  // returned with indexes of uniforms accessed
+    int* numUniformsAccessed);
+
+SH_IMPORT_EXPORT int ShLinkExt(
+    const ShHandle,               // linker object
+    const ShHandle h[],           // compiler objects to link together
+    const int numHandles);
+
+//
+// ShSetEncrpytionMethod is a place-holder for specifying
+// how source code is encrypted.
+//
+SH_IMPORT_EXPORT void ShSetEncryptionMethod(ShHandle);
+
+//
+// All the following return 0 if the information is not
+// available in the object passed down, or the object is bad.
+//
+SH_IMPORT_EXPORT const char* ShGetInfoLog(const ShHandle);
+SH_IMPORT_EXPORT const void* ShGetExecutable(const ShHandle);
+SH_IMPORT_EXPORT int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*);   // to detect user aliasing
+SH_IMPORT_EXPORT int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*);     // to force any physical mappings
+//
+// Tell the linker to never assign a vertex attribute to this list of physical attributes
+//
+SH_IMPORT_EXPORT int ShExcludeAttributes(const ShHandle, int *attributes, int count);
+
+//
+// Returns the location ID of the named uniform.
+// Returns -1 if error.
+//
+SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* name);
+
+#ifdef __cplusplus
+    }  // end extern "C"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Deferred-Lowering C++ Interface
+// -----------------------------------
+//
+// Below is a new alternate C++ interface that might potentially replace the above
+// opaque handle-based interface.
+//
+// The below is further designed to handle multiple compilation units per stage, where
+// the intermediate results, including the parse tree, are preserved until link time,
+// rather than the above interface which is designed to have each compilation unit
+// lowered at compile time.  In the above model, linking occurs on the lowered results,
+// whereas in this model intra-stage linking can occur at the parse tree
+// (treeRoot in TIntermediate) level, and then a full stage can be lowered.
+//
+
+#include <list>
+#include <string>
+#include <utility>
+
+class TCompiler;
+class TInfoSink;
+
+namespace glslang {
+
+const char* GetEsslVersionString();
+const char* GetGlslVersionString();
+int GetKhronosToolId();
+
+class TIntermediate;
+class TProgram;
+class TPoolAllocator;
+
+// Call this exactly once per process before using anything else
+bool InitializeProcess();
+
+// Call once per process to tear down everything
+void FinalizeProcess();
+
+// Make one TShader per shader that you will link into a program.  Then provide
+// the shader through setStrings() or setStringsWithLengths(), then call parse(),
+// then query the info logs.
+// Optionally use setPreamble() to set a special shader string that will be
+// processed before all others but won't affect the validity of #version.
+//
+// N.B.: Does not yet support having the same TShader instance being linked into
+// multiple programs.
+//
+// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
+//
+class TShader {
+public:
+    explicit TShader(EShLanguage);
+    virtual ~TShader();
+    void setStrings(const char* const* s, int n);
+    void setStringsWithLengths(const char* const* s, const int* l, int n);
+    void setStringsWithLengthsAndNames(
+        const char* const* s, const int* l, const char* const* names, int n);
+    void setPreamble(const char* s) { preamble = s; }
+    void setEntryPoint(const char* entryPoint);
+    void setSourceEntryPoint(const char* sourceEntryPointName);
+    void setShiftSamplerBinding(unsigned int base);
+    void setShiftTextureBinding(unsigned int base);
+    void setShiftImageBinding(unsigned int base);
+    void setShiftUboBinding(unsigned int base);
+    void setAutoMapBindings(bool map);
+    void setFlattenUniformArrays(bool flatten);
+    void setNoStorageFormat(bool useUnknownFormat);
+
+    // Interface to #include handlers.
+    //
+    // To support #include, a client of Glslang does the following:
+    // 1. Call setStringsWithNames to set the source strings and associated
+    //    names.  For example, the names could be the names of the files
+    //    containing the shader sources.
+    // 2. Call parse with an Includer.
+    //
+    // When the Glslang parser encounters an #include directive, it calls
+    // the Includer's include method with the requested include name
+    // together with the current string name.  The returned IncludeResult
+    // contains the fully resolved name of the included source, together
+    // with the source text that should replace the #include directive
+    // in the source stream.  After parsing that source, Glslang will
+    // release the IncludeResult object.
+    class Includer {
+    public:
+        // An IncludeResult contains the resolved name and content of a source
+        // inclusion.
+        struct IncludeResult {
+            IncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength, void* userData) :
+                headerName(headerName), headerData(headerData), headerLength(headerLength), userData(userData) { }
+            // For a successful inclusion, the fully resolved name of the requested
+            // include.  For example, in a file system-based includer, full resolution
+            // should convert a relative path name into an absolute path name.
+            // For a failed inclusion, this is an empty string.
+            const std::string headerName;
+            // The content and byte length of the requested inclusion.  The
+            // Includer producing this IncludeResult retains ownership of the
+            // storage.
+            // For a failed inclusion, the header
+            // field points to a string containing error details.
+            const char* const headerData;
+            const size_t headerLength;
+            // Include resolver's context.
+            void* userData;
+        protected:
+            IncludeResult& operator=(const IncludeResult&);
+            IncludeResult();
+        };
+
+        // For both include methods below:
+        //
+        // Resolves an inclusion request by name, current source name,
+        // and include depth.
+        // On success, returns an IncludeResult containing the resolved name
+        // and content of the include.
+        // On failure, returns a nullptr, or an IncludeResult
+        // with an empty string for the headerName and error details in the
+        // header field.
+        // The Includer retains ownership of the contents
+        // of the returned IncludeResult value, and those contents must
+        // remain valid until the releaseInclude method is called on that
+        // IncludeResult object.
+        //
+        // Note "local" vs. "system" is not an "either/or": "local" is an
+        // extra thing to do over "system". Both might get called, as per
+        // the C++ specification.
+
+        // For the "system" or <>-style includes; search the "system" paths.
+        virtual IncludeResult* includeSystem(const char* /*headerName*/,
+                                             const char* /*includerName*/,
+                                             size_t /*inclusionDepth*/) { return nullptr; }
+
+        // For the "local"-only aspect of a "" include. Should not search in the
+        // "system" paths, because on returning a failure, the parser will
+        // call includeSystem() to look in the "system" locations.
+        virtual IncludeResult* includeLocal(const char* /*headerName*/,
+                                            const char* /*includerName*/,
+                                            size_t /*inclusionDepth*/) { return nullptr; }
+
+        // Signals that the parser will no longer use the contents of the
+        // specified IncludeResult.
+        virtual void releaseInclude(IncludeResult*) = 0;
+        virtual ~Includer() {}
+    };
+
+    // Fail all Includer searches
+    class ForbidIncluder : public Includer {
+    public:
+        virtual void releaseInclude(IncludeResult*) override { }
+    };
+
+    bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
+               bool forwardCompatible, EShMessages messages)
+    {
+        TShader::ForbidIncluder includer;
+        return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer);
+    }
+
+    bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
+               bool forwardCompatible, EShMessages, Includer&);
+
+    // Equivalent to parse() without a default profile and without forcing defaults.
+    // Provided for backwards compatibility.
+    bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages);
+    bool preprocess(const TBuiltInResource* builtInResources,
+                    int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
+                    bool forwardCompatible, EShMessages message, std::string* outputString,
+                    Includer& includer);
+
+    const char* getInfoLog();
+    const char* getInfoDebugLog();
+
+    EShLanguage getStage() const { return stage; }
+
+protected:
+    TPoolAllocator* pool;
+    EShLanguage stage;
+    TCompiler* compiler;
+    TIntermediate* intermediate;
+    TInfoSink* infoSink;
+    // strings and lengths follow the standard for glShaderSource:
+    //     strings is an array of numStrings pointers to string data.
+    //     lengths can be null, but if not it is an array of numStrings
+    //         integers containing the length of the associated strings.
+    //         if lengths is null or lengths[n] < 0  the associated strings[n] is
+    //         assumed to be null-terminated.
+    // stringNames is the optional names for all the strings. If stringNames
+    // is null, then none of the strings has name. If a certain element in
+    // stringNames is null, then the corresponding string does not have name.
+    const char* const* strings;
+    const int* lengths;
+    const char* const* stringNames;
+    const char* preamble;
+    int numStrings;
+
+    // a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
+    std::string sourceEntryPointName;
+
+    friend class TProgram;
+
+private:
+    TShader& operator=(TShader&);
+};
+
+class TReflection;
+class TIoMapper;
+
+// Allows to customize the binding layout after linking.
+// All used uniform variables will invoke at least validateBinding.
+// If validateBinding returned true then the other resolveBinding
+// and resolveSet are invoked to resolve the binding and descriptor
+// set index respectively.
+// Invocations happen in a particular order:
+// 1) var with binding and set already defined
+// 2) var with binding but no set defined
+// 3) var with set but no binding defined
+// 4) var with no binding and no set defined
+//
+// NOTE: that still limit checks are applied to bindings and sets
+// and may result in an error.
+class TIoMapResolver
+{
+public:
+  virtual ~TIoMapResolver() {}
+
+  // Should return true if the resulting/current binding would be ok.
+  // Basic idea is to do aliasing binding checks with this.
+  virtual bool validateBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Should return a value >= 0 if the current binding should be overridden.
+  // Return -1 if the current binding (including no binding) should be kept.
+  virtual int resolveBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Should return a value >= 0 if the current set should be overriden.
+  // Return -1 if the current set (including no set) should be kept.
+  virtual int resolveSet(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+};
+
+// Make one TProgram per set of shaders that will get linked together.  Add all
+// the shaders that are to be linked together.  After calling shader.parse()
+// for all shaders, call link().
+//
+// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
+//
+class TProgram {
+public:
+    TProgram();
+    virtual ~TProgram();
+    void addShader(TShader* shader) { stages[shader->stage].push_back(shader); }
+
+    // Link Validation interface
+    bool link(EShMessages);
+    const char* getInfoLog();
+    const char* getInfoDebugLog();
+
+    TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
+
+    // Reflection Interface
+    bool buildReflection();                          // call first, to do liveness analysis, index mapping, etc.; returns false on failure
+    int getNumLiveUniformVariables() const;                // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
+    int getNumLiveUniformBlocks() const;                   // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
+    const char* getUniformName(int index) const;           // can be used for "name" part of glGetActiveUniform()
+    const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
+    int getUniformBlockSize(int blockIndex) const;         // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
+    int getUniformIndex(const char* name) const;           // can be used for glGetUniformIndices()
+    int getUniformBlockIndex(int index) const;             // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
+    int getUniformType(int index) const;                   // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
+    int getUniformBufferOffset(int index) const;           // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
+    int getUniformArraySize(int index) const;              // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
+    int getNumLiveAttributes() const;                      // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
+    const char *getAttributeName(int index) const;         // can be used for glGetActiveAttrib()
+    int getAttributeType(int index) const;                 // can be used for glGetActiveAttrib()
+    const TType* getUniformTType(int index) const;         // returns a TType*
+    const TType* getUniformBlockTType(int index) const;    // returns a TType*
+    const TType* getAttributeTType(int index) const;       // returns a TType*
+
+    void dumpReflection();
+
+    // I/O mapping: apply base offsets and map live unbound variables
+    // If resolver is not provided it uses the previous approach
+    // and respects auto assignment and offsets.
+    bool mapIO(TIoMapResolver* resolver = NULL);
+
+protected:
+    bool linkStage(EShLanguage, EShMessages);
+
+    TPoolAllocator* pool;
+    std::list<TShader*> stages[EShLangCount];
+    TIntermediate* intermediate[EShLangCount];
+    bool newedIntermediate[EShLangCount];      // track which intermediate were "new" versus reusing a singleton unit in a stage
+    TInfoSink* infoSink;
+    TReflection* reflection;
+    TIoMapper* ioMapper;
+    bool linked;
+
+private:
+    TProgram& operator=(TProgram&);
+};
+
+} // end namespace glslang
+
+#endif // _COMPILER_INTERFACE_INCLUDED_

+ 67 - 38
src/modules/graphics/Graphics.cpp

@@ -81,8 +81,8 @@ Colorf unGammaCorrectColor(const Colorf &c)
 
 love::Type Graphics::type("graphics", &Module::type);
 
-Shader::ShaderSource Graphics::defaultShaderCode[Graphics::RENDERER_MAX_ENUM][2];
-Shader::ShaderSource Graphics::defaultVideoShaderCode[Graphics::RENDERER_MAX_ENUM][2];
+Shader::ShaderSource Graphics::defaultShaderCode[Shader::LANGUAGE_MAX_ENUM][2];
+Shader::ShaderSource Graphics::defaultVideoShaderCode[Shader::LANGUAGE_MAX_ENUM][2];
 
 Graphics::Graphics()
 	: width(0)
@@ -101,6 +101,9 @@ Graphics::Graphics()
 
 	pixelScaleStack.reserve(16);
 	pixelScaleStack.push_back(1);
+
+	if (!Shader::initialize())
+		throw love::Exception("Shader support failed to initialize!");
 }
 
 Graphics::~Graphics()
@@ -124,6 +127,8 @@ Graphics::~Graphics()
 	delete streamBufferState.vb[0];
 	delete streamBufferState.vb[1];
 	delete streamBufferState.indexBuffer;
+
+	Shader::deinitialize();
 }
 
 Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
@@ -131,6 +136,11 @@ Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
 	return new Quad(v, sw, sh);
 }
 
+bool Graphics::validateShader(bool gles, const Shader::ShaderSource &source, std::string &err)
+{
+	return Shader::validate(this, gles, source, true, err);
+}
+
 int Graphics::getWidth() const
 {
 	return width;
@@ -544,6 +554,7 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
 
 	int totalvertices = state.vertexCount + req.vertexCount;
 
+	// We only support uint16 index buffers for now.
 	if (totalvertices > LOVE_UINT16_MAX && req.indexMode != TriangleIndexMode::NONE)
 		shouldflush = true;
 
@@ -555,45 +566,39 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
 
 	for (int i = 0; i < 2; i++)
 	{
-		if (req.formats[i] != CommonFormat::NONE)
-		{
-			size_t stride = getFormatStride(req.formats[i]);
-			size_t datasize = stride * totalvertices;
-
-			size_t cursize = state.vb[i]->getSize();
+		if (req.formats[i] == CommonFormat::NONE)
+			continue;
 
-			if (datasize > cursize)
-			{
-				shouldflush = true;
+		size_t stride = getFormatStride(req.formats[i]);
+		size_t datasize = stride * totalvertices;
 
-				if (stride * req.vertexCount > cursize)
-				{
-					buffersizes[i] = std::max(datasize, cursize * 2);
-					shouldresize = true;
-				}
-			}
+		if (state.vbMap[i].data != nullptr && datasize > state.vbMap[i].size)
+			shouldflush = true;
 
-			newdatasizes[i] = stride * req.vertexCount;
+		if (datasize > state.vb[i]->getSize())
+		{
+			buffersizes[i] = std::max(datasize, state.vb[i]->getSize() * 2);
+			shouldresize = true;
 		}
+
+		newdatasizes[i] = stride * req.vertexCount;
 	}
 
+	if (req.indexMode != TriangleIndexMode::NONE)
 	{
 		size_t datasize = (state.indexCount + reqIndexCount) * sizeof(uint16);
-		size_t cursize = state.indexBuffer->getSize();
 
-		if (datasize > cursize)
-		{
+		if (state.indexBufferMap.data != nullptr && datasize > state.indexBufferMap.size)
 			shouldflush = true;
 
-			if (reqIndexSize > cursize)
-			{
-				buffersizes[2] = std::max(datasize, cursize * 2);
-				shouldresize = true;
-			}
+		if (datasize > state.indexBuffer->getSize())
+		{
+			buffersizes[2] = std::max(datasize, state.indexBuffer->getSize() * 2);
+			shouldresize = true;
 		}
 	}
 
-	if (shouldflush)
+	if (shouldflush || shouldresize)
 	{
 		flushStreamDraws();
 
@@ -609,30 +614,48 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
 		for (int i = 0; i < 2; i++)
 		{
 			if (state.vb[i]->getSize() < buffersizes[i])
-				state.vb[i]->setSize(buffersizes[i]);
+			{
+				delete state.vb[i];
+				state.vb[i] = newStreamBuffer(BUFFER_VERTEX, buffersizes[i]);
+			}
 		}
 
 		if (state.indexBuffer->getSize() < buffersizes[2])
-			state.indexBuffer->setSize(buffersizes[2]);
+		{
+			delete state.indexBuffer;
+			state.indexBuffer = newStreamBuffer(BUFFER_INDEX, buffersizes[2]);
+		}
 	}
 
 	if (req.indexMode != TriangleIndexMode::NONE)
 	{
-		uint16 *indices = (uint16 *) state.indexBuffer->getOffsetData();
+		if (state.indexBufferMap.data == nullptr)
+			state.indexBufferMap = state.indexBuffer->map(reqIndexSize);
+
+		uint16 *indices = (uint16 *) state.indexBufferMap.data;
 		fillIndices(req.indexMode, state.vertexCount, req.vertexCount, indices);
-		state.indexBuffer->incrementOffset(reqIndexSize);
+
+		state.indexBufferMap.data += reqIndexSize;
 	}
 
 	StreamVertexData d;
-	d.stream[0] = state.vb[0]->getOffsetData();
-	d.stream[1] = state.vb[1]->getOffsetData();
+
+	for (int i = 0; i < 2; i++)
+	{
+		if (newdatasizes[i] > 0)
+		{
+			if (state.vbMap[i].data == nullptr)
+				state.vbMap[i] = state.vb[i]->map(newdatasizes[i]);
+
+			d.stream[i] = state.vbMap[i].data;
+
+			state.vbMap[i].data += newdatasizes[i];
+		}
+	}
 
 	state.vertexCount += req.vertexCount;
 	state.indexCount  += reqIndexCount;
 
-	state.vb[0]->incrementOffset(newdatasizes[0]);
-	state.vb[1]->incrementOffset(newdatasizes[1]);
-
 	return d;
 }
 
@@ -1107,6 +1130,11 @@ Vector Graphics::inverseTransformPoint(Vector point)
 	return p;
 }
 
+const Shader::ShaderSource &Graphics::getCurrentDefaultShaderCode() const
+{
+	return defaultShaderCode[getShaderLanguageTarget()][isGammaCorrect() ? 1 : 0];
+}
+
 /**
  * Constants.
  **/
@@ -1308,8 +1336,9 @@ StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featur
 	{ "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS },
 	{ "clampzero",          FEATURE_CLAMP_ZERO           },
 	{ "lighten",            FEATURE_LIGHTEN              },
-	{ "fullnpot", FEATURE_FULL_NPOT },
-	{ "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP },
+	{ "fullnpot",           FEATURE_FULL_NPOT            },
+	{ "pixelshaderhighp",   FEATURE_PIXEL_SHADER_HIGHP   },
+	{ "glsl3",              FEATURE_GLSL3                },
 };
 
 StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));

+ 20 - 2
src/modules/graphics/Graphics.h

@@ -166,6 +166,7 @@ public:
 		FEATURE_LIGHTEN,
 		FEATURE_FULL_NPOT,
 		FEATURE_PIXEL_SHADER_HIGHP,
+		FEATURE_GLSL3,
 		FEATURE_MAX_ENUM
 	};
 
@@ -313,6 +314,8 @@ public:
 
 	virtual Shader *newShader(const Shader::ShaderSource &source) = 0;
 
+	bool validateShader(bool gles, const Shader::ShaderSource &source, std::string &err);
+
 	/**
 	 * Resets the current color, background color, line style, and so forth.
 	 **/
@@ -634,6 +637,11 @@ public:
 	 **/
 	virtual double getSystemLimit(SystemLimit limittype) const = 0;
 
+	/**
+	 * Gets the renderer used by love.graphics.
+	 **/
+	virtual Renderer getRenderer() const = 0;
+
 	/**
 	 * Returns system-dependent renderer information.
 	 * Returned strings can vary greatly between systems! Do not rely on it for
@@ -667,6 +675,9 @@ public:
 	virtual void flushStreamDraws() = 0;
 	StreamVertexData requestStreamDraw(const StreamDrawRequest &request);
 
+	virtual Shader::Language getShaderLanguageTarget() const = 0;
+	const Shader::ShaderSource &getCurrentDefaultShaderCode() const;
+
 	template <typename T>
 	T *getScratchBuffer(size_t count)
 	{
@@ -712,8 +723,8 @@ public:
 	static bool getConstant(StackType in, const char *&out);
 
 	// Default shader code (a shader is always required internally.)
-	static Shader::ShaderSource defaultShaderCode[RENDERER_MAX_ENUM][2];
-	static Shader::ShaderSource defaultVideoShaderCode[RENDERER_MAX_ENUM][2];
+	static Shader::ShaderSource defaultShaderCode[Shader::LANGUAGE_MAX_ENUM][2];
+	static Shader::ShaderSource defaultVideoShaderCode[Shader::LANGUAGE_MAX_ENUM][2];
 
 protected:
 
@@ -756,6 +767,7 @@ protected:
 	{
 		StreamBuffer *vb[2];
 		StreamBuffer *indexBuffer = nullptr;
+
 		vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES;
 		vertex::CommonFormat formats[2];
 		StrongRef<Texture> texture;
@@ -763,13 +775,19 @@ protected:
 		int vertexCount = 0;
 		int indexCount = 0;
 
+		StreamBuffer::MapInfo vbMap[2];
+		StreamBuffer::MapInfo indexBufferMap = StreamBuffer::MapInfo();
+
 		StreamBufferState()
 		{
 			vb[0] = vb[1] = nullptr;
 			formats[0] = formats[1] = vertex::CommonFormat::NONE;
+			vbMap[0] = vbMap[1] = StreamBuffer::MapInfo();
 		}
 	};
 
+	virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0;
+
 	void restoreState(const DisplayState &s);
 	void restoreStateChecked(const DisplayState &s);
 

+ 211 - 21
src/modules/graphics/Shader.cpp

@@ -20,6 +20,110 @@
 
 // LOVE
 #include "Shader.h"
+#include "Graphics.h"
+
+// glslang
+#include "libraries/glslang/glslang/Public/ShaderLang.h"
+
+// C++
+#include <string>
+
+// TODO: Use love.graphics to determine actual limits?
+static const TBuiltInResource defaultTBuiltInResource = {
+	/* .MaxLights = */ 32,
+	/* .MaxClipPlanes = */ 6,
+	/* .MaxTextureUnits = */ 32,
+	/* .MaxTextureCoords = */ 32,
+	/* .MaxVertexAttribs = */ 64,
+	/* .MaxVertexUniformComponents = */ 16384,
+	/* .MaxVaryingFloats = */ 128,
+	/* .MaxVertexTextureImageUnits = */ 32,
+	/* .MaxCombinedTextureImageUnits = */ 80,
+	/* .MaxTextureImageUnits = */ 32,
+	/* .MaxFragmentUniformComponents = */ 16384,
+	/* .MaxDrawBuffers = */ 8,
+	/* .MaxVertexUniformVectors = */ 4096,
+	/* .MaxVaryingVectors = */ 32,
+	/* .MaxFragmentUniformVectors = */ 4096,
+	/* .MaxVertexOutputVectors = */ 32,
+	/* .MaxFragmentInputVectors = */ 31,
+	/* .MinProgramTexelOffset = */ -8,
+	/* .MaxProgramTexelOffset = */ 7,
+	/* .MaxClipDistances = */ 8,
+	/* .MaxComputeWorkGroupCountX = */ 65535,
+	/* .MaxComputeWorkGroupCountY = */ 65535,
+	/* .MaxComputeWorkGroupCountZ = */ 65535,
+	/* .MaxComputeWorkGroupSizeX = */ 1024,
+	/* .MaxComputeWorkGroupSizeY = */ 1024,
+	/* .MaxComputeWorkGroupSizeZ = */ 64,
+	/* .MaxComputeUniformComponents = */ 1024,
+	/* .MaxComputeTextureImageUnits = */ 32,
+	/* .MaxComputeImageUniforms = */ 16,
+	/* .MaxComputeAtomicCounters = */ 4096,
+	/* .MaxComputeAtomicCounterBuffers = */ 8,
+	/* .MaxVaryingComponents = */ 128,
+	/* .MaxVertexOutputComponents = */ 128,
+	/* .MaxGeometryInputComponents = */ 128,
+	/* .MaxGeometryOutputComponents = */ 128,
+	/* .MaxFragmentInputComponents = */ 128,
+	/* .MaxImageUnits = */ 192,
+	/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
+	/* .MaxCombinedShaderOutputResources = */ 144,
+	/* .MaxImageSamples = */ 32,
+	/* .MaxVertexImageUniforms = */ 16,
+	/* .MaxTessControlImageUniforms = */ 16,
+	/* .MaxTessEvaluationImageUniforms = */ 16,
+	/* .MaxGeometryImageUniforms = */ 16,
+	/* .MaxFragmentImageUniforms = */ 16,
+	/* .MaxCombinedImageUniforms = */ 80,
+	/* .MaxGeometryTextureImageUnits = */ 16,
+	/* .MaxGeometryOutputVertices = */ 256,
+	/* .MaxGeometryTotalOutputComponents = */ 1024,
+	/* .MaxGeometryUniformComponents = */ 1024,
+	/* .MaxGeometryVaryingComponents = */ 64,
+	/* .MaxTessControlInputComponents = */ 128,
+	/* .MaxTessControlOutputComponents = */ 128,
+	/* .MaxTessControlTextureImageUnits = */ 16,
+	/* .MaxTessControlUniformComponents = */ 1024,
+	/* .MaxTessControlTotalOutputComponents = */ 4096,
+	/* .MaxTessEvaluationInputComponents = */ 128,
+	/* .MaxTessEvaluationOutputComponents = */ 128,
+	/* .MaxTessEvaluationTextureImageUnits = */ 16,
+	/* .MaxTessEvaluationUniformComponents = */ 1024,
+	/* .MaxTessPatchComponents = */ 120,
+	/* .MaxPatchVertices = */ 32,
+	/* .MaxTessGenLevel = */ 64,
+	/* .MaxViewports = */ 16,
+	/* .MaxVertexAtomicCounters = */ 4096,
+	/* .MaxTessControlAtomicCounters = */ 4096,
+	/* .MaxTessEvaluationAtomicCounters = */ 4096,
+	/* .MaxGeometryAtomicCounters = */ 4096,
+	/* .MaxFragmentAtomicCounters = */ 4096,
+	/* .MaxCombinedAtomicCounters = */ 4096,
+	/* .MaxAtomicCounterBindings = */ 8,
+	/* .MaxVertexAtomicCounterBuffers = */ 8,
+	/* .MaxTessControlAtomicCounterBuffers = */ 8,
+	/* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
+	/* .MaxGeometryAtomicCounterBuffers = */ 8,
+	/* .MaxFragmentAtomicCounterBuffers = */ 8,
+	/* .MaxCombinedAtomicCounterBuffers = */ 8,
+	/* .MaxAtomicCounterBufferSize = */ 16384,
+	/* .MaxTransformFeedbackBuffers = */ 4,
+	/* .MaxTransformFeedbackInterleavedComponents = */ 64,
+	/* .MaxCullDistances = */ 8,
+	/* .MaxCombinedClipAndCullDistances = */ 8,
+	/* .MaxSamples = */ 32,
+	/* .limits = */ {
+		/* .nonInductiveForLoops = */ 1,
+		/* .whileLoops = */ 1,
+		/* .doWhileLoops = */ 1,
+		/* .generalUniformIndexing = */ 1,
+		/* .generalAttributeMatrixVectorIndexing = */ 1,
+		/* .generalVaryingIndexing = */ 1,
+		/* .generalSamplerIndexing = */ 1,
+		/* .generalVariableIndexing = */ 1,
+		/* .generalConstantMatrixVectorIndexing = */ 1,
+	}};
 
 namespace love
 {
@@ -31,6 +135,19 @@ Shader *Shader::current = nullptr;
 Shader *Shader::defaultShader = nullptr;
 Shader *Shader::defaultVideoShader = nullptr;
 
+Shader::Shader(const ShaderSource &source)
+	: shaderSource(source)
+{
+	auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
+	if (gfx == nullptr)
+		throw love::Exception("love.graphics must be initialized to create a Shader.");
+
+	bool gles = gfx->getRenderer() == Graphics::RENDERER_OPENGLES;
+	std::string err;
+	if (!validate(gfx, gles, source, false, err))
+		throw love::Exception("%s", err.c_str());
+}
+
 Shader::~Shader()
 {
 	if (defaultShader == this)
@@ -56,24 +173,100 @@ void Shader::attachDefault()
 	current = nullptr;
 }
 
-bool Shader::getConstant(const char *in, ShaderStage &out)
+bool Shader::validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err)
 {
-	return stageNames.find(in, out);
+	if (source.vertex.empty() && source.pixel.empty())
+	{
+		err = "Error validating shader: no source code!";
+		return false;
+	}
+
+	bool supportsGLSL3 = gfx->isSupported(Graphics::FEATURE_GLSL3);
+
+	int defaultversion = gles ? 100 : 120;
+	EProfile defaultprofile = gles ? EEsProfile : ENoProfile;
+
+	glslang::TShader vshader(EShLangVertex);
+	glslang::TShader pshader(EShLangFragment);
+
+	// TProgram must be destroyed before TShader.
+	glslang::TProgram program;
+
+	auto addshader = [&](glslang::TShader &s, const std::string &src, ShaderStage stage) -> bool
+	{
+		if (src.empty())
+			return true;
+
+		const char *csrc = src.c_str();
+		int srclen = (int) src.length();
+		s.setStringsWithLengths(&csrc, &srclen, 1);
+
+		bool forcedefault = false;
+		if (src.find("#define LOVE_GLSL1_ON_GLSL3") != std::string::npos)
+			forcedefault = true;
+
+		bool forwardcompat = supportsGLSL3 && !forcedefault;
+
+		if (!s.parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings))
+		{
+			const char *stagename;
+			getConstant(stage, stagename);
+			err = "Error validating " + std::string(stagename) + " shader:\n\n"
+				+ std::string(s.getInfoLog()) + "\n" + std::string(s.getInfoDebugLog());
+			return false;
+		}
+
+		program.addShader(&s);
+		return true;
+	};
+
+	const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode();
+	const std::string &vertcode = (checkWithDefaults && source.vertex.empty()) ? defaults.vertex : source.vertex;
+	const std::string &pixcode = (checkWithDefaults && source.pixel.empty()) ? defaults.pixel : source.pixel;
+
+	if (!addshader(vshader, vertcode, STAGE_VERTEX))
+		return false;
+
+	if (!addshader(pshader, pixcode, STAGE_PIXEL))
+		return false;
+
+	if (!program.link(EShMsgDefault))
+	{
+		err = "Cannot compile shader:\n\n" + std::string(program.getInfoLog()) + "\n" + std::string(program.getInfoDebugLog());
+		return false;
+	}
+
+	return true;
 }
 
-bool Shader::getConstant(ShaderStage in, const char *&out)
+bool Shader::initialize()
 {
-	return stageNames.find(in, out);
+	return glslang::InitializeProcess();
+}
+
+void Shader::deinitialize()
+{
+	glslang::FinalizeProcess();
+}
+
+bool Shader::getConstant(const char *in, Language &out)
+{
+	return languages.find(in, out);
+}
+
+bool Shader::getConstant(Language in, const char *&out)
+{
+	return languages.find(in, out);
 }
 
-bool Shader::getConstant(const char *in, UniformType &out)
+bool Shader::getConstant(const char *in, ShaderStage &out)
 {
-	return uniformTypes.find(in, out);
+	return stageNames.find(in, out);
 }
 
-bool Shader::getConstant(UniformType in, const char *&out)
+bool Shader::getConstant(ShaderStage in, const char *&out)
 {
-	return uniformTypes.find(in, out);
+	return stageNames.find(in, out);
 }
 
 bool Shader::getConstant(const char *in, VertexAttribID &out)
@@ -96,26 +289,23 @@ bool Shader::getConstant(BuiltinUniform in, const char *&out)
 	return builtinNames.find(in, out);
 }
 
-StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
+StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM>::Entry Shader::languageEntries[] =
 {
-	{"vertex", Shader::STAGE_VERTEX},
-	{"pixel", Shader::STAGE_PIXEL},
+	{"glsl1",   LANGUAGE_GLSL1  },
+	{"glsles1", LANGUAGE_GLSLES1},
+	{"glsl3",   LANGUAGE_GLSL3  },
+	{"glsles3", LANGUAGE_GLSLES3},
 };
 
-StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
+StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM> Shader::languages(Shader::languageEntries, sizeof(Shader::languageEntries));
 
-StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
+StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
 {
-	{"float", Shader::UNIFORM_FLOAT},
-	{"matrix", Shader::UNIFORM_MATRIX},
-	{"int", Shader::UNIFORM_INT},
-	{"uint", Shader::UNIFORM_UINT},
-	{"bool", Shader::UNIFORM_BOOL},
-	{"image", Shader::UNIFORM_SAMPLER},
-	{"unknown", Shader::UNIFORM_UNKNOWN},
+	{"vertex", Shader::STAGE_VERTEX},
+	{"pixel", Shader::STAGE_PIXEL},
 };
 
-StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
+StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
 
 StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
 {

+ 28 - 6
src/modules/graphics/Shader.h

@@ -36,6 +36,8 @@ namespace love
 namespace graphics
 {
 
+class Graphics;
+
 // A GLSL shader
 class Shader : public Object
 {
@@ -43,6 +45,15 @@ public:
 
 	static love::Type type;
 
+	enum Language
+	{
+		LANGUAGE_GLSL1,
+		LANGUAGE_GLSLES1,
+		LANGUAGE_GLSL3,
+		LANGUAGE_GLSLES3,
+		LANGUAGE_MAX_ENUM
+	};
+
 	enum ShaderStage
 	{
 		STAGE_VERTEX,
@@ -122,6 +133,7 @@ public:
 	static Shader *defaultShader;
 	static Shader *defaultVideoShader;
 
+	Shader(const ShaderSource &source);
 	virtual ~Shader();
 
 	/**
@@ -158,26 +170,36 @@ public:
 	 **/
 	virtual void setVideoTextures(ptrdiff_t ytexture, ptrdiff_t cbtexture, ptrdiff_t crtexture) = 0;
 
+	static bool validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err);
+
+	static bool initialize();
+	static void deinitialize();
+
+	static bool getConstant(const char *in, Language &out);
+	static bool getConstant(Language in, const char *&out);
+
 	static bool getConstant(const char *in, ShaderStage &out);
 	static bool getConstant(ShaderStage in, const char *&out);
 
-	static bool getConstant(const char *in, UniformType &out);
-	static bool getConstant(UniformType in, const char *&out);
-
 	static bool getConstant(const char *in, VertexAttribID &out);
 	static bool getConstant(VertexAttribID in, const char *&out);
 
 	static bool getConstant(const char *in, BuiltinUniform &out);
 	static bool getConstant(BuiltinUniform in, const char *&out);
 
+protected:
+
+	// Source code used for this Shader.
+	ShaderSource shaderSource;
+
 private:
 
+	static StringMap<Language, LANGUAGE_MAX_ENUM>::Entry languageEntries[];
+	static StringMap<Language, LANGUAGE_MAX_ENUM> languages;
+
 	static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
 	static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
 	
-	static StringMap<UniformType, UNIFORM_MAX_ENUM>::Entry uniformTypeEntries[];
-	static StringMap<UniformType, UNIFORM_MAX_ENUM> uniformTypes;
-	
 	// Names for the generic vertex attributes used by love.
 	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry attribNameEntries[];
 	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM> attribNames;

+ 2 - 46
src/modules/graphics/StreamBuffer.cpp

@@ -26,54 +26,10 @@ namespace love
 namespace graphics
 {
 
-StreamBuffer::StreamBuffer(Mode mode, size_t size)
-	: data(nullptr)
-	, offset(0)
-	, totalSize(size)
+StreamBuffer::StreamBuffer(BufferType mode, size_t size)
+	: bufferSize(size)
 	, mode(mode)
 {
-	setSize(size);
-}
-
-StreamBuffer::~StreamBuffer()
-{
-	delete[] data;
-}
-
-void *StreamBuffer::getData() const
-{
-	return data;
-}
-
-void *StreamBuffer::getOffsetData() const
-{
-	return data + offset;
-}
-
-void StreamBuffer::incrementOffset(size_t amount)
-{
-	offset += amount;
-}
-
-void StreamBuffer::resetOffset()
-{
-	offset = 0;
-}
-
-void StreamBuffer::setSize(size_t size)
-{
-	delete[] data;
-
-	try
-	{
-		data = new uint8[size];
-	}
-	catch (std::exception &)
-	{
-		throw love::Exception("Out of memory.");
-	}
-
-	this->totalSize = size;
 }
 
 } // graphics

+ 22 - 26
src/modules/graphics/StreamBuffer.h

@@ -22,6 +22,7 @@
 
 // LOVE
 #include "common/int.h"
+#include "vertex.h"
 
 // C
 #include <cstddef>
@@ -31,45 +32,40 @@ namespace love
 namespace graphics
 {
 
-// TODO: This class will need to be changed significantly in the future to
-// accomodate non-client-side vertex/index data.
 class StreamBuffer
 {
 public:
 
-	enum Mode
+	struct MapInfo
 	{
-		MODE_VERTEX,
-		MODE_INDEX,
-	};
+		uint8 *data = nullptr;
+		size_t size = 0;
 
-	StreamBuffer(Mode mode, size_t size);
-	~StreamBuffer();
+		MapInfo() {}
 
-	void *getData() const;
-	void *getOffsetData() const;
+		MapInfo(uint8 *data, size_t size)
+			: data(data)
+			, size(size)
+		{}
+	};
 
-	void incrementOffset(size_t amount);
-	void resetOffset();
+	virtual ~StreamBuffer() {}
 
-	void setSize(size_t size);
+	size_t getSize() const { return bufferSize; }
+	BufferType getMode() const { return mode; }
 
-	size_t getSize() const
-	{
-		return totalSize;
-	}
+	virtual MapInfo map(size_t minsize) = 0;
+	virtual size_t unmap(size_t usedsize) = 0;
+	virtual void markUsed(size_t usedsize) = 0;
 
-	Mode getMode() const
-	{
-		return mode;
-	}
+	virtual ptrdiff_t getHandle() const = 0;
+
+protected:
 
-private:
+	StreamBuffer(BufferType mode, size_t size);
 
-	uint8 *data;
-	size_t offset;
-	size_t totalSize;
-	Mode mode;
+	size_t bufferSize;
+	BufferType mode;
 
 }; // StreamBuffer
 

+ 94 - 0
src/modules/graphics/opengl/BufferSync.cpp

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+
+#include "BufferSync.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+BufferSync::~BufferSync()
+{
+	cleanup();
+}
+
+void BufferSync::lock(size_t start, size_t length)
+{
+	Range range = {start, length};
+	GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+	locks.emplace_back(range, sync);
+}
+
+void BufferSync::wait(size_t start, size_t length)
+{
+	Range range = {start, length};
+	int lockcount = (int) locks.size();
+
+	for (int i = 0; i < lockcount; i++)
+	{
+		if (range.overlaps(locks[i].range))
+		{
+			syncWait(locks[i].sync);
+			glDeleteSync(locks[i].sync);
+
+			locks[i] = locks[lockcount - 1];
+			locks.pop_back();
+
+			--lockcount;
+			--i;
+		}
+	}
+}
+
+void BufferSync::cleanup()
+{
+	for (const auto &lock : locks)
+		glDeleteSync(lock.sync);
+
+	locks.clear();
+}
+
+void BufferSync::syncWait(GLsync sync)
+{
+	GLbitfield flags = 0;
+	GLuint64 duration = 0;
+
+	while (true)
+	{
+		GLenum status = glClientWaitSync(sync, flags, duration);
+
+		if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
+			return;
+
+		if (status == GL_WAIT_FAILED)
+			return;
+
+		flags = GL_SYNC_FLUSH_COMMANDS_BIT;
+		duration = 1000000000; // 1 second in nanoseconds.
+	}
+}
+
+} // opengl
+} // graphics
+} // love

+ 80 - 0
src/modules/graphics/opengl/BufferSync.h

@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "OpenGL.h"
+
+// C
+#include <stddef.h>
+#include <vector>
+
+#pragma once
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+class BufferSync
+{
+public:
+
+	~BufferSync();
+
+	void lock(size_t start, size_t length);
+	void wait(size_t start, size_t length);
+	void cleanup();
+
+private:
+
+	struct Range
+	{
+		size_t offset;
+		size_t length;
+
+		bool overlaps(const Range &other) const
+		{
+			return offset < (other.offset + other.length)
+				&& other.offset < (offset + length);
+		}
+	};
+
+	struct Lock
+	{
+		Range range;
+		GLsync sync;
+
+		Lock(const Range &range, GLsync sync)
+			: range(range)
+			, sync(sync)
+		{}
+	};
+
+	void syncWait(GLsync sync);
+
+	std::vector<Lock> locks;
+
+}; // BufferSync
+
+} // opengl
+} // graphics
+} // love

+ 63 - 23
src/modules/graphics/opengl/Graphics.cpp

@@ -26,7 +26,7 @@
 #include "Graphics.h"
 #include "font/Font.h"
 #include "Font.h"
-#include "graphics/Polyline.h"
+#include "StreamBuffer.h"
 #include "math/MathModule.h"
 #include "window/Window.h"
 
@@ -95,6 +95,11 @@ const char *Graphics::getName() const
 	return "love.graphics.opengl";
 }
 
+love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t size)
+{
+	return CreateStreamBuffer(type, size);
+}
+
 Image *Graphics::newImage(const std::vector<love::image::ImageData *> &data, const Image::Settings &settings)
 {
 	return new Image(data, settings);
@@ -215,6 +220,13 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 
 	// Okay, setup OpenGL.
 	gl.initContext();
+
+	if (gl.isCoreProfile())
+	{
+		glGenVertexArrays(1, &mainVAO);
+		glBindVertexArray(mainVAO);
+	}
+
 	gl.setupContext();
 
 	created = true;
@@ -237,12 +249,6 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 		glEnable(GL_TEXTURE_2D);
 	}
 
-	if (gl.isCoreProfile())
-	{
-		glGenVertexArrays(1, &mainVAO);
-		glBindVertexArray(mainVAO);
-	}
-
 	gl.setTextureUnit(0);
 
 	// Set pixel row alignment
@@ -274,9 +280,9 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 	{
 		// Initial sizes that should be good enough for most cases. It will
 		// resize to fit if needed, later.
-		streamBufferState.vb[0] = new StreamBuffer(StreamBuffer::MODE_VERTEX, 1024 * 1024 * 1);
-		streamBufferState.vb[1] = new StreamBuffer(StreamBuffer::MODE_VERTEX, 256  * 1024 * 1);
-		streamBufferState.indexBuffer = new StreamBuffer(StreamBuffer::MODE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
+		streamBufferState.vb[0] = CreateStreamBuffer(BUFFER_VERTEX, 1024 * 1024 * 1);
+		streamBufferState.vb[1] = CreateStreamBuffer(BUFFER_VERTEX, 256  * 1024 * 1);
+		streamBufferState.indexBuffer = CreateStreamBuffer(BUFFER_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
 	}
 
 	// Reload all volatile objects.
@@ -299,15 +305,15 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 	// We always need a default shader.
 	if (!Shader::defaultShader)
 	{
-		Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
-		Shader::defaultShader = newShader(defaultShaderCode[renderer][gammacorrect]);
+		Shader::Language target = getShaderLanguageTarget();
+		Shader::defaultShader = newShader(defaultShaderCode[target][gammacorrect]);
 	}
 
 	// and a default video shader.
 	if (!Shader::defaultVideoShader)
 	{
-		Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
-		Shader::defaultVideoShader = newShader(defaultVideoShaderCode[renderer][gammacorrect]);
+		Shader::Language target = getShaderLanguageTarget();
+		Shader::defaultVideoShader = newShader(defaultVideoShaderCode[target][gammacorrect]);
 	}
 
 	// A shader should always be active, but the default shader shouldn't be
@@ -365,7 +371,7 @@ void Graphics::flushStreamDraws()
 {
 	using namespace vertex;
 
-	const auto &sbstate = streamBufferState;
+	auto &sbstate = streamBufferState;
 
 	if (sbstate.vertexCount == 0 && sbstate.indexCount == 0)
 		return;
@@ -373,19 +379,22 @@ void Graphics::flushStreamDraws()
 	OpenGL::TempDebugGroup debuggroup("Stream vertices flush and draw");
 
 	uint32 attribs = 0;
+	size_t usedsizes[3] = {0, 0, 0};
 
 	for (int i = 0; i < 2; i++)
 	{
 		if (sbstate.formats[i] == CommonFormat::NONE)
 			continue;
 
-		StreamBuffer *buffer = sbstate.vb[i];
-
-		buffer->resetOffset();
-		ptrdiff_t offset = (ptrdiff_t) buffer->getData();
 		GLsizei stride = (GLsizei) getFormatStride(sbstate.formats[i]);
+		usedsizes[i] = stride * sbstate.vertexCount;
 
-		gl.bindBuffer(BUFFER_VERTEX, 0);
+		love::graphics::StreamBuffer *buffer = sbstate.vb[i];
+
+		gl.bindBuffer(BUFFER_VERTEX, (GLuint) buffer->getHandle());
+		size_t offset = buffer->unmap(usedsizes[i]);
+
+		sbstate.vbMap[i] = StreamBuffer::MapInfo();
 
 		switch (sbstate.formats[i])
 		{
@@ -451,15 +460,27 @@ void Graphics::flushStreamDraws()
 
 	if (sbstate.indexCount > 0)
 	{
-		sbstate.indexBuffer->resetOffset();
-		ptrdiff_t offset = (ptrdiff_t) sbstate.indexBuffer->getData();
+		usedsizes[2] = sizeof(uint16) * sbstate.indexCount;
+
+		gl.bindBuffer(BUFFER_INDEX, (GLuint) sbstate.indexBuffer->getHandle());
+		size_t offset = sbstate.indexBuffer->unmap(usedsizes[2]);
+
+		sbstate.indexBufferMap = StreamBuffer::MapInfo();
 
-		gl.bindBuffer(BUFFER_INDEX, 0);
 		gl.drawElements(glmode, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset));
 	}
 	else
 		gl.drawArrays(glmode, 0, sbstate.vertexCount);
 
+	for (int i = 0; i < 2; i++)
+	{
+		if (usedsizes[i] > 0)
+			sbstate.vb[i]->markUsed(usedsizes[i]);
+	}
+
+	if (usedsizes[2] > 0)
+		sbstate.indexBuffer->markUsed(usedsizes[2]);
+
 	popTransform();
 
 	if (attribs & ATTRIB_CONSTANTCOLOR)
@@ -1376,6 +1397,11 @@ void Graphics::setWireframe(bool enable)
 	states.back().wireframe = enable;
 }
 
+Graphics::Renderer Graphics::getRenderer() const
+{
+	return GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
+}
+
 Graphics::RendererInfo Graphics::getRendererInfo() const
 {
 	RendererInfo info;
@@ -1459,11 +1485,25 @@ bool Graphics::isSupported(Feature feature) const
 		return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot;
 	case FEATURE_PIXEL_SHADER_HIGHP:
 		return gl.isPixelShaderHighpSupported();
+	case FEATURE_GLSL3:
+		return GLAD_ES_VERSION_3_0 || gl.isCoreProfile();
 	default:
 		return false;
 	}
 }
 
+Shader::Language Graphics::getShaderLanguageTarget() const
+{
+	if (gl.isCoreProfile())
+		return Shader::LANGUAGE_GLSL3;
+	else if (GLAD_ES_VERSION_3_0)
+		return Shader::LANGUAGE_GLSLES3;
+	else if (GLAD_ES_VERSION_2_0)
+		return Shader::LANGUAGE_GLSLES1;
+	else
+		return Shader::LANGUAGE_GLSL1;
+}
+
 } // opengl
 } // graphics
 } // love

+ 5 - 0
src/modules/graphics/opengl/Graphics.h

@@ -129,9 +129,12 @@ public:
 
 	bool isSupported(Feature feature) const override;
 	double getSystemLimit(SystemLimit limittype) const override;
+	Renderer getRenderer() const override;
 	RendererInfo getRendererInfo() const override;
 	Stats getStats() const override;
 
+	Shader::Language getShaderLanguageTarget() const override;
+
 private:
 
 	struct CachedRenderbuffer
@@ -143,6 +146,8 @@ private:
 		GLuint renderbuffer;
 	};
 
+	love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override;
+
 	void endPass();
 	void bindCachedFBO(const std::vector<love::graphics::Canvas *> &canvases);
 	void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);

+ 5 - 10
src/modules/graphics/opengl/Shader.cpp

@@ -37,7 +37,7 @@ namespace opengl
 {
 
 Shader::Shader(const ShaderSource &source)
-	: shaderSource(source)
+	: love::graphics::Shader(source)
 	, program(0)
 	, builtinUniforms()
 	, builtinAttributes()
@@ -46,9 +46,6 @@ Shader::Shader(const ShaderSource &source)
 	, lastPointSize(0.0f)
 	, videoTextureUnits()
 {
-	if (source.vertex.empty() && source.pixel.empty())
-		throw love::Exception("Cannot create shader: no source code!");
-
 	// load shader source and create program object
 	loadVolatile();
 }
@@ -360,14 +357,12 @@ bool Shader::loadVolatile()
 
 	std::vector<GLuint> shaderids;
 
-	bool gammacorrect = graphics::isGammaCorrect();
-	const ShaderSource *defaults = &Graphics::defaultShaderCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
-	if (GLAD_ES_VERSION_2_0)
-		defaults = &Graphics::defaultShaderCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
+	auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
+	const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode();
 
 	// The shader program must have both vertex and pixel shader stages.
-	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
-	const std::string &pixelcode = shaderSource.pixel.empty() ? defaults->pixel : shaderSource.pixel;
+	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults.vertex : shaderSource.vertex;
+	const std::string &pixelcode = shaderSource.pixel.empty() ? defaults.pixel : shaderSource.pixel;
 
 	try
 	{

+ 0 - 3
src/modules/graphics/opengl/Shader.h

@@ -102,9 +102,6 @@ private:
 	// Get any warnings or errors generated only by the shader program object.
 	std::string getProgramWarnings() const;
 
-	// Source code used for this Shader.
-	ShaderSource shaderSource;
-
 	// Shader compiler warning strings for individual shader stages.
 	std::map<ShaderStage, std::string> shaderWarnings;
 

+ 367 - 0
src/modules/graphics/opengl/StreamBuffer.cpp

@@ -0,0 +1,367 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "StreamBuffer.h"
+#include "OpenGL.h"
+#include "BufferSync.h"
+#include "graphics/Volatile.h"
+#include "common/Exception.h"
+
+#include <vector>
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+static int BUFFER_FRAMES = 3;
+
+class StreamBufferClientMemory final : public love::graphics::StreamBuffer
+{
+public:
+
+	StreamBufferClientMemory(BufferType mode, size_t size)
+		: love::graphics::StreamBuffer(mode, size)
+		, data(nullptr)
+	{
+		try
+		{
+			data = new uint8[size];
+		}
+		catch (std::exception &)
+		{
+			throw love::Exception("Out of memory.");
+		}
+	}
+
+	virtual ~StreamBufferClientMemory()
+	{
+		delete[] data;
+	}
+
+	MapInfo map(size_t /*minsize*/) override
+	{
+		return MapInfo(data, bufferSize);
+	}
+
+	size_t unmap(size_t /*usedsize*/) override
+	{
+		return (size_t) data;
+	}
+
+	void markUsed(size_t /*usedsize*/) override { }
+	ptrdiff_t getHandle() const override { return 0; }
+
+private:
+
+	uint8 *data;
+
+}; // StreamBufferClientMemory
+
+class StreamBufferSubDataOrphan : public love::graphics::StreamBuffer, public Volatile
+{
+public:
+
+	StreamBufferSubDataOrphan(BufferType mode, size_t size)
+		: love::graphics::StreamBuffer(mode, size)
+		, vbo(0)
+		, glMode(OpenGL::getGLBufferType(mode))
+		, data(nullptr)
+		, offset(0)
+	{
+		try
+		{
+			data = new uint8[size];
+		}
+		catch (std::exception &)
+		{
+			throw love::Exception("Out of memory.");
+		}
+
+		loadVolatile();
+	}
+
+	virtual ~StreamBufferSubDataOrphan()
+	{
+		unloadVolatile();
+		delete[] data;
+	}
+
+	MapInfo map(size_t minsize) override
+	{
+		if (offset + minsize > bufferSize)
+		{
+			offset = 0;
+			glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
+		}
+
+		return MapInfo(data, bufferSize - offset);
+	}
+
+	size_t unmap(size_t usedsize) override
+	{
+		gl.bindBuffer(mode, vbo);
+		glBufferSubData(glMode, offset, usedsize, data);
+		return offset;
+	}
+
+	void markUsed(size_t usedsize) override
+	{
+		offset += usedsize;
+	}
+
+	ptrdiff_t getHandle() const override { return vbo; }
+
+	bool loadVolatile() override
+	{
+		if (vbo != 0)
+			return true;
+
+		glGenBuffers(1, &vbo);
+		gl.bindBuffer(mode, vbo);
+		glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
+
+		offset = 0;
+
+		return true;
+	}
+
+	void unloadVolatile() override
+	{
+		if (vbo == 0)
+			return;
+
+		gl.deleteBuffer(vbo);
+		vbo = 0;
+	}
+
+protected:
+
+	GLuint vbo;
+	GLenum glMode;
+
+	uint8 *data;
+
+	size_t offset;
+
+}; // StreamBufferSubDataOrphan
+
+class StreamBufferMapSync final : public love::graphics::StreamBuffer, public Volatile
+{
+public:
+
+	StreamBufferMapSync(BufferType type, size_t size)
+		: love::graphics::StreamBuffer(type, size)
+		, vbo(0)
+		, gpuReadOffset(0)
+		, glMode(OpenGL::getGLBufferType(mode))
+	{
+		loadVolatile();
+	}
+
+	~StreamBufferMapSync()
+	{
+		unloadVolatile();
+	}
+
+	MapInfo map(size_t minsize) override
+	{
+		gl.bindBuffer(mode, vbo);
+
+		if (gpuReadOffset + minsize > bufferSize * BUFFER_FRAMES)
+			gpuReadOffset = 0;
+
+		MapInfo info;
+		info.size = bufferSize - (gpuReadOffset % bufferSize);
+
+		sync.wait(gpuReadOffset, info.size);
+
+		GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
+
+		info.data = (uint8 *) glMapBufferRange(glMode, gpuReadOffset, info.size, flags);
+		return info;
+	}
+
+	size_t unmap(size_t usedsize) override
+	{
+		gl.bindBuffer(mode, vbo);
+		glFlushMappedBufferRange(glMode, 0, usedsize);
+		glUnmapBuffer(glMode);
+
+		return gpuReadOffset;
+	}
+
+	void markUsed(size_t usedsize) override
+	{
+		sync.lock(gpuReadOffset, usedsize);
+		gpuReadOffset += usedsize;
+	}
+
+	ptrdiff_t getHandle() const override { return vbo; }
+
+	bool loadVolatile() override
+	{
+		if (vbo != 0)
+			return true;
+
+		glGenBuffers(1, &vbo);
+		gl.bindBuffer(mode, vbo);
+		glBufferData(glMode, bufferSize * BUFFER_FRAMES, nullptr, GL_STREAM_DRAW);
+
+		gpuReadOffset = 0;
+
+		return true;
+	}
+
+	void unloadVolatile() override
+	{
+		if (vbo == 0)
+			return;
+
+		gl.deleteBuffer(vbo);
+		vbo = 0;
+
+		sync.cleanup();
+	}
+
+private:
+
+	GLuint vbo;
+	size_t gpuReadOffset;
+	GLenum glMode;
+
+	BufferSync sync;
+
+}; // StreamBufferMapSync
+
+class StreamBufferPersistentMapSync final : public love::graphics::StreamBuffer, public Volatile
+{
+public:
+
+	StreamBufferPersistentMapSync(BufferType type, size_t size)
+		: love::graphics::StreamBuffer(type, size)
+		, vbo(0)
+		, gpuReadOffset(0)
+		, glMode(OpenGL::getGLBufferType(mode))
+		, data(nullptr)
+	{
+		loadVolatile();
+	}
+
+	~StreamBufferPersistentMapSync()
+	{
+		unloadVolatile();
+	}
+
+	MapInfo map(size_t minsize) override
+	{
+		if (gpuReadOffset + minsize > bufferSize * BUFFER_FRAMES)
+			gpuReadOffset = 0;
+
+		MapInfo info;
+		info.size = bufferSize - (gpuReadOffset % bufferSize);
+		info.data = data + gpuReadOffset;
+
+		sync.wait(gpuReadOffset, info.size);
+
+		return info;
+	}
+
+	size_t unmap(size_t usedsize) override
+	{
+		gl.bindBuffer(mode, vbo);
+		glFlushMappedBufferRange(glMode, gpuReadOffset, usedsize);
+
+		return gpuReadOffset;
+	}
+
+	void markUsed(size_t usedsize) override
+	{
+		sync.lock(gpuReadOffset, usedsize);
+		gpuReadOffset += usedsize;
+	}
+
+	ptrdiff_t getHandle() const override { return vbo; }
+
+	bool loadVolatile() override
+	{
+		if (vbo != 0)
+			return true;
+
+		glGenBuffers(1, &vbo);
+		gl.bindBuffer(mode, vbo);
+
+		GLbitfield storageflags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
+		GLbitfield mapflags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+
+		glBufferStorage(glMode, bufferSize * BUFFER_FRAMES, nullptr, storageflags);
+		data = (uint8 *) glMapBufferRange(glMode, 0, bufferSize * BUFFER_FRAMES, mapflags);
+
+		gpuReadOffset = 0;
+
+		return true;
+	}
+
+	void unloadVolatile() override
+	{
+		if (vbo == 0)
+			return;
+
+		gl.bindBuffer(mode, vbo);
+		glUnmapBuffer(glMode);
+		gl.deleteBuffer(vbo);
+		vbo = 0;
+
+		sync.cleanup();
+	}
+
+private:
+	
+	GLuint vbo;
+	size_t gpuReadOffset;
+	GLenum glMode;
+	uint8 *data;
+	
+	BufferSync sync;
+	
+}; // StreamBufferPersistentMapSync
+
+love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size)
+{
+	if (gl.isCoreProfile())
+	{
+		// FIXME: This is disabled until more efficient manual syncing can be
+		// implemented.
+#if 0
+		if (GLAD_VERSION_4_4 || GLAD_ARB_buffer_storage)
+			return new StreamBufferPersistentMapSync(mode, size);
+		else
+#endif
+			return new StreamBufferSubDataOrphan(mode, size);
+	}
+	else
+		return new StreamBufferClientMemory(mode, size);
+}
+
+} // opengl
+} // graphics
+} // love

+ 36 - 0
src/modules/graphics/opengl/StreamBuffer.h

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+#include "graphics/StreamBuffer.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size);
+
+} // opengl
+} // graphics
+} // love

+ 63 - 22
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -720,15 +720,12 @@ int w_newCanvas(lua_State *L)
 	return 1;
 }
 
-int w_newShader(lua_State *L)
+static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::ShaderSource &source)
 {
 	luax_checkgraphicscreated(L);
 
-	// clamp stack to 2 elements
-	lua_settop(L, 2);
-
 	// read any filepath arguments
-	for (int i = 1; i <= 2; i++)
+	for (int i = startidx; i < startidx + 2; i++)
 	{
 		if (!lua_isstring(L, i))
 			continue;
@@ -763,25 +760,32 @@ int w_newShader(lua_State *L)
 		}
 	}
 
-	bool has_arg1 = lua_isstring(L, 1) != 0;
-	bool has_arg2 = lua_isstring(L, 2) != 0;
+	bool has_arg1 = lua_isstring(L, startidx + 0) != 0;
+	bool has_arg2 = lua_isstring(L, startidx + 1) != 0;
 
 	// require at least one string argument
 	if (!(has_arg1 || has_arg2))
-		luaL_checkstring(L, 1);
+		luaL_checkstring(L, startidx);
 
 	luax_getfunction(L, "graphics", "_shaderCodeToGLSL");
 
 	// push vertexcode and pixelcode strings to the top of the stack
-	lua_pushvalue(L, 1);
-	lua_pushvalue(L, 2);
+	lua_pushboolean(L, gles);
+
+	if (has_arg1)
+		lua_pushvalue(L, startidx + 0);
+	else
+		lua_pushnil(L);
+
+	if (has_arg2)
+		lua_pushvalue(L, startidx + 1);
+	else
+		lua_pushnil(L);
 
 	// call effectCodeToGLSL, returned values will be at the top of the stack
-	if (lua_pcall(L, 2, 2, 0) != 0)
+	if (lua_pcall(L, 3, 2, 0) != 0)
 		return luaL_error(L, "%s", lua_tostring(L, -1));
 
-	Shader::ShaderSource source;
-
 	// vertex shader code
 	if (lua_isstring(L, -2))
 		source.vertex = luax_checkstring(L, -2);
@@ -797,13 +801,23 @@ int w_newShader(lua_State *L)
 	if (source.vertex.empty() && source.pixel.empty())
 	{
 		// Original args had source code, but effectCodeToGLSL couldn't translate it
-		for (int i = 1; i <= 2; i++)
+		for (int i = startidx; i < startidx + 2; i++)
 		{
 			if (lua_isstring(L, i))
 				return luaL_argerror(L, i, "missing 'position' or 'effect' function?");
 		}
 	}
 
+	return 0;
+}
+
+int w_newShader(lua_State *L)
+{
+	bool gles = instance()->getRenderer() == Graphics::RENDERER_OPENGLES;
+
+	Shader::ShaderSource source;
+	w_getShaderSource(L, 1, gles, source);
+
 	bool should_error = false;
 	try
 	{
@@ -827,6 +841,28 @@ int w_newShader(lua_State *L)
 	return 1;
 }
 
+int w_validateShader(lua_State *L)
+{
+	luaL_checktype(L, 1, LUA_TBOOLEAN);
+	bool gles = luax_toboolean(L, 1);
+
+	Shader::ShaderSource source;
+	w_getShaderSource(L, 2, gles, source);
+
+	std::string err;
+	bool success = instance()->validateShader(gles, source, err);
+
+	luax_pushboolean(L, success);
+
+	if (!success)
+	{
+		luax_pushstring(L, err);
+		return 2;
+	}
+
+	return 1;
+}
+
 static vertex::Usage luax_optmeshusage(lua_State *L, int idx, vertex::Usage def)
 {
 	const char *usagestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
@@ -1428,16 +1464,17 @@ int w_getShader(lua_State *L)
 
 int w_setDefaultShaderCode(lua_State *L)
 {
-	luaL_checktype(L, 1, LUA_TTABLE);
-	luaL_checktype(L, 2, LUA_TTABLE);
-
 	for (int i = 0; i < 2; i++)
 	{
-		for (int renderer = 0; renderer < Graphics::RENDERER_MAX_ENUM; renderer++)
+		luaL_checktype(L, i + 1, LUA_TTABLE);
+
+		for (int lang = 0; lang < Shader::LANGUAGE_MAX_ENUM; lang++)
 		{
-			const char *lang = renderer == Graphics::RENDERER_OPENGLES ? "glsles" : "glsl";
+			const char *langname;
+			if (!Shader::getConstant((Shader::Language) lang, langname))
+				continue;
 
-			lua_getfield(L, i + 1, lang);
+			lua_getfield(L, i + 1, langname);
 
 			lua_getfield(L, -1, "vertex");
 			lua_getfield(L, -2, "pixel");
@@ -1453,8 +1490,8 @@ int w_setDefaultShaderCode(lua_State *L)
 
 			lua_pop(L, 4);
 
-			Graphics::defaultShaderCode[renderer][i] = code;
-			Graphics::defaultVideoShaderCode[renderer][i] = videocode;
+			Graphics::defaultShaderCode[lang][i] = code;
+			Graphics::defaultVideoShaderCode[lang][i] = videocode;
 		}
 	}
 
@@ -2111,6 +2148,8 @@ static const luaL_Reg functions[] =
 	{ "newText", w_newText },
 	{ "_newVideo", w_newVideo },
 
+	{ "validateShader", w_validateShader },
+
 	{ "setCanvas", w_setCanvas },
 	{ "getCanvas", w_getCanvas },
 
@@ -2248,6 +2287,8 @@ extern "C" int luaopen_love_graphics(lua_State *L)
 
 	if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "wrap_Graphics.lua") == 0)
 		lua_call(L, 0, 0);
+	else
+		lua_error(L);
 
 	return n;
 }

+ 127 - 69
src/modules/graphics/opengl/wrap_Graphics.lua

@@ -29,19 +29,20 @@ local ipairs = ipairs
 
 local GLSL = {}
 
-GLSL.VERSION = "#version 120"
-GLSL.VERSION_ES = "#version 100"
+GLSL.VERSION = { -- index using [target][gles]
+	glsl1 = {[false]="#version 120",      [true]="#version 100"},
+	glsl3 = {[false]="#version 330 core", [true]="#version 300 es"},
+}
 
 GLSL.SYNTAX = [[
-#ifndef GL_ES
-#define lowp
-#define mediump
-#define highp
+#if !defined(GL_ES) && __VERSION__ < 140
+	#define lowp
+	#define mediump
+	#define highp
 #endif
 #define number float
 #define Image sampler2D
 #define extern uniform
-#define Texel texture2D
 #pragma optionNV(strict on)]]
 
 -- Uniforms shared by the vertex and pixel shader stages.
@@ -50,9 +51,9 @@ GLSL.UNIFORMS = [[
 // but we can't guarantee that highp is always supported in fragment shaders...
 // We *really* don't want to use mediump for these in vertex shaders though.
 #if defined(VERTEX) || defined(GL_FRAGMENT_PRECISION_HIGH)
-#define LOVE_UNIFORM_PRECISION highp
+	#define LOVE_UNIFORM_PRECISION highp
 #else
-#define LOVE_UNIFORM_PRECISION mediump
+	#define LOVE_UNIFORM_PRECISION mediump
 #endif
 uniform LOVE_UNIFORM_PRECISION mat4 TransformMatrix;
 uniform LOVE_UNIFORM_PRECISION mat4 ProjectionMatrix;
@@ -61,6 +62,22 @@ uniform LOVE_UNIFORM_PRECISION mat3 NormalMatrix;
 uniform mediump vec4 love_ScreenSize;]]
 
 GLSL.FUNCTIONS = [[
+#if __VERSION__ >= 130 && !defined(LOVE_GLSL1_ON_GLSL3)
+	#define Texel texture
+#else
+	#if __VERSION__ >= 130
+		#define texture2D Texel
+		#define love_texture2D texture
+	#else
+		#define love_texture2D texture2D
+	#endif
+	vec4 Texel(sampler2D s, vec2 c) { return love_texture2D(s, c); }
+	#ifdef PIXEL
+		vec4 Texel(sampler2D s, vec2 c, float b) { return love_texture2D(s, c, b); }
+	#endif
+	#define texture love_texture
+#endif
+
 float gammaToLinearPrecise(float c) {
 	return c <= 0.04045 ? c * 0.077399380804954 : pow((c + 0.055) * 0.9478672985782, 2.4);
 }
@@ -93,45 +110,52 @@ mediump vec3 linearToGammaFast(mediump vec3 c) { return pow(max(c, vec3(0.0)), v
 mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c.rgb), c.a); }
 
 #ifdef LOVE_PRECISE_GAMMA
-#define gammaToLinear gammaToLinearPrecise
-#define linearToGamma linearToGammaPrecise
+	#define gammaToLinear gammaToLinearPrecise
+	#define linearToGamma linearToGammaPrecise
 #else
-#define gammaToLinear gammaToLinearFast
-#define linearToGamma linearToGammaFast
+	#define gammaToLinear gammaToLinearFast
+	#define linearToGamma linearToGammaFast
 #endif
 
 #ifdef LOVE_GAMMA_CORRECT
-#define gammaCorrectColor gammaToLinear
-#define unGammaCorrectColor linearToGamma
-#define gammaCorrectColorPrecise gammaToLinearPrecise
-#define unGammaCorrectColorPrecise linearToGammaPrecise
-#define gammaCorrectColorFast gammaToLinearFast
-#define unGammaCorrectColorFast linearToGammaFast
+	#define gammaCorrectColor gammaToLinear
+	#define unGammaCorrectColor linearToGamma
+	#define gammaCorrectColorPrecise gammaToLinearPrecise
+	#define unGammaCorrectColorPrecise linearToGammaPrecise
+	#define gammaCorrectColorFast gammaToLinearFast
+	#define unGammaCorrectColorFast linearToGammaFast
 #else
-#define gammaCorrectColor
-#define unGammaCorrectColor
-#define gammaCorrectColorPrecise
-#define unGammaCorrectColorPrecise
-#define gammaCorrectColorFast
-#define unGammaCorrectColorFast
+	#define gammaCorrectColor
+	#define unGammaCorrectColor
+	#define gammaCorrectColorPrecise
+	#define unGammaCorrectColorPrecise
+	#define gammaCorrectColorFast
+	#define unGammaCorrectColorFast
 #endif]]
 
 GLSL.VERTEX = {
 	HEADER = [[
-#define VERTEX
 #define LOVE_PRECISE_GAMMA
 
+#if __VERSION__ >= 130
+	#define attribute in
+	#define varying out
+	#ifndef LOVE_GLSL1_ON_GLSL3
+		#define love_VertexID gl_VertexID
+	#endif
+#endif
+
+#ifdef GL_ES
+	uniform mediump float love_PointSize;
+#endif
+
 attribute vec4 VertexPosition;
 attribute vec4 VertexTexCoord;
 attribute vec4 VertexColor;
 attribute vec4 ConstantColor;
 
 varying vec4 VaryingTexCoord;
-varying vec4 VaryingColor;
-
-#ifdef GL_ES
-uniform mediump float love_PointSize;
-#endif]],
+varying vec4 VaryingColor;]],
 
 	FUNCTIONS = "",
 
@@ -148,26 +172,39 @@ void main() {
 
 GLSL.PIXEL = {
 	HEADER = [[
-#define PIXEL
-
 #ifdef GL_ES
-precision mediump float;
+	precision mediump float;
 #endif
 
-varying mediump vec4 VaryingTexCoord;
-varying mediump vec4 VaryingColor;
+#define love_MaxCanvases gl_MaxDrawBuffers
 
-#define love_Canvases gl_FragData
+#if __VERSION__ >= 130
+	#define varying in
+	#ifdef LOVE_MULTI_CANVAS
+		layout(location = 0) out vec4 love_Canvases[love_MaxCanvases];
+	#else
+		layout(location = 0) out vec4 love_PixelColor;
+	#endif
+#else
+	#ifdef LOVE_MULTI_CANVAS
+		#define love_Canvases gl_FragData
+	#else
+		#define love_PixelColor gl_FragColor
+	#endif
+#endif
+
+// See Shader::checkSetScreenParams in Shader.cpp.
+#define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))
 
-uniform sampler2D _tex0_;]],
+varying mediump vec4 VaryingTexCoord;
+varying mediump vec4 VaryingColor;]],
 
 	FUNCTIONS = [[
 uniform sampler2D love_VideoYChannel;
 uniform sampler2D love_VideoCbChannel;
 uniform sampler2D love_VideoCrChannel;
 
-vec4 VideoTexel(vec2 texcoords)
-{
+vec4 VideoTexel(vec2 texcoords) {
 	vec3 yuv;
 	yuv[0] = Texel(love_VideoYChannel, texcoords).r;
 	yuv[1] = Texel(love_VideoCbChannel, texcoords).r;
@@ -184,39 +221,37 @@ vec4 VideoTexel(vec2 texcoords)
 }]],
 
 	FOOTER = [[
+uniform sampler2D MainTexture;
 void main() {
-	// fix crashing issue in OSX when _tex0_ is unused within effect()
-	float dummy = Texel(_tex0_, vec2(.5)).r;
-
-	// See Shader::checkSetScreenParams in Shader.cpp.
-	vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w);
-
-	gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord);
+	love_PixelColor = effect(VaryingColor, MainTexture, VaryingTexCoord.st, love_PixelCoord);
 }]],
 
 	FOOTER_MULTI_CANVAS = [[
+uniform sampler2D MainTexture;
 void main() {
-	// fix crashing issue in OSX when _tex0_ is unused within effect()
-	float dummy = Texel(_tex0_, vec2(.5)).r;
-
-	// See Shader::checkSetScreenParams in Shader.cpp.
-	vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w);
-
-	effects(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord);
+	effects(VaryingColor, MainTexture, VaryingTexCoord.st, love_PixelCoord);
 }]],
 }
 
-local function createShaderStageCode(stage, code, lang, gammacorrect, multicanvas)
+local function getLanguageTarget(code)
+	if not code then return nil end
+	return (code:match("^%s*#pragma language (%w+)")) or "glsl1"
+end
+
+local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, multicanvas)
 	stage = stage:upper()
 	local lines = {
-		lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION,
-		GLSL.SYNTAX,
+		GLSL.VERSION[lang][gles],
+		"#define "..stage,
+		glsl1on3 and "#define LOVE_GLSL1_ON_GLSL3 1" or "",
 		gammacorrect and "#define LOVE_GAMMA_CORRECT 1" or "",
+		multicanvas and "#define LOVE_MULTI_CANVAS 1" or "",
+		GLSL.SYNTAX,
 		GLSL[stage].HEADER,
 		GLSL.UNIFORMS,
 		GLSL.FUNCTIONS,
 		GLSL[stage].FUNCTIONS,
-		lang == "glsles" and "#line 1" or "#line 0",
+		(lang == "glsl3" or gles) and "#line 1" or "#line 0",
 		code,
 		multicanvas and GLSL[stage].FOOTER_MULTI_CANVAS or GLSL[stage].FOOTER,
 	}
@@ -238,7 +273,7 @@ local function isPixelCode(code)
 	end
 end
 
-function love.graphics._shaderCodeToGLSL(arg1, arg2)
+function love.graphics._shaderCodeToGLSL(gles, arg1, arg2)
 	local vertexcode, pixelcode
 	local is_multicanvas = false -- whether pixel code has "effects" function instead of "effect"
 
@@ -266,18 +301,34 @@ function love.graphics._shaderCodeToGLSL(arg1, arg2)
 		end
 	end
 
-	local lang = "glsl"
-	if love.graphics.getRendererInfo() == "OpenGL ES" then
-		lang = "glsles"
+	local supportsGLSL3 = love.graphics.getSupported().glsl3
+	local gammacorrect = love.graphics.isGammaCorrect()
+
+	local targetlang = getLanguageTarget(pixelcode or vertexcode)
+	if getLanguageTarget(vertexcode or pixelcode) ~= targetlang then
+		error("vertex and pixel shader languages must match", 2)
 	end
 
-	local gammacorrect = love.graphics.isGammaCorrect()
+	if targetlang == "glsl3" and not supportsGLSL3 then
+		error("GLSL 3 shaders are not supported on this system!", 2)
+	end
+
+	if targetlang ~= nil and not GLSL.VERSION[targetlang] then
+		error("Invalid shader language: " .. targetlang, 2)
+	end
+
+	local lang = targetlang or "glsl1"
+	local glsl1on3 = false
+	if lang == "glsl1" and supportsGLSL3 then
+		lang = "glsl3"
+		glsl1on3 = true
+	end
 
 	if vertexcode then
-		vertexcode = createShaderStageCode("VERTEX", vertexcode, lang, gammacorrect)
+		vertexcode = createShaderStageCode("VERTEX", vertexcode, lang, gles, glsl1on3, gammacorrect)
 	end
 	if pixelcode then
-		pixelcode = createShaderStageCode("PIXEL", pixelcode, lang, gammacorrect, is_multicanvas)
+		pixelcode = createShaderStageCode("PIXEL", pixelcode, lang, gles, glsl1on3, gammacorrect, is_multicanvas)
 	end
 
 	return vertexcode, pixelcode
@@ -328,13 +379,20 @@ vec4 effect(mediump vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
 local defaults = {}
 local defaults_gammacorrect = {}
 
-for _, lang in ipairs{"glsl", "glsles"} do
+local langs = {
+	glsl1   = {target="glsl1", gles=false},
+	glsles1 = {target="glsl1", gles=true},
+	glsl3   = {target="glsl3", gles=false},
+	glsles3 = {target="glsl3", gles=true},
+}
+
+for lang, info in pairs(langs) do
 	for _, gammacorrect in ipairs{false, true} do
 		local t = gammacorrect and defaults_gammacorrect or defaults
 		t[lang] = {
-			vertex = createShaderStageCode("VERTEX", defaultcode.vertex, lang, gammacorrect),
-			pixel = createShaderStageCode("PIXEL", defaultcode.pixel, lang, gammacorrect, false),
-			videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, lang, gammacorrect, false),
+			vertex = createShaderStageCode("VERTEX", defaultcode.vertex, info.target, info.gles, false, gammacorrect),
+			pixel = createShaderStageCode("PIXEL", defaultcode.pixel, info.target, info.gles, false, gammacorrect, false),
+			videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, info.target, info.gles, false, gammacorrect, false),
 		}
 	end
 end

+ 22 - 21
src/modules/window/sdl/Window.cpp

@@ -131,6 +131,8 @@ void Window::setGLContextAttributes(const ContextAttribs &attribs)
 
 	if (attribs.gles)
 		profilemask = SDL_GL_CONTEXT_PROFILE_ES;
+	else if (attribs.versionMajor * 10 + attribs.versionMinor >= 32)
+		profilemask |= SDL_GL_CONTEXT_PROFILE_CORE;
 	else if (attribs.debug)
 		profilemask = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
 
@@ -236,34 +238,33 @@ std::vector<Window::ContextAttribs> Window::getContextAttribsList() const
 	const char *debughint = SDL_GetHint("LOVE_GRAPHICS_DEBUG");
 	bool debug = (debughint != nullptr && debughint[0] != '0');
 
-	// Different context attribute profiles to try.
-	std::vector<ContextAttribs> attribslist = {
-		{2, 1, false, debug}, // OpenGL 2.1.
-		{3, 0, true,  debug}, // OpenGL ES 3.
-		{2, 0, true,  debug}, // OpenGL ES 2.
-	};
+	const char *preferGL2hint = SDL_GetHint("LOVE_GRAPHICS_USE_GL2");
+	bool preferGL2 = (preferGL2hint != nullptr && preferGL2hint[0] != '0');
 
-	// OpenGL ES 3+ contexts are only properly supported in SDL 2.0.4+.
-	bool removeES3 = hasSDL203orEarlier;
+	std::vector<ContextAttribs> glcontexts = {{2, 1, false, debug}};
+	glcontexts.insert(preferGL2 ? glcontexts.end() : glcontexts.begin(), {3, 3, false, debug});
+
+	std::vector<ContextAttribs> glescontexts = {{2, 0, true, debug}};
 
 	// While UWP SDL is above 2.0.4, it still doesn't support OpenGL ES 3+
-#ifdef LOVE_WINDOWS_UWP
-	removeES3 = true;
+#ifndef LOVE_WINDOWS_UWP
+	// OpenGL ES 3+ contexts are only properly supported in SDL 2.0.4+.
+	if (!hasSDL203orEarlier)
+		glescontexts.insert(preferGL2 ? glescontexts.end() : glescontexts.begin(), {3, 0, true, debug});
 #endif
 
-	if (removeES3)
-	{
-		auto it = std::remove_if(attribslist.begin(), attribslist.end(), [](ContextAttribs a)
-		{
-			return a.gles && a.versionMajor >= 3;
-		});
+	std::vector<ContextAttribs> attribslist;
 
-		attribslist.erase(it, attribslist.end());
-	}
-
-	// Move OpenGL ES to the front of the list if we should prefer GLES.
 	if (preferGLES)
-		std::rotate(attribslist.begin(), attribslist.begin() + 1, attribslist.end());
+	{
+		attribslist.insert(attribslist.end(), glescontexts.begin(), glescontexts.end());
+		attribslist.insert(attribslist.end(), glcontexts.begin(), glcontexts.end());
+	}
+	else
+	{
+		attribslist.insert(attribslist.end(), glcontexts.begin(), glcontexts.end());
+		attribslist.insert(attribslist.end(), glescontexts.begin(), glescontexts.end());
+	}
 
 	return attribslist;
 }