Merge remote-tracking branch 'aosp/master-ndk' into merge-shaderc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33b4764..e7b22e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,9 @@
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 option(ENABLE_AMD_EXTENSIONS "Enables support of AMD-specific extensions" ON)
+option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" ON)
+
+option(ENABLE_NV_EXTENSIONS "Enables support of Nvidia-specific extensions" ON)
 
 enable_testing()
 
@@ -13,6 +16,10 @@
     add_definitions(-DAMD_EXTENSIONS)
 endif(ENABLE_AMD_EXTENSIONS)
 
+if(ENABLE_NV_EXTENSIONS)
+    add_definitions(-DNV_EXTENSIONS)
+endif(ENABLE_NV_EXTENSIONS)
+
 if(WIN32)
     set(CMAKE_DEBUG_POSTFIX "d")
     include(ChooseMSVCCRT.cmake)
@@ -52,7 +59,9 @@
 
 add_subdirectory(glslang)
 add_subdirectory(OGLCompilersDLL)
-add_subdirectory(StandAlone)
+if(ENABLE_GLSLANG_BINARIES)
+	add_subdirectory(StandAlone)
+endif()
 add_subdirectory(SPIRV)
 add_subdirectory(hlsl)
 add_subdirectory(gtests)
diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt
index 2c65d71..c538e84 100755
--- a/SPIRV/CMakeLists.txt
+++ b/SPIRV/CMakeLists.txt
@@ -33,6 +33,11 @@
          GLSL.ext.AMD.h)
 endif(ENABLE_AMD_EXTENSIONS)
 
+if(ENABLE_NV_EXTENSIONS)
+    set(HEADERS
+        GLSL.ext.NV.h)
+endif(ENABLE_NV_EXTENSIONS)
+
 add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
 set_property(TARGET SPIRV PROPERTY FOLDER glslang)
 
diff --git a/SPIRV/GLSL.ext.NV.h b/SPIRV/GLSL.ext.NV.h
new file mode 100644
index 0000000..adfcb0f
--- /dev/null
+++ b/SPIRV/GLSL.ext.NV.h
@@ -0,0 +1,49 @@
+/*
+** Copyright (c) 2014-2016 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.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
+**
+** 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.
+*/
+
+#ifndef GLSLextNV_H
+#define GLSLextNV_H
+
+enum BuiltIn;
+enum Decoration;
+enum Op;
+
+static const int GLSLextNVVersion = 100;
+static const int GLSLextNVRevision = 2;
+
+//SPV_NV_sample_mask_override_coverage
+const char* const E_SPV_NV_sample_mask_override_coverage = "SPV_NV_sample_mask_override_coverage";
+
+static const Decoration OverrideCoverageNV = static_cast<Decoration>(5248);
+
+
+//SPV_NV_geometry_shader_passthrough
+const char* const E_SPV_NV_geometry_shader_passthrough = "SPV_NV_geometry_shader_passthrough";
+
+static const Decoration PassthroughNV = static_cast<Decoration>(5250);
+
+static const Capability GeometryShaderPassthroughNV = static_cast<Capability>(5251);
+#endif  // #ifndef GLSLextNV_H
\ No newline at end of file
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 15af947..3c287a7 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -47,6 +47,9 @@
 #ifdef AMD_EXTENSIONS
     #include "GLSL.ext.AMD.h"
 #endif
+#ifdef NV_EXTENSIONS
+    #include "GLSL.ext.NV.h"
+#endif
 }
 
 // Glslang includes
@@ -436,6 +439,7 @@
         return spv::DecorationMax;
 }
 
+
 // Translate a glslang built-in variable to a SPIR-V built in decoration.  Also generate
 // associated capabilities when required.  For some built-in variables, a capability
 // is generated only when using the variable in an executable instruction, but not when
@@ -4127,7 +4131,8 @@
     spv::Op opCode = spv::OpNop;
 
     std::vector<spv::Id> spvGroupOperands;
-    if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation) {
+    if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||
+        op == glslang::EOpReadInvocation) {
         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
     } else {
@@ -4167,7 +4172,7 @@
     }
 
     case glslang::EOpReadInvocation:
-        opCode = spv::OpGroupBroadcast;
+        opCode = spv::OpSubgroupReadInvocationKHR;
         if (builder.isVectorType(typeId))
             return CreateInvocationsVectorOperation(opCode, typeId, operands);
         break;
@@ -4279,13 +4284,15 @@
     assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||
            op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
            op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
+           op == spv::OpSubgroupReadInvocationKHR ||
            op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD ||
            op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || op == spv::OpGroupSMaxNonUniformAMD ||
            op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);
 #else
     assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||
            op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
-           op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast);
+           op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
+           op == spv::OpSubgroupReadInvocationKHR);
 #endif
 
     // Handle group invocation operations scalar by scalar.
@@ -4305,13 +4312,16 @@
         std::vector<unsigned int> indexes;
         indexes.push_back(comp);
         spv::Id scalar = builder.createCompositeExtract(operands[0], scalarType, indexes);
-
         std::vector<spv::Id> spvGroupOperands;
-        spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
-        if (op == spv::OpGroupBroadcast) {
+        if (op == spv::OpSubgroupReadInvocationKHR) {
+            spvGroupOperands.push_back(scalar);
+            spvGroupOperands.push_back(operands[1]);
+        } else if (op == spv::OpGroupBroadcast) {
+            spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
             spvGroupOperands.push_back(scalar);
             spvGroupOperands.push_back(operands[1]);
         } else {
+            spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
             spvGroupOperands.push_back(spv::GroupOperationReduce);
             spvGroupOperands.push_back(scalar);
         }
@@ -4721,6 +4731,26 @@
     if (builtIn != spv::BuiltInMax)
         addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
 
+#ifdef NV_EXTENSIONS 
+    if (builtIn == spv::BuiltInSampleMask) {
+          spv::Decoration decoration;
+          // GL_NV_sample_mask_override_coverage extension
+          if (glslangIntermediate->getLayoutOverrideCoverage())
+              decoration = (spv::Decoration)spv::OverrideCoverageNV;
+          else
+              decoration = (spv::Decoration)spv::DecorationMax;
+        addDecoration(id, decoration);
+        if (decoration != spv::DecorationMax) {
+            builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
+        }
+    }
+    if (symbol->getQualifier().layoutPassthrough) {
+        addDecoration(id, spv::PassthroughNV);
+        builder.addCapability(spv::GeometryShaderPassthroughNV);
+        builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
+    }
+#endif
+
     return id;
 }
 
diff --git a/SPIRV/SPVRemapper.cpp b/SPIRV/SPVRemapper.cpp
index 5c551fb..f30963b 100755
--- a/SPIRV/SPVRemapper.cpp
+++ b/SPIRV/SPVRemapper.cpp
@@ -327,12 +327,10 @@
         bound(maxBound); // reset header ID bound to as big as it now needs to be
     }
 
+    // Mark debug instructions for stripping
     void spirvbin_t::stripDebug()
     {
-        if ((options & STRIP) == 0)
-            return;
-
-        // build local Id and name maps
+        // Strip instructions in the stripOp set: debug info.
         process(
             [&](spv::Op opCode, unsigned start) {
                 // remember opcodes we want to strip later
@@ -343,6 +341,32 @@
             op_fn_nop);
     }
 
+    // Mark instructions that refer to now-removed IDs for stripping
+    void spirvbin_t::stripDeadRefs()
+    {
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // strip opcodes pointing to removed data
+                switch (opCode) {
+                case spv::OpName:
+                case spv::OpMemberName:
+                case spv::OpDecorate:
+                case spv::OpMemberDecorate:
+                    if (idPosR.find(asId(start+1)) == idPosR.end())
+                        stripInst(start);
+                    break;
+                default: 
+                    break; // leave it alone
+                }
+
+                return true;
+            },
+            op_fn_nop);
+
+        strip();
+    }
+
+    // Update local maps of ID, type, etc positions
     void spirvbin_t::buildLocalMaps()
     {
         msg(2, 2, std::string("build local maps: "));
@@ -351,7 +375,6 @@
         idMapL.clear();
 //      preserve nameMap, so we don't clear that.
         fnPos.clear();
-        fnPosDCE.clear();
         fnCalls.clear();
         typeConstPos.clear();
         idPosR.clear();
@@ -366,10 +389,6 @@
         // build local Id and name maps
         process(
             [&](spv::Op opCode, unsigned start) {
-                // remember opcodes we want to strip later
-                if ((options & STRIP) && isStripOp(opCode))
-                    stripInst(start);
-
                 unsigned word = start+1;
                 spv::Id  typeId = spv::NoResult;
 
@@ -957,7 +976,6 @@
                 if (call_it == fnCalls.end() || call_it->second == 0) {
                     changed = true;
                     stripRange.push_back(fn->second);
-                    fnPosDCE.insert(*fn);
 
                     // decrease counts of called functions
                     process(
@@ -1011,11 +1029,15 @@
         // Remove single-use function variables + associated decorations and names
         process(
             [&](spv::Op opCode, unsigned start) {
-                if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||
-                    (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||
-                    (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {
-                        stripInst(start);
-                }
+                spv::Id id = spv::NoResult;
+                if (opCode == spv::OpVariable)
+                    id = asId(start+2);
+                if (opCode == spv::OpDecorate || opCode == spv::OpName)
+                    id = asId(start+1);
+
+                if (id != spv::NoResult && varUseCount[id] == 1)
+                    stripInst(start);
+
                 return true;
             },
             op_fn_nop);
@@ -1276,25 +1298,31 @@
         // Set up opcode tables from SpvDoc
         spv::Parameterize();
 
-        validate();  // validate header
-        buildLocalMaps();
+        validate();       // validate header
+        buildLocalMaps(); // build ID maps
 
         msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
 
+        if (options & STRIP)         stripDebug();
         strip();        // strip out data we decided to eliminate
         if (options & OPT_LOADSTORE) optLoadStore();
         if (options & OPT_FWD_LS)    forwardLoadStores();
         if (options & DCE_FUNCS)     dceFuncs();
         if (options & DCE_VARS)      dceVars();
         if (options & DCE_TYPES)     dceTypes();
-        strip();        // strip out data we decided to eliminate
+
+        strip();         // strip out data we decided to eliminate
+        stripDeadRefs(); // remove references to things we DCEed
+        // after the last strip, we must clean any debug info referring to now-deleted data
 
         if (options & MAP_TYPES)     mapTypeConst();
         if (options & MAP_NAMES)     mapNames();
         if (options & MAP_FUNCS)     mapFnBodies();
 
-        mapRemainder(); // map any unmapped IDs
-        applyMap();     // Now remap each shader to the new IDs we've come up with
+        if (options & MAP_ALL) {
+            mapRemainder(); // map any unmapped IDs
+            applyMap();     // Now remap each shader to the new IDs we've come up with
+        }
     }
 
     // remap from a memory image
diff --git a/SPIRV/SPVRemapper.h b/SPIRV/SPVRemapper.h
index b3c686a..77c9658 100755
--- a/SPIRV/SPVRemapper.h
+++ b/SPIRV/SPVRemapper.h
@@ -239,7 +239,8 @@
 
    void        applyMap();            // remap per local name map
    void        mapRemainder();        // map any IDs we haven't touched yet
-   void        stripDebug();          // strip debug info
+   void        stripDebug();          // strip all debug info
+   void        stripDeadRefs();       // strips debug info for now-dead references after DCE
    void        strip();               // remove debug symbols
    
    std::vector<spirword_t> spv;      // SPIR words
@@ -264,7 +265,6 @@
    // Function start and end.  use unordered_map because we'll have
    // many fewer functions than IDs.
    std::unordered_map<spv::Id, range_t> fnPos;
-   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
 
    // Which functions are called, anywhere in the module, with a call count
    std::unordered_map<spv::Id, int> fnCalls;
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 04b0f04..b0b74b2 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -2144,6 +2144,7 @@
         std::vector<unsigned> oldSwizzle = accessChain.swizzle;
         accessChain.swizzle.resize(0);
         for (unsigned int i = 0; i < swizzle.size(); ++i) {
+            assert(swizzle[i] < oldSwizzle.size());
             accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
         }
     } else
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index b1023b9..cbc9a9b 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -54,6 +54,9 @@
 #ifdef AMD_EXTENSIONS
         #include "GLSL.ext.AMD.h"
 #endif
+#ifdef NV_EXTENSIONS
+        #include "GLSL.ext.NV.h"
+#endif
     }
 }
 const char* GlslStd450DebugNames[spv::GLSLstd450Count];
@@ -64,6 +67,10 @@
 static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
 #endif
 
+#ifdef NV_EXTENSIONS
+static const char* GLSLextNVGetDebugNames(const char*, unsigned);
+#endif
+
 static void Kill(std::ostream& out, const char* message)
 {
     out << std::endl << "Disassembly failed: " << message << std::endl;
@@ -76,6 +83,9 @@
 #ifdef AMD_EXTENSIONS
     GLSLextAMDInst,
 #endif
+#ifdef NV_EXTENSIONS
+    GLSLextNVInst,
+#endif
     OpenCLExtInst,
 };
 
@@ -470,6 +480,11 @@
                            strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
                     extInstSet = GLSLextAMDInst;
 #endif
+#ifdef NV_EXTENSIONS
+                }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
+                          strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0) {
+                    extInstSet = GLSLextNVInst;
+#endif
                 }
                 unsigned entrypoint = stream[word - 1];
                 if (extInstSet == GLSL450Inst) {
@@ -480,6 +495,11 @@
                 } else if (extInstSet == GLSLextAMDInst) {
                     out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
 #endif
+#ifdef NV_EXTENSIONS
+                }
+                else if (extInstSet == GLSLextNVInst) {
+                    out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
+#endif
                 }
             }
             break;
@@ -631,6 +651,23 @@
 }
 #endif
 
+
+#ifdef NV_EXTENSIONS
+static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
+{
+    if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
+        strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0) {
+        switch (entrypoint) {
+        case OverrideCoverageNV:          return "OverrideCoverageNV";
+        case PassthroughNV:               return "PassthroughNV";
+        case GeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
+        default:                          return "Bad";
+        }
+    }
+    return "Bad";
+}
+#endif
+
 void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
 {
     SpirvStream SpirvStream(out, stream);
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 0e68c7e..b20944f 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -51,6 +51,9 @@
 #ifdef AMD_EXTENSIONS
         #include "GLSL.ext.AMD.h"
 #endif
+#ifdef NV_EXTENSIONS
+        #include "GLSL.ext.NV.h"
+#endif
     }
 }
 
@@ -256,6 +259,10 @@
 #ifdef AMD_EXTENSIONS
     case 4999: return "ExplicitInterpAMD";
 #endif
+#ifdef NV_EXTENSIONS
+    case 5248: return "OverrideCoverageNV";
+    case 5250: return "PassthroughNV";
+#endif
     }
 }
 
@@ -812,6 +819,11 @@
 
     case 4423: return "SubgroupBallotKHR";
     case 4427: return "DrawParameters";
+
+#ifdef NV_EXTENSIONS
+    case 5251: return "GeometryShaderPassthroughNV";
+#endif
+
     }
 }
 
@@ -1146,6 +1158,7 @@
 
     case 4421: return "OpSubgroupBallotKHR";
     case 4422: return "OpSubgroupFirstInvocationKHR";
+    case 4432: return "OpSubgroupReadInvocationKHR";
 
 #ifdef AMD_EXTENSIONS
     case 5000: return "OpGroupIAddNonUniformAMD";
@@ -2758,6 +2771,10 @@
 
     InstructionDesc[OpSubgroupFirstInvocationKHR].operands.push(OperandId, "'Value'");
 
+    InstructionDesc[OpSubgroupReadInvocationKHR].capabilities.push_back(CapabilityGroups);
+    InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Index'");
+
 #ifdef AMD_EXTENSIONS
     InstructionDesc[OpGroupIAddNonUniformAMD].capabilities.push_back(CapabilityGroups);
     InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandScope, "'Execution'");
diff --git a/SPIRV/spirv.hpp b/SPIRV/spirv.hpp
index bb3c3f4..088b1af 100755
--- a/SPIRV/spirv.hpp
+++ b/SPIRV/spirv.hpp
@@ -905,6 +905,7 @@
     OpImageSparseRead = 320,
     OpSubgroupBallotKHR = 4421,
     OpSubgroupFirstInvocationKHR = 4422,
+    OpSubgroupReadInvocationKHR = 4432,
     OpMax = 0x7fffffff,
 };
 
diff --git a/Test/baseResults/120.vert.out b/Test/baseResults/120.vert.out
index 94a97b5..c63d95a 100644
--- a/Test/baseResults/120.vert.out
+++ b/Test/baseResults/120.vert.out
@@ -77,9 +77,8 @@
 ERROR: 0:192: 'assign' :  l-value required (can't modify a const)
 ERROR: 0:195: 'gl_ModelViewMatrix' : identifiers starting with "gl_" are reserved 
 ERROR: 0:200: 'token pasting (##)' : not supported for this version or the enabled extensions 
-ERROR: 0:200: '##' : token pasting not implemented (internal error) 
-ERROR: 0:200: '' :  syntax error
-ERROR: 80 compilation errors.  No code generated.
+ERROR: 0:203: 'token pasting (##)' : not supported for this version or the enabled extensions 
+ERROR: 79 compilation errors.  No code generated.
 
 
 Shader version: 120
@@ -427,7 +426,8 @@
 0:?     'c2D' (in 2-component vector of float)
 0:?     'c3D' (in 3-component vector of float)
 0:?     'v4' (uniform 4-component vector of float)
-0:?     'abc' (global int)
+0:?     'abcdef' (global int)
+0:?     'qrstuv' (global int)
 
 
 Linked vertex stage:
@@ -499,5 +499,6 @@
 0:?     'c2D' (in 2-component vector of float)
 0:?     'c3D' (in 3-component vector of float)
 0:?     'v4' (uniform 4-component vector of float)
-0:?     'abc' (global int)
+0:?     'abcdef' (global int)
+0:?     'qrstuv' (global int)
 
diff --git a/Test/baseResults/130.vert.out b/Test/baseResults/130.vert.out
index 1b3a0e1..7ca32a1 100644
--- a/Test/baseResults/130.vert.out
+++ b/Test/baseResults/130.vert.out
@@ -3,9 +3,7 @@
 ERROR: 0:59: '=' :  cannot convert from 'temp float' to 'temp int'
 ERROR: 0:61: 'texelFetch' : no matching overloaded function found 
 ERROR: 0:61: 'assign' :  cannot convert from 'const float' to 'temp int'
-ERROR: 0:75: '##' : token pasting not implemented (internal error) 
-ERROR: 0:75: '' :  syntax error
-ERROR: 6 compilation errors.  No code generated.
+ERROR: 4 compilation errors.  No code generated.
 
 
 Shader version: 130
@@ -149,7 +147,8 @@
 0:?     'v4' (uniform 4-component vector of float)
 0:?     'gl_ClipDistance' (smooth out implicitly-sized array of float ClipDistance)
 0:?     'gl_TexCoord' (smooth out implicitly-sized array of 4-component vector of float TexCoord)
-0:?     'abc' (global int)
+0:?     'abcdef' (global int)
+0:?     'qrstuv' (global int)
 0:?     'gl_VertexID' (gl_VertexId int VertexId)
 
 
@@ -281,6 +280,7 @@
 0:?     'v4' (uniform 4-component vector of float)
 0:?     'gl_ClipDistance' (smooth out 2-element array of float ClipDistance)
 0:?     'gl_TexCoord' (smooth out 1-element array of 4-component vector of float TexCoord)
-0:?     'abc' (global int)
+0:?     'abcdef' (global int)
+0:?     'qrstuv' (global int)
 0:?     'gl_VertexID' (gl_VertexId int VertexId)
 
diff --git a/Test/baseResults/cppBad.vert.out b/Test/baseResults/cppBad.vert.out
index 1fb18ec..d808e72 100755
--- a/Test/baseResults/cppBad.vert.out
+++ b/Test/baseResults/cppBad.vert.out
@@ -3,8 +3,9 @@
 ERROR: 0:2: '#if' : unexpected tokens following directive 
 ERROR: 0:5: 'string' : End of line in string 
 ERROR: 0:5: 'macro expansion' : expected '(' following n
+ERROR: 0:5: '""' : string literals not supported 
 ERROR: 0:5: '' :  syntax error
-ERROR: 5 compilation errors.  No code generated.
+ERROR: 6 compilation errors.  No code generated.
 
 
 Shader version: 100
diff --git a/Test/baseResults/hlsl.array.implicit-size.frag.out b/Test/baseResults/hlsl.array.implicit-size.frag.out
index 5674cb4..5f20362 100644
--- a/Test/baseResults/hlsl.array.implicit-size.frag.out
+++ b/Test/baseResults/hlsl.array.implicit-size.frag.out
@@ -41,38 +41,38 @@
 0:28            1.000000
 0:28            2.000000
 0:28            3.000000
-0:30      move second child to first child (temp 4-component vector of float)
-0:30        color: direct index for structure (temp 4-component vector of float)
-0:30          'ps_output' (out structure{temp 4-component vector of float color})
-0:30          Constant:
-0:30            0 (const int)
-0:30        Construct vec4 (temp 4-component vector of float)
-0:30          add (temp float)
-0:30            add (temp float)
-0:30              add (temp float)
-0:30                add (temp float)
-0:30                  direct index (temp float)
-0:30                    'g_array' (global 5-element array of float)
-0:30                    Constant:
-0:30                      0 (const int)
-0:30                  direct index (temp float)
-0:30                    'g_array' (global 5-element array of float)
-0:30                    Constant:
-0:30                      4 (const int)
-0:30                direct index (temp float)
-0:30                  'l_array' (temp 3-element array of float)
-0:30                  Constant:
-0:30                    1 (const int)
-0:30              f: direct index for structure (temp float)
-0:30                direct index (temp structure{temp int i, temp float f})
-0:30                  'g_mystruct' (global 2-element array of structure{temp int i, temp float f})
-0:30                  Constant:
-0:30                    0 (const int)
-0:30                Constant:
-0:30                  1 (const int)
-0:30            indirect index (temp float)
-0:30              'g_array' (global 5-element array of float)
-0:30              'idx' (temp void)
+0:31      move second child to first child (temp 4-component vector of float)
+0:31        color: direct index for structure (temp 4-component vector of float)
+0:31          'ps_output' (out structure{temp 4-component vector of float color})
+0:31          Constant:
+0:31            0 (const int)
+0:31        Construct vec4 (temp 4-component vector of float)
+0:31          add (temp float)
+0:31            add (temp float)
+0:31              add (temp float)
+0:31                add (temp float)
+0:31                  direct index (temp float)
+0:31                    'g_array' (global 5-element array of float)
+0:31                    Constant:
+0:31                      0 (const int)
+0:31                  direct index (temp float)
+0:31                    'g_array' (global 5-element array of float)
+0:31                    Constant:
+0:31                      4 (const int)
+0:31                direct index (temp float)
+0:31                  'l_array' (temp 3-element array of float)
+0:31                  Constant:
+0:31                    1 (const int)
+0:31              f: direct index for structure (temp float)
+0:31                direct index (temp structure{temp int i, temp float f})
+0:31                  'g_mystruct' (global 2-element array of structure{temp int i, temp float f})
+0:31                  Constant:
+0:31                    0 (const int)
+0:31                Constant:
+0:31                  1 (const int)
+0:31            indirect index (temp float)
+0:31              'g_array' (global 5-element array of float)
+0:31              'idx' (temp int)
 0:?   Linker Objects
 0:?     'g_array' (global 5-element array of float)
 0:?     'g_array_unused' (global 7-element array of float)
@@ -125,38 +125,38 @@
 0:28            1.000000
 0:28            2.000000
 0:28            3.000000
-0:30      move second child to first child (temp 4-component vector of float)
-0:30        color: direct index for structure (temp 4-component vector of float)
-0:30          'ps_output' (out structure{temp 4-component vector of float color})
-0:30          Constant:
-0:30            0 (const int)
-0:30        Construct vec4 (temp 4-component vector of float)
-0:30          add (temp float)
-0:30            add (temp float)
-0:30              add (temp float)
-0:30                add (temp float)
-0:30                  direct index (temp float)
-0:30                    'g_array' (global 5-element array of float)
-0:30                    Constant:
-0:30                      0 (const int)
-0:30                  direct index (temp float)
-0:30                    'g_array' (global 5-element array of float)
-0:30                    Constant:
-0:30                      4 (const int)
-0:30                direct index (temp float)
-0:30                  'l_array' (temp 3-element array of float)
-0:30                  Constant:
-0:30                    1 (const int)
-0:30              f: direct index for structure (temp float)
-0:30                direct index (temp structure{temp int i, temp float f})
-0:30                  'g_mystruct' (global 2-element array of structure{temp int i, temp float f})
-0:30                  Constant:
-0:30                    0 (const int)
-0:30                Constant:
-0:30                  1 (const int)
-0:30            indirect index (temp float)
-0:30              'g_array' (global 5-element array of float)
-0:30              'idx' (temp void)
+0:31      move second child to first child (temp 4-component vector of float)
+0:31        color: direct index for structure (temp 4-component vector of float)
+0:31          'ps_output' (out structure{temp 4-component vector of float color})
+0:31          Constant:
+0:31            0 (const int)
+0:31        Construct vec4 (temp 4-component vector of float)
+0:31          add (temp float)
+0:31            add (temp float)
+0:31              add (temp float)
+0:31                add (temp float)
+0:31                  direct index (temp float)
+0:31                    'g_array' (global 5-element array of float)
+0:31                    Constant:
+0:31                      0 (const int)
+0:31                  direct index (temp float)
+0:31                    'g_array' (global 5-element array of float)
+0:31                    Constant:
+0:31                      4 (const int)
+0:31                direct index (temp float)
+0:31                  'l_array' (temp 3-element array of float)
+0:31                  Constant:
+0:31                    1 (const int)
+0:31              f: direct index for structure (temp float)
+0:31                direct index (temp structure{temp int i, temp float f})
+0:31                  'g_mystruct' (global 2-element array of structure{temp int i, temp float f})
+0:31                  Constant:
+0:31                    0 (const int)
+0:31                Constant:
+0:31                  1 (const int)
+0:31            indirect index (temp float)
+0:31              'g_array' (global 5-element array of float)
+0:31              'idx' (temp int)
 0:?   Linker Objects
 0:?     'g_array' (global 5-element array of float)
 0:?     'g_array_unused' (global 7-element array of float)
@@ -228,7 +228,7 @@
               49:             TypePointer Private 6(float)
               52:     32(int) Constant 4
               56:             TypePointer Function 6(float)
-              63:             TypePointer Function 2
+              63:             TypePointer Function 32(int)
               70:             TypePointer Function 7(fvec4)
 4(PixelShaderFunction):           2 Function None 3
                5:             Label
@@ -254,7 +254,7 @@
               60:     49(ptr) AccessChain 37(g_mystruct) 48 38
               61:    6(float) Load 60
               62:    6(float) FAdd 59 61
-              65:           2 Load 64(idx)
+              65:     32(int) Load 64(idx)
               66:     49(ptr) AccessChain 18(g_array) 65
               67:    6(float) Load 66
               68:    6(float) FAdd 62 67
diff --git a/Test/baseResults/hlsl.identifier.sample.frag.out b/Test/baseResults/hlsl.identifier.sample.frag.out
index 8e74081..35e88e9 100644
--- a/Test/baseResults/hlsl.identifier.sample.frag.out
+++ b/Test/baseResults/hlsl.identifier.sample.frag.out
@@ -12,18 +12,27 @@
 0:12    Function Parameters: 
 0:?     Sequence
 0:15      Sequence
-0:15        move second child to first child (temp int)
-0:15          'sample' (temp int)
-0:15          Constant:
-0:15            3 (const int)
+0:15        move second child to first child (temp 4-component vector of float)
+0:15          'sample' (temp 4-component vector of float)
+0:?           Constant:
+0:?             3.000000
+0:?             4.000000
+0:?             5.000000
+0:?             6.000000
 0:17      Sequence
 0:17        move second child to first child (temp 4-component vector of float)
 0:?           '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
-0:?           Constant:
-0:?             0.000000
-0:?             0.000000
-0:?             0.000000
-0:?             0.000000
+0:17          vector swizzle (temp 4-component vector of float)
+0:17            'sample' (temp 4-component vector of float)
+0:17            Sequence
+0:17              Constant:
+0:17                0 (const int)
+0:17              Constant:
+0:17                1 (const int)
+0:17              Constant:
+0:17                2 (const int)
+0:17              Constant:
+0:17                3 (const int)
 0:17        Branch: Return
 0:?   Linker Objects
 0:?     '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
@@ -45,54 +54,67 @@
 0:12    Function Parameters: 
 0:?     Sequence
 0:15      Sequence
-0:15        move second child to first child (temp int)
-0:15          'sample' (temp int)
-0:15          Constant:
-0:15            3 (const int)
+0:15        move second child to first child (temp 4-component vector of float)
+0:15          'sample' (temp 4-component vector of float)
+0:?           Constant:
+0:?             3.000000
+0:?             4.000000
+0:?             5.000000
+0:?             6.000000
 0:17      Sequence
 0:17        move second child to first child (temp 4-component vector of float)
 0:?           '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
-0:?           Constant:
-0:?             0.000000
-0:?             0.000000
-0:?             0.000000
-0:?             0.000000
+0:17          vector swizzle (temp 4-component vector of float)
+0:17            'sample' (temp 4-component vector of float)
+0:17            Sequence
+0:17              Constant:
+0:17                0 (const int)
+0:17              Constant:
+0:17                1 (const int)
+0:17              Constant:
+0:17                2 (const int)
+0:17              Constant:
+0:17                3 (const int)
 0:17        Branch: Return
 0:?   Linker Objects
 0:?     '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 24
+// Id's are bound by 28
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 20
+                              EntryPoint Fragment 4  "main" 25
                               ExecutionMode 4 OriginUpperLeft
                               Name 4  "main"
                               Name 10  "sample(i1;"
                               Name 9  "x"
-                              Name 15  "sample"
-                              Name 20  "@entryPointOutput"
-                              Decorate 20(@entryPointOutput) Location 0
+                              Name 18  "sample"
+                              Name 25  "@entryPointOutput"
+                              Decorate 25(@entryPointOutput) Location 0
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
                7:             TypePointer Function 6(int)
                8:             TypeFunction 6(int) 7(ptr)
-              16:      6(int) Constant 3
-              17:             TypeFloat 32
-              18:             TypeVector 17(float) 4
-              19:             TypePointer Output 18(fvec4)
-20(@entryPointOutput):     19(ptr) Variable Output
-              21:   17(float) Constant 0
-              22:   18(fvec4) ConstantComposite 21 21 21 21
+              15:             TypeFloat 32
+              16:             TypeVector 15(float) 4
+              17:             TypePointer Function 16(fvec4)
+              19:   15(float) Constant 1077936128
+              20:   15(float) Constant 1082130432
+              21:   15(float) Constant 1084227584
+              22:   15(float) Constant 1086324736
+              23:   16(fvec4) ConstantComposite 19 20 21 22
+              24:             TypePointer Output 16(fvec4)
+25(@entryPointOutput):     24(ptr) Variable Output
          4(main):           2 Function None 3
                5:             Label
-      15(sample):      7(ptr) Variable Function
-                              Store 15(sample) 16
-                              Store 20(@entryPointOutput) 22
+      18(sample):     17(ptr) Variable Function
+                              Store 18(sample) 23
+              26:   16(fvec4) Load 18(sample)
+                              Store 25(@entryPointOutput) 26
                               Return
                               FunctionEnd
   10(sample(i1;):      6(int) Function None 8
diff --git a/Test/baseResults/remap.basic.dcefunc.frag.out b/Test/baseResults/remap.basic.dcefunc.frag.out
index 99b4d55..c28d90a 100644
--- a/Test/baseResults/remap.basic.dcefunc.frag.out
+++ b/Test/baseResults/remap.basic.dcefunc.frag.out
@@ -3,34 +3,33 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 19
+// Id's are bound by 22
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 14 16
+                              EntryPoint Fragment 4  "main" 17 19
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450
                               Name 4  "main"
-                              Name 9  "dead_fn("
-                              Name 14  "outf4"
-                              Name 16  "inf"
+                              Name 17  "outf4"
+                              Name 19  "inf"
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
                7:             TypeVector 6(float) 3
                8:             TypeFunction 7(fvec3)
-              10:    6(float) Constant 0
-              11:    7(fvec3) ConstantComposite 10 10 10
-              12:             TypeVector 6(float) 4
-              13:             TypePointer Output 12(fvec4)
-       14(outf4):     13(ptr) Variable Output
-              15:             TypePointer Input 6(float)
-         16(inf):     15(ptr) Variable Input
+              11:    6(float) Constant 0
+              12:    7(fvec3) ConstantComposite 11 11 11
+              15:             TypeVector 6(float) 4
+              16:             TypePointer Output 15(fvec4)
+       17(outf4):     16(ptr) Variable Output
+              18:             TypePointer Input 6(float)
+         19(inf):     18(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
-              17:    6(float) Load 16(inf)
-              18:   12(fvec4) CompositeConstruct 17 17 17 17
-                              Store 14(outf4) 18
+              20:    6(float) Load 19(inf)
+              21:   15(fvec4) CompositeConstruct 20 20 20 20
+                              Store 17(outf4) 21
                               Return
                               FunctionEnd
diff --git a/Test/baseResults/remap.basic.none.frag.out b/Test/baseResults/remap.basic.none.frag.out
index 39e56b2..44f5747 100644
--- a/Test/baseResults/remap.basic.none.frag.out
+++ b/Test/baseResults/remap.basic.none.frag.out
@@ -3,18 +3,18 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 20
+// Id's are bound by 22
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 15 17
+                              EntryPoint Fragment 4  "main" 17 19
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450
                               Name 4  "main"
                               Name 9  "dead_fn("
-                              Name 15  "outf4"
-                              Name 17  "inf"
+                              Name 17  "outf4"
+                              Name 19  "inf"
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -22,16 +22,16 @@
                8:             TypeFunction 7(fvec3)
               11:    6(float) Constant 0
               12:    7(fvec3) ConstantComposite 11 11 11
-              13:             TypeVector 6(float) 4
-              14:             TypePointer Output 13(fvec4)
-       15(outf4):     14(ptr) Variable Output
-              16:             TypePointer Input 6(float)
-         17(inf):     16(ptr) Variable Input
+              15:             TypeVector 6(float) 4
+              16:             TypePointer Output 15(fvec4)
+       17(outf4):     16(ptr) Variable Output
+              18:             TypePointer Input 6(float)
+         19(inf):     18(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
-              18:    6(float) Load 17(inf)
-              19:   13(fvec4) CompositeConstruct 18 18 18 18
-                              Store 15(outf4) 19
+              20:    6(float) Load 19(inf)
+              21:   15(fvec4) CompositeConstruct 20 20 20 20
+                              Store 17(outf4) 21
                               Return
                               FunctionEnd
      9(dead_fn():    7(fvec3) Function None 8
diff --git a/Test/baseResults/remap.basic.strip.frag.out b/Test/baseResults/remap.basic.strip.frag.out
index 27c0874..ab1a003 100644
--- a/Test/baseResults/remap.basic.strip.frag.out
+++ b/Test/baseResults/remap.basic.strip.frag.out
@@ -3,12 +3,12 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 20
+// Id's are bound by 22
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 15 17
+                              EntryPoint Fragment 4  "main" 17 19
                               ExecutionMode 4 OriginUpperLeft
                2:             TypeVoid
                3:             TypeFunction 2
@@ -17,16 +17,16 @@
                8:             TypeFunction 7(fvec3)
               11:    6(float) Constant 0
               12:    7(fvec3) ConstantComposite 11 11 11
-              13:             TypeVector 6(float) 4
-              14:             TypePointer Output 13(fvec4)
-              15:     14(ptr) Variable Output
-              16:             TypePointer Input 6(float)
-              17:     16(ptr) Variable Input
+              15:             TypeVector 6(float) 4
+              16:             TypePointer Output 15(fvec4)
+              17:     16(ptr) Variable Output
+              18:             TypePointer Input 6(float)
+              19:     18(ptr) Variable Input
                4:           2 Function None 3
                5:             Label
-              18:    6(float) Load 17
-              19:   13(fvec4) CompositeConstruct 18 18 18 18
-                              Store 15 19
+              20:    6(float) Load 19
+              21:   15(fvec4) CompositeConstruct 20 20 20 20
+                              Store 17 21
                               Return
                               FunctionEnd
                9:    7(fvec3) Function None 8
diff --git a/Test/baseResults/remap.hlsl.sample.basic.none.frag.out b/Test/baseResults/remap.hlsl.sample.basic.none.frag.out
index 28c384c..51ad1a8 100644
--- a/Test/baseResults/remap.hlsl.sample.basic.none.frag.out
+++ b/Test/baseResults/remap.hlsl.sample.basic.none.frag.out
@@ -3,7 +3,7 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 190
+// Id's are bound by 191
 
                               Capability Shader
                               Capability Sampled1D
@@ -57,9 +57,9 @@
                               Name 173  "psout"
                               Name 180  "Color"
                               Name 184  "Depth"
-                              Name 187  "g_sSamp2d"
-                              Name 188  "g_sSamp2D_b"
-                              Name 189  "g_tTex1df4a"
+                              Name 188  "g_sSamp2d"
+                              Name 189  "g_sSamp2D_b"
+                              Name 190  "g_tTex1df4a"
                               Decorate 41(g_tTex1df4) DescriptorSet 0
                               Decorate 41(g_tTex1df4) Binding 0
                               Decorate 45(g_sSamp) DescriptorSet 0
@@ -77,10 +77,10 @@
                               Decorate 165(g_tTexcdu4) DescriptorSet 0
                               Decorate 180(Color) Location 0
                               Decorate 184(Depth) BuiltIn FragDepth
-                              Decorate 187(g_sSamp2d) DescriptorSet 0
-                              Decorate 188(g_sSamp2D_b) DescriptorSet 0
-                              Decorate 189(g_tTex1df4a) DescriptorSet 0
-                              Decorate 189(g_tTex1df4a) Binding 1
+                              Decorate 188(g_sSamp2d) DescriptorSet 0
+                              Decorate 189(g_sSamp2D_b) DescriptorSet 0
+                              Decorate 190(g_tTex1df4a) DescriptorSet 0
+                              Decorate 190(g_tTex1df4a) Binding 1
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -184,9 +184,9 @@
       180(Color):    179(ptr) Variable Output
              183:             TypePointer Output 35(float)
       184(Depth):    183(ptr) Variable Output
-  187(g_sSamp2d):     44(ptr) Variable UniformConstant
-188(g_sSamp2D_b):     44(ptr) Variable UniformConstant
-189(g_tTex1df4a):     40(ptr) Variable UniformConstant
+  188(g_sSamp2d):     44(ptr) Variable UniformConstant
+189(g_sSamp2D_b):     44(ptr) Variable UniformConstant
+190(g_tTex1df4a):     40(ptr) Variable UniformConstant
          4(main):           2 Function None 3
                5:             Label
         9(mtest):      8(ptr) Variable Function
diff --git a/Test/baseResults/remap.hlsl.sample.basic.strip.frag.out b/Test/baseResults/remap.hlsl.sample.basic.strip.frag.out
index 10a8938..f95d7ef 100644
--- a/Test/baseResults/remap.hlsl.sample.basic.strip.frag.out
+++ b/Test/baseResults/remap.hlsl.sample.basic.strip.frag.out
@@ -3,7 +3,7 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 190
+// Id's are bound by 191
 
                               Capability Shader
                               Capability Sampled1D
@@ -28,10 +28,10 @@
                               Decorate 165 DescriptorSet 0
                               Decorate 180 Location 0
                               Decorate 184 BuiltIn FragDepth
-                              Decorate 187 DescriptorSet 0
                               Decorate 188 DescriptorSet 0
                               Decorate 189 DescriptorSet 0
-                              Decorate 189 Binding 1
+                              Decorate 190 DescriptorSet 0
+                              Decorate 190 Binding 1
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -135,9 +135,9 @@
              180:    179(ptr) Variable Output
              183:             TypePointer Output 35(float)
              184:    183(ptr) Variable Output
-             187:     44(ptr) Variable UniformConstant
              188:     44(ptr) Variable UniformConstant
-             189:     40(ptr) Variable UniformConstant
+             189:     44(ptr) Variable UniformConstant
+             190:     40(ptr) Variable UniformConstant
                4:           2 Function None 3
                5:             Label
                9:      8(ptr) Variable Function
diff --git a/Test/baseResults/remap.hlsl.templatetypes.none.frag.out b/Test/baseResults/remap.hlsl.templatetypes.none.frag.out
index c3fab1a..027f020 100644
--- a/Test/baseResults/remap.hlsl.templatetypes.none.frag.out
+++ b/Test/baseResults/remap.hlsl.templatetypes.none.frag.out
@@ -1,13 +1,13 @@
 remap.hlsl.templatetypes.none.frag
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 149
+// Id's are bound by 150
 
                               Capability Shader
                               Capability Float64
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 146 148
+                              EntryPoint Fragment 4  "main" 146 149
                               ExecutionMode 4 OriginUpperLeft
                               Name 4  "main"
                               Name 9  "r00"
@@ -39,9 +39,9 @@
                               Name 136  "r65"
                               Name 141  "r66"
                               Name 146  "@entryPointOutput"
-                              Name 148  "input"
+                              Name 149  "input"
                               Decorate 146(@entryPointOutput) Location 0
-                              Decorate 148(input) Location 0
+                              Decorate 149(input) Location 0
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -157,8 +157,8 @@
              144:         139 ConstantComposite 72 126 142 143
              145:             TypePointer Output 6(float)
 146(@entryPointOutput):    145(ptr) Variable Output
-             147:             TypePointer Input 7(fvec4)
-      148(input):    147(ptr) Variable Input
+             148:             TypePointer Input 7(fvec4)
+      149(input):    148(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
           9(r00):      8(ptr) Variable Function
diff --git a/Test/baseResults/remap.similar_1a.none.frag.out b/Test/baseResults/remap.similar_1a.none.frag.out
index ad1273a..910ef42 100644
--- a/Test/baseResults/remap.similar_1a.none.frag.out
+++ b/Test/baseResults/remap.similar_1a.none.frag.out
@@ -3,12 +3,12 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 82
+// Id's are bound by 86
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 50 69 71
+                              EntryPoint Fragment 4  "main" 53 73 75
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450
                               Name 4  "main"
@@ -18,13 +18,13 @@
                               Name 13  "bound"
                               Name 17  "r"
                               Name 19  "x"
-                              Name 42  "param"
-                              Name 50  "ini4"
-                              Name 69  "outf4"
-                              Name 71  "inf"
-                              Name 74  "param"
+                              Name 44  "param"
+                              Name 53  "ini4"
+                              Name 73  "outf4"
+                              Name 75  "inf"
                               Name 78  "param"
-                              Decorate 50(ini4) Flat
+                              Name 82  "param"
+                              Decorate 53(ini4) Flat
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -37,35 +37,35 @@
               28:             TypeBool
               30:    8(float) Constant 1056964608
               34:      6(int) Constant 1
-              38:      6(int) Constant 2
-              48:             TypeVector 6(int) 4
-              49:             TypePointer Input 48(ivec4)
-        50(ini4):     49(ptr) Variable Input
-              51:             TypeInt 32 0
-              52:     51(int) Constant 1
-              53:             TypePointer Input 6(int)
-              56:     51(int) Constant 2
-              61:     51(int) Constant 0
-              67:             TypeVector 8(float) 4
-              68:             TypePointer Output 67(fvec4)
-       69(outf4):     68(ptr) Variable Output
-              70:             TypePointer Input 8(float)
-         71(inf):     70(ptr) Variable Input
+              40:      6(int) Constant 2
+              51:             TypeVector 6(int) 4
+              52:             TypePointer Input 51(ivec4)
+        53(ini4):     52(ptr) Variable Input
+              54:             TypeInt 32 0
+              55:     54(int) Constant 1
+              56:             TypePointer Input 6(int)
+              59:     54(int) Constant 2
+              64:     54(int) Constant 0
+              71:             TypeVector 8(float) 4
+              72:             TypePointer Output 71(fvec4)
+       73(outf4):     72(ptr) Variable Output
+              74:             TypePointer Input 8(float)
+         75(inf):     74(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
-       74(param):      7(ptr) Variable Function
        78(param):      7(ptr) Variable Function
-              72:    8(float) Load 71(inf)
-              73:      6(int) ConvertFToS 72
-                              Store 74(param) 73
-              75:    8(float) FunctionCall 11(Test1(i1;) 74(param)
-              76:    8(float) Load 71(inf)
+       82(param):      7(ptr) Variable Function
+              76:    8(float) Load 75(inf)
               77:      6(int) ConvertFToS 76
                               Store 78(param) 77
-              79:    8(float) FunctionCall 14(Test2(i1;) 78(param)
-              80:    8(float) FAdd 75 79
-              81:   67(fvec4) CompositeConstruct 80 80 80 80
-                              Store 69(outf4) 81
+              79:    8(float) FunctionCall 11(Test1(i1;) 78(param)
+              80:    8(float) Load 75(inf)
+              81:      6(int) ConvertFToS 80
+                              Store 82(param) 81
+              83:    8(float) FunctionCall 14(Test2(i1;) 82(param)
+              84:    8(float) FAdd 79 83
+              85:   71(fvec4) CompositeConstruct 84 84 84 84
+                              Store 73(outf4) 85
                               Return
                               FunctionEnd
    11(Test1(i1;):    8(float) Function None 9
@@ -101,31 +101,31 @@
    14(Test2(i1;):    8(float) Function None 9
        13(bound):      7(ptr) FunctionParameter
               15:             Label
-       42(param):      7(ptr) Variable Function
-              37:      6(int) Load 13(bound)
-              39:    28(bool) SGreaterThan 37 38
-                              SelectionMerge 41 None
-                              BranchConditional 39 40 45
-              40:               Label
-              43:      6(int)   Load 13(bound)
-                                Store 42(param) 43
-              44:    8(float)   FunctionCall 11(Test1(i1;) 42(param)
-                                ReturnValue 44
-              45:               Label
-              46:      6(int)   Load 13(bound)
-              47:      6(int)   IMul 46 38
-              54:     53(ptr)   AccessChain 50(ini4) 52
-              55:      6(int)   Load 54
-              57:     53(ptr)   AccessChain 50(ini4) 56
+       44(param):      7(ptr) Variable Function
+              39:      6(int) Load 13(bound)
+              41:    28(bool) SGreaterThan 39 40
+                              SelectionMerge 43 None
+                              BranchConditional 41 42 48
+              42:               Label
+              45:      6(int)   Load 13(bound)
+                                Store 44(param) 45
+              46:    8(float)   FunctionCall 11(Test1(i1;) 44(param)
+                                ReturnValue 46
+              48:               Label
+              49:      6(int)   Load 13(bound)
+              50:      6(int)   IMul 49 40
+              57:     56(ptr)   AccessChain 53(ini4) 55
               58:      6(int)   Load 57
-              59:      6(int)   IMul 55 58
-              60:      6(int)   IAdd 47 59
-              62:     53(ptr)   AccessChain 50(ini4) 61
-              63:      6(int)   Load 62
-              64:      6(int)   IAdd 60 63
-              65:    8(float)   ConvertSToF 64
-                                ReturnValue 65
-              41:             Label
-              66:    8(float) Undef
-                              ReturnValue 66
+              60:     56(ptr)   AccessChain 53(ini4) 59
+              61:      6(int)   Load 60
+              62:      6(int)   IMul 58 61
+              63:      6(int)   IAdd 50 62
+              65:     56(ptr)   AccessChain 53(ini4) 64
+              66:      6(int)   Load 65
+              67:      6(int)   IAdd 63 66
+              68:    8(float)   ConvertSToF 67
+                                ReturnValue 68
+              43:             Label
+              70:    8(float) Undef
+                              ReturnValue 70
                               FunctionEnd
diff --git a/Test/baseResults/remap.similar_1b.none.frag.out b/Test/baseResults/remap.similar_1b.none.frag.out
index b86fd4b..ce79e00 100644
--- a/Test/baseResults/remap.similar_1b.none.frag.out
+++ b/Test/baseResults/remap.similar_1b.none.frag.out
@@ -3,12 +3,12 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 87
+// Id's are bound by 91
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 55 74 76
+                              EntryPoint Fragment 4  "main" 58 78 80
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450
                               Name 4  "main"
@@ -18,13 +18,13 @@
                               Name 13  "bound"
                               Name 17  "r"
                               Name 19  "x"
-                              Name 47  "param"
-                              Name 55  "ini4"
-                              Name 74  "outf4"
-                              Name 76  "inf"
-                              Name 79  "param"
+                              Name 49  "param"
+                              Name 58  "ini4"
+                              Name 78  "outf4"
+                              Name 80  "inf"
                               Name 83  "param"
-                              Decorate 55(ini4) Flat
+                              Name 87  "param"
+                              Decorate 58(ini4) Flat
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -38,36 +38,36 @@
               30:    8(float) Constant 1056964608
               34:      6(int) Constant 1
               36:    8(float) Constant 1045220557
-              41:      6(int) Constant 2
-              51:      6(int) Constant 4
-              53:             TypeVector 6(int) 4
-              54:             TypePointer Input 53(ivec4)
-        55(ini4):     54(ptr) Variable Input
-              56:             TypeInt 32 0
-              57:     56(int) Constant 1
-              58:             TypePointer Input 6(int)
-              61:     56(int) Constant 2
-              66:     56(int) Constant 0
-              72:             TypeVector 8(float) 4
-              73:             TypePointer Output 72(fvec4)
-       74(outf4):     73(ptr) Variable Output
-              75:             TypePointer Input 8(float)
-         76(inf):     75(ptr) Variable Input
+              43:      6(int) Constant 2
+              54:      6(int) Constant 4
+              56:             TypeVector 6(int) 4
+              57:             TypePointer Input 56(ivec4)
+        58(ini4):     57(ptr) Variable Input
+              59:             TypeInt 32 0
+              60:     59(int) Constant 1
+              61:             TypePointer Input 6(int)
+              64:     59(int) Constant 2
+              69:     59(int) Constant 0
+              76:             TypeVector 8(float) 4
+              77:             TypePointer Output 76(fvec4)
+       78(outf4):     77(ptr) Variable Output
+              79:             TypePointer Input 8(float)
+         80(inf):     79(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
-       79(param):      7(ptr) Variable Function
        83(param):      7(ptr) Variable Function
-              77:    8(float) Load 76(inf)
-              78:      6(int) ConvertFToS 77
-                              Store 79(param) 78
-              80:    8(float) FunctionCall 11(Test1(i1;) 79(param)
-              81:    8(float) Load 76(inf)
+       87(param):      7(ptr) Variable Function
+              81:    8(float) Load 80(inf)
               82:      6(int) ConvertFToS 81
                               Store 83(param) 82
-              84:    8(float) FunctionCall 14(Test2(i1;) 83(param)
-              85:    8(float) FAdd 80 84
-              86:   72(fvec4) CompositeConstruct 85 85 85 85
-                              Store 74(outf4) 86
+              84:    8(float) FunctionCall 11(Test1(i1;) 83(param)
+              85:    8(float) Load 80(inf)
+              86:      6(int) ConvertFToS 85
+                              Store 87(param) 86
+              88:    8(float) FunctionCall 14(Test2(i1;) 87(param)
+              89:    8(float) FAdd 84 88
+              90:   76(fvec4) CompositeConstruct 89 89 89 89
+                              Store 78(outf4) 90
                               Return
                               FunctionEnd
    11(Test1(i1;):    8(float) Function None 9
@@ -106,32 +106,32 @@
    14(Test2(i1;):    8(float) Function None 9
        13(bound):      7(ptr) FunctionParameter
               15:             Label
-       47(param):      7(ptr) Variable Function
-              40:      6(int) Load 13(bound)
-              42:    28(bool) SGreaterThan 40 41
-                              SelectionMerge 44 None
-                              BranchConditional 42 43 49
-              43:               Label
-              45:      6(int)   Load 13(bound)
-              46:      6(int)   IMul 45 41
-                                Store 47(param) 46
-              48:    8(float)   FunctionCall 11(Test1(i1;) 47(param)
-                                ReturnValue 48
-              49:               Label
-              50:      6(int)   Load 13(bound)
-              52:      6(int)   IMul 50 51
-              59:     58(ptr)   AccessChain 55(ini4) 57
-              60:      6(int)   Load 59
-              62:     58(ptr)   AccessChain 55(ini4) 61
+       49(param):      7(ptr) Variable Function
+              42:      6(int) Load 13(bound)
+              44:    28(bool) SGreaterThan 42 43
+                              SelectionMerge 46 None
+                              BranchConditional 44 45 52
+              45:               Label
+              47:      6(int)   Load 13(bound)
+              48:      6(int)   IMul 47 43
+                                Store 49(param) 48
+              50:    8(float)   FunctionCall 11(Test1(i1;) 49(param)
+                                ReturnValue 50
+              52:               Label
+              53:      6(int)   Load 13(bound)
+              55:      6(int)   IMul 53 54
+              62:     61(ptr)   AccessChain 58(ini4) 60
               63:      6(int)   Load 62
-              64:      6(int)   IMul 60 63
-              65:      6(int)   IAdd 52 64
-              67:     58(ptr)   AccessChain 55(ini4) 66
-              68:      6(int)   Load 67
-              69:      6(int)   IAdd 65 68
-              70:    8(float)   ConvertSToF 69
-                                ReturnValue 70
-              44:             Label
-              71:    8(float) Undef
-                              ReturnValue 71
+              65:     61(ptr)   AccessChain 58(ini4) 64
+              66:      6(int)   Load 65
+              67:      6(int)   IMul 63 66
+              68:      6(int)   IAdd 55 67
+              70:     61(ptr)   AccessChain 58(ini4) 69
+              71:      6(int)   Load 70
+              72:      6(int)   IAdd 68 71
+              73:    8(float)   ConvertSToF 72
+                                ReturnValue 73
+              46:             Label
+              75:    8(float) Undef
+                              ReturnValue 75
                               FunctionEnd
diff --git a/Test/baseResults/remap.switch.none.frag.out b/Test/baseResults/remap.switch.none.frag.out
index 5d373cc..68d075b 100644
--- a/Test/baseResults/remap.switch.none.frag.out
+++ b/Test/baseResults/remap.switch.none.frag.out
@@ -5,7 +5,7 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 44
+// Id's are bound by 48
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
@@ -20,8 +20,8 @@
                               Decorate 23(FragColor) RelaxedPrecision
                               Decorate 23(FragColor) Location 0
                               Decorate 29 RelaxedPrecision
-                              Decorate 35 RelaxedPrecision
-                              Decorate 41 RelaxedPrecision
+                              Decorate 36 RelaxedPrecision
+                              Decorate 43 RelaxedPrecision
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -36,12 +36,12 @@
    23(FragColor):     22(ptr) Variable Output
               24:     10(int) Constant 0
               27:    6(float) Constant 0
-              30:     10(int) Constant 1
-              33:    6(float) Constant 1065353216
-              36:     10(int) Constant 2
-              39:    6(float) Constant 1073741824
-              42:    6(float) Constant 3212836864
-              43:    7(fvec4) ConstantComposite 42 42 42 42
+              31:     10(int) Constant 1
+              34:    6(float) Constant 1065353216
+              38:     10(int) Constant 2
+              41:    6(float) Constant 1073741824
+              45:    6(float) Constant 3212836864
+              46:    7(fvec4) ConstantComposite 45 45 45 45
          4(main):           2 Function None 3
                5:             Label
               13:     12(ptr) AccessChain 9(in0) 11
@@ -53,7 +53,7 @@
                                      case 1: 18
                                      case 2: 19
               20:               Label
-                                Store 23(FragColor) 43
+                                Store 23(FragColor) 46
                                 Branch 21
               17:               Label
               25:     12(ptr)   AccessChain 9(in0) 24
@@ -63,18 +63,18 @@
                                 Store 23(FragColor) 29
                                 Branch 21
               18:               Label
-              31:     12(ptr)   AccessChain 9(in0) 30
-              32:    6(float)   Load 31
-              34:    6(float)   FAdd 32 33
-              35:    7(fvec4)   CompositeConstruct 34 34 34 34
-                                Store 23(FragColor) 35
+              32:     12(ptr)   AccessChain 9(in0) 31
+              33:    6(float)   Load 32
+              35:    6(float)   FAdd 33 34
+              36:    7(fvec4)   CompositeConstruct 35 35 35 35
+                                Store 23(FragColor) 36
                                 Branch 21
               19:               Label
-              37:     12(ptr)   AccessChain 9(in0) 36
-              38:    6(float)   Load 37
-              40:    6(float)   FAdd 38 39
-              41:    7(fvec4)   CompositeConstruct 40 40 40 40
-                                Store 23(FragColor) 41
+              39:     12(ptr)   AccessChain 9(in0) 38
+              40:    6(float)   Load 39
+              42:    6(float)   FAdd 40 41
+              43:    7(fvec4)   CompositeConstruct 42 42 42 42
+                                Store 23(FragColor) 43
                                 Branch 21
               21:             Label
                               Return
diff --git a/Test/baseResults/spv.GeometryShaderPassthrough.geom.out b/Test/baseResults/spv.GeometryShaderPassthrough.geom.out
new file mode 100644
index 0000000..05aeb97
--- /dev/null
+++ b/Test/baseResults/spv.GeometryShaderPassthrough.geom.out
@@ -0,0 +1,46 @@
+spv.GeometryShaderPassthrough.geom
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 15
+
+                              Capability Geometry
+                              Capability GeometryShaderPassthroughNV
+                              Extension  "SPV_NV_geometry_shader_passthrough"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Geometry 4  "main" 10 14
+                              ExecutionMode 4 Triangles
+                              ExecutionMode 4 Invocations 1
+                              ExecutionMode 4 OutputVertices
+                              Source GLSL 450
+                              SourceExtension  "GL_NV_geometry_shader_passthrough"
+                              Name 4  "main"
+                              Name 8  "gl_PerVertex"
+                              MemberName 8(gl_PerVertex) 0  "gl_Position"
+                              Name 10  ""
+                              Name 12  "Inputs"
+                              MemberName 12(Inputs) 0  "texcoord"
+                              MemberName 12(Inputs) 1  "baseColor"
+                              Name 14  ""
+                              MemberDecorate 8(gl_PerVertex) 0 BuiltIn Position
+                              Decorate 8(gl_PerVertex) Block
+                              Decorate 10 PassthroughNV
+                              Decorate 12(Inputs) Block
+                              Decorate 14 PassthroughNV
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+ 8(gl_PerVertex):             TypeStruct 7(fvec4)
+               9:             TypePointer Input 8(gl_PerVertex)
+              10:      9(ptr) Variable Input
+              11:             TypeVector 6(float) 2
+      12(Inputs):             TypeStruct 11(fvec2) 7(fvec4)
+              13:             TypePointer Input 12(Inputs)
+              14:     13(ptr) Variable Input
+         4(main):           2 Function None 3
+               5:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out b/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out
new file mode 100644
index 0000000..6bae6bd
--- /dev/null
+++ b/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out
@@ -0,0 +1,42 @@
+spv.sampleMaskOverrideCoverage.frag
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 20
+
+                              Capability Shader
+                              Capability SampleRateShading
+                              Extension  "SPV_NV_sample_mask_override_coverage"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 11 19
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_NV_sample_mask_override_coverage"
+                              Name 4  "main"
+                              Name 11  "gl_SampleMask"
+                              Name 19  "color"
+                              Decorate 11(gl_SampleMask) BuiltIn SampleMask
+                              Decorate 11(gl_SampleMask) OverrideCoverageNV
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeInt 32 1
+               7:             TypeInt 32 0
+               8:      7(int) Constant 1
+               9:             TypeArray 6(int) 8
+              10:             TypePointer Output 9
+11(gl_SampleMask):     10(ptr) Variable Output
+              12:      6(int) Constant 0
+              13:      6(int) Constant 4294967295
+              14:             TypePointer Output 6(int)
+              16:             TypeFloat 32
+              17:             TypeVector 16(float) 4
+              18:             TypePointer Input 17(fvec4)
+       19(color):     18(ptr) Variable Input
+         4(main):           2 Function None 3
+               5:             Label
+              15:     14(ptr) AccessChain 11(gl_SampleMask) 12
+                              Store 15 13
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/spv.shaderBallot.comp.out b/Test/baseResults/spv.shaderBallot.comp.out
index 4f03312..b8d5e3a 100644
--- a/Test/baseResults/spv.shaderBallot.comp.out
+++ b/Test/baseResults/spv.shaderBallot.comp.out
@@ -3,11 +3,10 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 299
+// Id's are bound by 298
 
                               Capability Shader
                               Capability Int64
-                              Capability Groups
                               Capability SubgroupBallotKHR
                               Extension  "SPV_KHR_shader_ballot"
                1:             ExtInstImport  "GLSL.std.450"
@@ -45,7 +44,7 @@
                               Decorate 52(Buffers) BufferBlock
                               Decorate 55(data) DescriptorSet 0
                               Decorate 55(data) Binding 0
-                              Decorate 298 BuiltIn WorkgroupSize
+                              Decorate 297 BuiltIn WorkgroupSize
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 0
@@ -77,23 +76,22 @@
               57:     50(int) Constant 0
               58:      6(int) Constant 0
               59:             TypePointer Uniform 48(float)
-              63:      6(int) Constant 3
-              67:     50(int) Constant 1
-              68:             TypeVector 48(float) 2
-              69:             TypePointer Uniform 49(fvec4)
-              83:     50(int) Constant 2
-              84:             TypeVector 48(float) 3
-             100:     50(int) Constant 3
-             115:             TypePointer Uniform 50(int)
-             122:             TypeVector 50(int) 2
-             123:             TypePointer Uniform 51(ivec4)
-             137:             TypeVector 50(int) 3
-             167:             TypePointer Uniform 6(int)
-             174:             TypePointer Uniform 38(ivec4)
-             188:             TypeVector 6(int) 3
-             296:      6(int) Constant 8
-             297:      6(int) Constant 1
-             298:  188(ivec3) ConstantComposite 296 296 297
+              66:     50(int) Constant 1
+              67:             TypeVector 48(float) 2
+              68:             TypePointer Uniform 49(fvec4)
+              82:     50(int) Constant 2
+              83:             TypeVector 48(float) 3
+              99:     50(int) Constant 3
+             114:             TypePointer Uniform 50(int)
+             121:             TypeVector 50(int) 2
+             122:             TypePointer Uniform 51(ivec4)
+             136:             TypeVector 50(int) 3
+             166:             TypePointer Uniform 6(int)
+             173:             TypePointer Uniform 38(ivec4)
+             187:             TypeVector 6(int) 3
+             295:      6(int) Constant 8
+             296:      6(int) Constant 1
+             297:  187(ivec3) ConstantComposite 295 295 296
          4(main):           2 Function None 3
                5:             Label
    8(invocation):      7(ptr) Variable Function
@@ -121,256 +119,256 @@
               44:     17(int) Bitcast 43
               45:    36(bool) IEqual 35 44
                               SelectionMerge 47 None
-                              BranchConditional 45 46 217
+                              BranchConditional 45 46 216
               46:               Label
               56:      6(int)   Load 8(invocation)
               60:     59(ptr)   AccessChain 55(data) 57 57 58
               61:   48(float)   Load 60
               62:      6(int)   Load 8(invocation)
-              64:   48(float)   GroupBroadcast 63 61 62
-              65:     59(ptr)   AccessChain 55(data) 56 57 58
-                                Store 65 64
-              66:      6(int)   Load 8(invocation)
-              70:     69(ptr)   AccessChain 55(data) 67 57
-              71:   49(fvec4)   Load 70
-              72:   68(fvec2)   VectorShuffle 71 71 0 1
-              73:      6(int)   Load 8(invocation)
-              74:   48(float)   CompositeExtract 72 0
-              75:   48(float)   GroupBroadcast 63 74 73
-              76:   48(float)   CompositeExtract 72 1
-              77:   48(float)   GroupBroadcast 63 76 73
-              78:   68(fvec2)   CompositeConstruct 75 77
-              79:     69(ptr)   AccessChain 55(data) 66 57
-              80:   49(fvec4)   Load 79
-              81:   49(fvec4)   VectorShuffle 80 78 4 5 2 3
-                                Store 79 81
-              82:      6(int)   Load 8(invocation)
-              85:     69(ptr)   AccessChain 55(data) 83 57
-              86:   49(fvec4)   Load 85
-              87:   84(fvec3)   VectorShuffle 86 86 0 1 2
-              88:      6(int)   Load 8(invocation)
-              89:   48(float)   CompositeExtract 87 0
-              90:   48(float)   GroupBroadcast 63 89 88
-              91:   48(float)   CompositeExtract 87 1
-              92:   48(float)   GroupBroadcast 63 91 88
-              93:   48(float)   CompositeExtract 87 2
-              94:   48(float)   GroupBroadcast 63 93 88
-              95:   84(fvec3)   CompositeConstruct 90 92 94
-              96:     69(ptr)   AccessChain 55(data) 82 57
-              97:   49(fvec4)   Load 96
-              98:   49(fvec4)   VectorShuffle 97 95 4 5 6 3
-                                Store 96 98
-              99:      6(int)   Load 8(invocation)
-             101:     69(ptr)   AccessChain 55(data) 100 57
-             102:   49(fvec4)   Load 101
-             103:      6(int)   Load 8(invocation)
-             104:   48(float)   CompositeExtract 102 0
-             105:   48(float)   GroupBroadcast 63 104 103
-             106:   48(float)   CompositeExtract 102 1
-             107:   48(float)   GroupBroadcast 63 106 103
-             108:   48(float)   CompositeExtract 102 2
-             109:   48(float)   GroupBroadcast 63 108 103
-             110:   48(float)   CompositeExtract 102 3
-             111:   48(float)   GroupBroadcast 63 110 103
-             112:   49(fvec4)   CompositeConstruct 105 107 109 111
-             113:     69(ptr)   AccessChain 55(data) 99 57
-                                Store 113 112
-             114:      6(int)   Load 8(invocation)
-             116:    115(ptr)   AccessChain 55(data) 57 67 58
-             117:     50(int)   Load 116
-             118:      6(int)   Load 8(invocation)
-             119:     50(int)   GroupBroadcast 63 117 118
-             120:    115(ptr)   AccessChain 55(data) 114 67 58
-                                Store 120 119
-             121:      6(int)   Load 8(invocation)
-             124:    123(ptr)   AccessChain 55(data) 67 67
-             125:   51(ivec4)   Load 124
-             126:  122(ivec2)   VectorShuffle 125 125 0 1
-             127:      6(int)   Load 8(invocation)
-             128:     50(int)   CompositeExtract 126 0
-             129:     50(int)   GroupBroadcast 63 128 127
-             130:     50(int)   CompositeExtract 126 1
-             131:     50(int)   GroupBroadcast 63 130 127
-             132:  122(ivec2)   CompositeConstruct 129 131
-             133:    123(ptr)   AccessChain 55(data) 121 67
-             134:   51(ivec4)   Load 133
-             135:   51(ivec4)   VectorShuffle 134 132 4 5 2 3
-                                Store 133 135
-             136:      6(int)   Load 8(invocation)
-             138:    123(ptr)   AccessChain 55(data) 83 67
-             139:   51(ivec4)   Load 138
-             140:  137(ivec3)   VectorShuffle 139 139 0 1 2
-             141:      6(int)   Load 8(invocation)
-             142:     50(int)   CompositeExtract 140 0
-             143:     50(int)   GroupBroadcast 63 142 141
-             144:     50(int)   CompositeExtract 140 1
-             145:     50(int)   GroupBroadcast 63 144 141
-             146:     50(int)   CompositeExtract 140 2
-             147:     50(int)   GroupBroadcast 63 146 141
-             148:  137(ivec3)   CompositeConstruct 143 145 147
-             149:    123(ptr)   AccessChain 55(data) 136 67
-             150:   51(ivec4)   Load 149
-             151:   51(ivec4)   VectorShuffle 150 148 4 5 6 3
-                                Store 149 151
-             152:      6(int)   Load 8(invocation)
-             153:    123(ptr)   AccessChain 55(data) 100 67
-             154:   51(ivec4)   Load 153
-             155:      6(int)   Load 8(invocation)
-             156:     50(int)   CompositeExtract 154 0
-             157:     50(int)   GroupBroadcast 63 156 155
-             158:     50(int)   CompositeExtract 154 1
-             159:     50(int)   GroupBroadcast 63 158 155
-             160:     50(int)   CompositeExtract 154 2
-             161:     50(int)   GroupBroadcast 63 160 155
-             162:     50(int)   CompositeExtract 154 3
-             163:     50(int)   GroupBroadcast 63 162 155
-             164:   51(ivec4)   CompositeConstruct 157 159 161 163
-             165:    123(ptr)   AccessChain 55(data) 152 67
-                                Store 165 164
-             166:      6(int)   Load 8(invocation)
-             168:    167(ptr)   AccessChain 55(data) 57 83 58
-             169:      6(int)   Load 168
-             170:      6(int)   Load 8(invocation)
-             171:      6(int)   GroupBroadcast 63 169 170
-             172:    167(ptr)   AccessChain 55(data) 166 83 58
-                                Store 172 171
-             173:      6(int)   Load 8(invocation)
-             175:    174(ptr)   AccessChain 55(data) 67 83
-             176:   38(ivec4)   Load 175
-             177:   42(ivec2)   VectorShuffle 176 176 0 1
-             178:      6(int)   Load 8(invocation)
-             179:      6(int)   CompositeExtract 177 0
-             180:      6(int)   GroupBroadcast 63 179 178
-             181:      6(int)   CompositeExtract 177 1
-             182:      6(int)   GroupBroadcast 63 181 178
-             183:   42(ivec2)   CompositeConstruct 180 182
-             184:    174(ptr)   AccessChain 55(data) 173 83
-             185:   38(ivec4)   Load 184
-             186:   38(ivec4)   VectorShuffle 185 183 4 5 2 3
-                                Store 184 186
-             187:      6(int)   Load 8(invocation)
-             189:    174(ptr)   AccessChain 55(data) 83 83
-             190:   38(ivec4)   Load 189
-             191:  188(ivec3)   VectorShuffle 190 190 0 1 2
-             192:      6(int)   Load 8(invocation)
-             193:      6(int)   CompositeExtract 191 0
-             194:      6(int)   GroupBroadcast 63 193 192
-             195:      6(int)   CompositeExtract 191 1
-             196:      6(int)   GroupBroadcast 63 195 192
-             197:      6(int)   CompositeExtract 191 2
-             198:      6(int)   GroupBroadcast 63 197 192
-             199:  188(ivec3)   CompositeConstruct 194 196 198
-             200:    174(ptr)   AccessChain 55(data) 187 83
-             201:   38(ivec4)   Load 200
-             202:   38(ivec4)   VectorShuffle 201 199 4 5 6 3
-                                Store 200 202
-             203:      6(int)   Load 8(invocation)
-             204:    174(ptr)   AccessChain 55(data) 100 83
-             205:   38(ivec4)   Load 204
-             206:      6(int)   Load 8(invocation)
-             207:      6(int)   CompositeExtract 205 0
-             208:      6(int)   GroupBroadcast 63 207 206
-             209:      6(int)   CompositeExtract 205 1
-             210:      6(int)   GroupBroadcast 63 209 206
-             211:      6(int)   CompositeExtract 205 2
-             212:      6(int)   GroupBroadcast 63 211 206
-             213:      6(int)   CompositeExtract 205 3
-             214:      6(int)   GroupBroadcast 63 213 206
-             215:   38(ivec4)   CompositeConstruct 208 210 212 214
-             216:    174(ptr)   AccessChain 55(data) 203 83
-                                Store 216 215
+              63:   48(float)   SubgroupReadInvocationKHR 61 62
+              64:     59(ptr)   AccessChain 55(data) 56 57 58
+                                Store 64 63
+              65:      6(int)   Load 8(invocation)
+              69:     68(ptr)   AccessChain 55(data) 66 57
+              70:   49(fvec4)   Load 69
+              71:   67(fvec2)   VectorShuffle 70 70 0 1
+              72:      6(int)   Load 8(invocation)
+              73:   48(float)   CompositeExtract 71 0
+              74:   48(float)   SubgroupReadInvocationKHR 73 72
+              75:   48(float)   CompositeExtract 71 1
+              76:   48(float)   SubgroupReadInvocationKHR 75 72
+              77:   67(fvec2)   CompositeConstruct 74 76
+              78:     68(ptr)   AccessChain 55(data) 65 57
+              79:   49(fvec4)   Load 78
+              80:   49(fvec4)   VectorShuffle 79 77 4 5 2 3
+                                Store 78 80
+              81:      6(int)   Load 8(invocation)
+              84:     68(ptr)   AccessChain 55(data) 82 57
+              85:   49(fvec4)   Load 84
+              86:   83(fvec3)   VectorShuffle 85 85 0 1 2
+              87:      6(int)   Load 8(invocation)
+              88:   48(float)   CompositeExtract 86 0
+              89:   48(float)   SubgroupReadInvocationKHR 88 87
+              90:   48(float)   CompositeExtract 86 1
+              91:   48(float)   SubgroupReadInvocationKHR 90 87
+              92:   48(float)   CompositeExtract 86 2
+              93:   48(float)   SubgroupReadInvocationKHR 92 87
+              94:   83(fvec3)   CompositeConstruct 89 91 93
+              95:     68(ptr)   AccessChain 55(data) 81 57
+              96:   49(fvec4)   Load 95
+              97:   49(fvec4)   VectorShuffle 96 94 4 5 6 3
+                                Store 95 97
+              98:      6(int)   Load 8(invocation)
+             100:     68(ptr)   AccessChain 55(data) 99 57
+             101:   49(fvec4)   Load 100
+             102:      6(int)   Load 8(invocation)
+             103:   48(float)   CompositeExtract 101 0
+             104:   48(float)   SubgroupReadInvocationKHR 103 102
+             105:   48(float)   CompositeExtract 101 1
+             106:   48(float)   SubgroupReadInvocationKHR 105 102
+             107:   48(float)   CompositeExtract 101 2
+             108:   48(float)   SubgroupReadInvocationKHR 107 102
+             109:   48(float)   CompositeExtract 101 3
+             110:   48(float)   SubgroupReadInvocationKHR 109 102
+             111:   49(fvec4)   CompositeConstruct 104 106 108 110
+             112:     68(ptr)   AccessChain 55(data) 98 57
+                                Store 112 111
+             113:      6(int)   Load 8(invocation)
+             115:    114(ptr)   AccessChain 55(data) 57 66 58
+             116:     50(int)   Load 115
+             117:      6(int)   Load 8(invocation)
+             118:     50(int)   SubgroupReadInvocationKHR 116 117
+             119:    114(ptr)   AccessChain 55(data) 113 66 58
+                                Store 119 118
+             120:      6(int)   Load 8(invocation)
+             123:    122(ptr)   AccessChain 55(data) 66 66
+             124:   51(ivec4)   Load 123
+             125:  121(ivec2)   VectorShuffle 124 124 0 1
+             126:      6(int)   Load 8(invocation)
+             127:     50(int)   CompositeExtract 125 0
+             128:     50(int)   SubgroupReadInvocationKHR 127 126
+             129:     50(int)   CompositeExtract 125 1
+             130:     50(int)   SubgroupReadInvocationKHR 129 126
+             131:  121(ivec2)   CompositeConstruct 128 130
+             132:    122(ptr)   AccessChain 55(data) 120 66
+             133:   51(ivec4)   Load 132
+             134:   51(ivec4)   VectorShuffle 133 131 4 5 2 3
+                                Store 132 134
+             135:      6(int)   Load 8(invocation)
+             137:    122(ptr)   AccessChain 55(data) 82 66
+             138:   51(ivec4)   Load 137
+             139:  136(ivec3)   VectorShuffle 138 138 0 1 2
+             140:      6(int)   Load 8(invocation)
+             141:     50(int)   CompositeExtract 139 0
+             142:     50(int)   SubgroupReadInvocationKHR 141 140
+             143:     50(int)   CompositeExtract 139 1
+             144:     50(int)   SubgroupReadInvocationKHR 143 140
+             145:     50(int)   CompositeExtract 139 2
+             146:     50(int)   SubgroupReadInvocationKHR 145 140
+             147:  136(ivec3)   CompositeConstruct 142 144 146
+             148:    122(ptr)   AccessChain 55(data) 135 66
+             149:   51(ivec4)   Load 148
+             150:   51(ivec4)   VectorShuffle 149 147 4 5 6 3
+                                Store 148 150
+             151:      6(int)   Load 8(invocation)
+             152:    122(ptr)   AccessChain 55(data) 99 66
+             153:   51(ivec4)   Load 152
+             154:      6(int)   Load 8(invocation)
+             155:     50(int)   CompositeExtract 153 0
+             156:     50(int)   SubgroupReadInvocationKHR 155 154
+             157:     50(int)   CompositeExtract 153 1
+             158:     50(int)   SubgroupReadInvocationKHR 157 154
+             159:     50(int)   CompositeExtract 153 2
+             160:     50(int)   SubgroupReadInvocationKHR 159 154
+             161:     50(int)   CompositeExtract 153 3
+             162:     50(int)   SubgroupReadInvocationKHR 161 154
+             163:   51(ivec4)   CompositeConstruct 156 158 160 162
+             164:    122(ptr)   AccessChain 55(data) 151 66
+                                Store 164 163
+             165:      6(int)   Load 8(invocation)
+             167:    166(ptr)   AccessChain 55(data) 57 82 58
+             168:      6(int)   Load 167
+             169:      6(int)   Load 8(invocation)
+             170:      6(int)   SubgroupReadInvocationKHR 168 169
+             171:    166(ptr)   AccessChain 55(data) 165 82 58
+                                Store 171 170
+             172:      6(int)   Load 8(invocation)
+             174:    173(ptr)   AccessChain 55(data) 66 82
+             175:   38(ivec4)   Load 174
+             176:   42(ivec2)   VectorShuffle 175 175 0 1
+             177:      6(int)   Load 8(invocation)
+             178:      6(int)   CompositeExtract 176 0
+             179:      6(int)   SubgroupReadInvocationKHR 178 177
+             180:      6(int)   CompositeExtract 176 1
+             181:      6(int)   SubgroupReadInvocationKHR 180 177
+             182:   42(ivec2)   CompositeConstruct 179 181
+             183:    173(ptr)   AccessChain 55(data) 172 82
+             184:   38(ivec4)   Load 183
+             185:   38(ivec4)   VectorShuffle 184 182 4 5 2 3
+                                Store 183 185
+             186:      6(int)   Load 8(invocation)
+             188:    173(ptr)   AccessChain 55(data) 82 82
+             189:   38(ivec4)   Load 188
+             190:  187(ivec3)   VectorShuffle 189 189 0 1 2
+             191:      6(int)   Load 8(invocation)
+             192:      6(int)   CompositeExtract 190 0
+             193:      6(int)   SubgroupReadInvocationKHR 192 191
+             194:      6(int)   CompositeExtract 190 1
+             195:      6(int)   SubgroupReadInvocationKHR 194 191
+             196:      6(int)   CompositeExtract 190 2
+             197:      6(int)   SubgroupReadInvocationKHR 196 191
+             198:  187(ivec3)   CompositeConstruct 193 195 197
+             199:    173(ptr)   AccessChain 55(data) 186 82
+             200:   38(ivec4)   Load 199
+             201:   38(ivec4)   VectorShuffle 200 198 4 5 6 3
+                                Store 199 201
+             202:      6(int)   Load 8(invocation)
+             203:    173(ptr)   AccessChain 55(data) 99 82
+             204:   38(ivec4)   Load 203
+             205:      6(int)   Load 8(invocation)
+             206:      6(int)   CompositeExtract 204 0
+             207:      6(int)   SubgroupReadInvocationKHR 206 205
+             208:      6(int)   CompositeExtract 204 1
+             209:      6(int)   SubgroupReadInvocationKHR 208 205
+             210:      6(int)   CompositeExtract 204 2
+             211:      6(int)   SubgroupReadInvocationKHR 210 205
+             212:      6(int)   CompositeExtract 204 3
+             213:      6(int)   SubgroupReadInvocationKHR 212 205
+             214:   38(ivec4)   CompositeConstruct 207 209 211 213
+             215:    173(ptr)   AccessChain 55(data) 202 82
+                                Store 215 214
                                 Branch 47
-             217:               Label
-             218:      6(int)   Load 8(invocation)
-             219:     59(ptr)   AccessChain 55(data) 57 57 58
-             220:   48(float)   Load 219
-             221:   48(float)   SubgroupFirstInvocationKHR 220
-             222:     59(ptr)   AccessChain 55(data) 218 57 58
-                                Store 222 221
-             223:      6(int)   Load 8(invocation)
-             224:     69(ptr)   AccessChain 55(data) 67 57
-             225:   49(fvec4)   Load 224
-             226:   68(fvec2)   VectorShuffle 225 225 0 1
-             227:   68(fvec2)   SubgroupFirstInvocationKHR 226
-             228:     69(ptr)   AccessChain 55(data) 223 57
-             229:   49(fvec4)   Load 228
-             230:   49(fvec4)   VectorShuffle 229 227 4 5 2 3
-                                Store 228 230
-             231:      6(int)   Load 8(invocation)
-             232:     69(ptr)   AccessChain 55(data) 83 57
-             233:   49(fvec4)   Load 232
-             234:   84(fvec3)   VectorShuffle 233 233 0 1 2
-             235:   84(fvec3)   SubgroupFirstInvocationKHR 234
-             236:     69(ptr)   AccessChain 55(data) 231 57
-             237:   49(fvec4)   Load 236
-             238:   49(fvec4)   VectorShuffle 237 235 4 5 6 3
-                                Store 236 238
-             239:      6(int)   Load 8(invocation)
-             240:     69(ptr)   AccessChain 55(data) 100 57
-             241:   49(fvec4)   Load 240
-             242:   49(fvec4)   SubgroupFirstInvocationKHR 241
-             243:     69(ptr)   AccessChain 55(data) 239 57
-                                Store 243 242
-             244:      6(int)   Load 8(invocation)
-             245:    115(ptr)   AccessChain 55(data) 57 67 58
-             246:     50(int)   Load 245
-             247:     50(int)   SubgroupFirstInvocationKHR 246
-             248:    115(ptr)   AccessChain 55(data) 244 67 58
-                                Store 248 247
-             249:      6(int)   Load 8(invocation)
-             250:    123(ptr)   AccessChain 55(data) 67 67
-             251:   51(ivec4)   Load 250
-             252:  122(ivec2)   VectorShuffle 251 251 0 1
-             253:  122(ivec2)   SubgroupFirstInvocationKHR 252
-             254:    123(ptr)   AccessChain 55(data) 249 67
-             255:   51(ivec4)   Load 254
-             256:   51(ivec4)   VectorShuffle 255 253 4 5 2 3
-                                Store 254 256
-             257:      6(int)   Load 8(invocation)
-             258:    123(ptr)   AccessChain 55(data) 83 67
-             259:   51(ivec4)   Load 258
-             260:  137(ivec3)   VectorShuffle 259 259 0 1 2
-             261:  137(ivec3)   SubgroupFirstInvocationKHR 260
-             262:    123(ptr)   AccessChain 55(data) 257 67
-             263:   51(ivec4)   Load 262
-             264:   51(ivec4)   VectorShuffle 263 261 4 5 6 3
-                                Store 262 264
-             265:      6(int)   Load 8(invocation)
-             266:    123(ptr)   AccessChain 55(data) 100 67
-             267:   51(ivec4)   Load 266
-             268:   51(ivec4)   SubgroupFirstInvocationKHR 267
-             269:    123(ptr)   AccessChain 55(data) 265 67
-                                Store 269 268
-             270:      6(int)   Load 8(invocation)
-             271:    167(ptr)   AccessChain 55(data) 57 83 58
-             272:      6(int)   Load 271
-             273:      6(int)   SubgroupFirstInvocationKHR 272
-             274:    167(ptr)   AccessChain 55(data) 270 83 58
-                                Store 274 273
-             275:      6(int)   Load 8(invocation)
-             276:    174(ptr)   AccessChain 55(data) 67 83
-             277:   38(ivec4)   Load 276
-             278:   42(ivec2)   VectorShuffle 277 277 0 1
-             279:   42(ivec2)   SubgroupFirstInvocationKHR 278
-             280:    174(ptr)   AccessChain 55(data) 275 83
-             281:   38(ivec4)   Load 280
-             282:   38(ivec4)   VectorShuffle 281 279 4 5 2 3
-                                Store 280 282
-             283:      6(int)   Load 8(invocation)
-             284:    174(ptr)   AccessChain 55(data) 83 83
-             285:   38(ivec4)   Load 284
-             286:  188(ivec3)   VectorShuffle 285 285 0 1 2
-             287:  188(ivec3)   SubgroupFirstInvocationKHR 286
-             288:    174(ptr)   AccessChain 55(data) 283 83
-             289:   38(ivec4)   Load 288
-             290:   38(ivec4)   VectorShuffle 289 287 4 5 6 3
-                                Store 288 290
-             291:      6(int)   Load 8(invocation)
-             292:    174(ptr)   AccessChain 55(data) 100 83
-             293:   38(ivec4)   Load 292
-             294:   38(ivec4)   SubgroupFirstInvocationKHR 293
-             295:    174(ptr)   AccessChain 55(data) 291 83
-                                Store 295 294
+             216:               Label
+             217:      6(int)   Load 8(invocation)
+             218:     59(ptr)   AccessChain 55(data) 57 57 58
+             219:   48(float)   Load 218
+             220:   48(float)   SubgroupFirstInvocationKHR 219
+             221:     59(ptr)   AccessChain 55(data) 217 57 58
+                                Store 221 220
+             222:      6(int)   Load 8(invocation)
+             223:     68(ptr)   AccessChain 55(data) 66 57
+             224:   49(fvec4)   Load 223
+             225:   67(fvec2)   VectorShuffle 224 224 0 1
+             226:   67(fvec2)   SubgroupFirstInvocationKHR 225
+             227:     68(ptr)   AccessChain 55(data) 222 57
+             228:   49(fvec4)   Load 227
+             229:   49(fvec4)   VectorShuffle 228 226 4 5 2 3
+                                Store 227 229
+             230:      6(int)   Load 8(invocation)
+             231:     68(ptr)   AccessChain 55(data) 82 57
+             232:   49(fvec4)   Load 231
+             233:   83(fvec3)   VectorShuffle 232 232 0 1 2
+             234:   83(fvec3)   SubgroupFirstInvocationKHR 233
+             235:     68(ptr)   AccessChain 55(data) 230 57
+             236:   49(fvec4)   Load 235
+             237:   49(fvec4)   VectorShuffle 236 234 4 5 6 3
+                                Store 235 237
+             238:      6(int)   Load 8(invocation)
+             239:     68(ptr)   AccessChain 55(data) 99 57
+             240:   49(fvec4)   Load 239
+             241:   49(fvec4)   SubgroupFirstInvocationKHR 240
+             242:     68(ptr)   AccessChain 55(data) 238 57
+                                Store 242 241
+             243:      6(int)   Load 8(invocation)
+             244:    114(ptr)   AccessChain 55(data) 57 66 58
+             245:     50(int)   Load 244
+             246:     50(int)   SubgroupFirstInvocationKHR 245
+             247:    114(ptr)   AccessChain 55(data) 243 66 58
+                                Store 247 246
+             248:      6(int)   Load 8(invocation)
+             249:    122(ptr)   AccessChain 55(data) 66 66
+             250:   51(ivec4)   Load 249
+             251:  121(ivec2)   VectorShuffle 250 250 0 1
+             252:  121(ivec2)   SubgroupFirstInvocationKHR 251
+             253:    122(ptr)   AccessChain 55(data) 248 66
+             254:   51(ivec4)   Load 253
+             255:   51(ivec4)   VectorShuffle 254 252 4 5 2 3
+                                Store 253 255
+             256:      6(int)   Load 8(invocation)
+             257:    122(ptr)   AccessChain 55(data) 82 66
+             258:   51(ivec4)   Load 257
+             259:  136(ivec3)   VectorShuffle 258 258 0 1 2
+             260:  136(ivec3)   SubgroupFirstInvocationKHR 259
+             261:    122(ptr)   AccessChain 55(data) 256 66
+             262:   51(ivec4)   Load 261
+             263:   51(ivec4)   VectorShuffle 262 260 4 5 6 3
+                                Store 261 263
+             264:      6(int)   Load 8(invocation)
+             265:    122(ptr)   AccessChain 55(data) 99 66
+             266:   51(ivec4)   Load 265
+             267:   51(ivec4)   SubgroupFirstInvocationKHR 266
+             268:    122(ptr)   AccessChain 55(data) 264 66
+                                Store 268 267
+             269:      6(int)   Load 8(invocation)
+             270:    166(ptr)   AccessChain 55(data) 57 82 58
+             271:      6(int)   Load 270
+             272:      6(int)   SubgroupFirstInvocationKHR 271
+             273:    166(ptr)   AccessChain 55(data) 269 82 58
+                                Store 273 272
+             274:      6(int)   Load 8(invocation)
+             275:    173(ptr)   AccessChain 55(data) 66 82
+             276:   38(ivec4)   Load 275
+             277:   42(ivec2)   VectorShuffle 276 276 0 1
+             278:   42(ivec2)   SubgroupFirstInvocationKHR 277
+             279:    173(ptr)   AccessChain 55(data) 274 82
+             280:   38(ivec4)   Load 279
+             281:   38(ivec4)   VectorShuffle 280 278 4 5 2 3
+                                Store 279 281
+             282:      6(int)   Load 8(invocation)
+             283:    173(ptr)   AccessChain 55(data) 82 82
+             284:   38(ivec4)   Load 283
+             285:  187(ivec3)   VectorShuffle 284 284 0 1 2
+             286:  187(ivec3)   SubgroupFirstInvocationKHR 285
+             287:    173(ptr)   AccessChain 55(data) 282 82
+             288:   38(ivec4)   Load 287
+             289:   38(ivec4)   VectorShuffle 288 286 4 5 6 3
+                                Store 287 289
+             290:      6(int)   Load 8(invocation)
+             291:    173(ptr)   AccessChain 55(data) 99 82
+             292:   38(ivec4)   Load 291
+             293:   38(ivec4)   SubgroupFirstInvocationKHR 292
+             294:    173(ptr)   AccessChain 55(data) 290 82
+                                Store 294 293
                                 Branch 47
               47:             Label
                               Return
diff --git a/Test/baseResults/tokenPaste.vert.out b/Test/baseResults/tokenPaste.vert.out
new file mode 100755
index 0000000..b0f7d10
--- /dev/null
+++ b/Test/baseResults/tokenPaste.vert.out
@@ -0,0 +1,112 @@
+tokenPaste.vert
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+ERROR: 0:38: '##' : unexpected location 
+ERROR: 0:40: '##' : unexpected location; end of replacement list 
+ERROR: 0:49: '##' : combined tokens are too long 
+ERROR: 0:52: '##' : not supported for these tokens 
+ERROR: 0:69: '##' : combined token is invalid 
+ERROR: 5 compilation errors.  No code generated.
+
+
+Shader version: 450
+ERROR: node is still EOpNull!
+0:52  Sequence
+0:52    move second child to first child (temp int)
+0:52      'a' (global int)
+0:52      Constant:
+0:52        11 (const int)
+0:58  Sequence
+0:58    move second child to first child (temp int)
+0:58      'cop' (global int)
+0:58      Constant:
+0:58        160 (const int)
+0:59  Sequence
+0:59    move second child to first child (temp bool)
+0:59      'dop' (global bool)
+0:59      Constant:
+0:59        true (const bool)
+0:63  Function Definition: ShouldntExpandToThis( (global void)
+0:63    Function Parameters: 
+0:65    Sequence
+0:65      Sequence
+0:65        move second child to first child (temp int)
+0:65          'e' (temp int)
+0:65          Constant:
+0:65            16 (const int)
+0:66      right shift second child into first child (temp int)
+0:66        'e' (temp int)
+0:66        Constant:
+0:66          2 (const int)
+0:69      Sequence
+0:69        move second child to first child (temp bool)
+0:69          'f' (temp bool)
+0:69          Compare Greater Than (temp bool)
+0:69            'e' (temp int)
+0:69            Constant:
+0:69              5 (const int)
+0:?   Linker Objects
+0:?     'SecondExpansion' (global int)
+0:?     'PostPasteExpansion' (global int)
+0:?     'foo27' (global float)
+0:?     'foo155' (uniform float)
+0:?     'foo719' (global float)
+0:?     'barfoo' (uniform float)
+0:?     'argless' (global float)
+0:?     'dc1' (global float)
+0:?     'dc2' (global float)
+0:?     'foo875' (uniform float)
+0:?     'ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345' (global float)
+0:?     'a' (global int)
+0:?     'aop' (const int)
+0:?       10 (const int)
+0:?     'bop' (const int)
+0:?       4 (const int)
+0:?     'cop' (global int)
+0:?     'dop' (global bool)
+0:?     'gl_VertexID' (gl_VertexId int VertexId)
+0:?     'gl_InstanceID' (gl_InstanceId int InstanceId)
+
+
+Linked vertex stage:
+
+ERROR: Linking vertex stage: Missing entry point: Each stage requires one entry point
+
+Shader version: 450
+ERROR: node is still EOpNull!
+0:52  Sequence
+0:52    move second child to first child (temp int)
+0:52      'a' (global int)
+0:52      Constant:
+0:52        11 (const int)
+0:58  Sequence
+0:58    move second child to first child (temp int)
+0:58      'cop' (global int)
+0:58      Constant:
+0:58        160 (const int)
+0:59  Sequence
+0:59    move second child to first child (temp bool)
+0:59      'dop' (global bool)
+0:59      Constant:
+0:59        true (const bool)
+0:?   Linker Objects
+0:?     'SecondExpansion' (global int)
+0:?     'PostPasteExpansion' (global int)
+0:?     'foo27' (global float)
+0:?     'foo155' (uniform float)
+0:?     'foo719' (global float)
+0:?     'barfoo' (uniform float)
+0:?     'argless' (global float)
+0:?     'dc1' (global float)
+0:?     'dc2' (global float)
+0:?     'foo875' (uniform float)
+0:?     'ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345' (global float)
+0:?     'a' (global int)
+0:?     'aop' (const int)
+0:?       10 (const int)
+0:?     'bop' (const int)
+0:?       4 (const int)
+0:?     'cop' (global int)
+0:?     'dop' (global bool)
+0:?     'gl_VertexID' (gl_VertexId int VertexId)
+0:?     'gl_InstanceID' (gl_InstanceId int InstanceId)
+
diff --git a/Test/hlsl.array.implicit-size.frag b/Test/hlsl.array.implicit-size.frag
index 78a9283..e7a54f4 100644
--- a/Test/hlsl.array.implicit-size.frag
+++ b/Test/hlsl.array.implicit-size.frag
@@ -26,6 +26,7 @@
 {
     // local array sized from initializers
     float l_array[] = { 1, 2, 3 };
+    int idx;
 
     ps_output.color = g_array[0] + g_array[4] + l_array[1] + g_mystruct[0].f + g_array[idx];
 }
diff --git a/Test/hlsl.identifier.sample.frag b/Test/hlsl.identifier.sample.frag
index 3281a9a..d3f8242 100644
--- a/Test/hlsl.identifier.sample.frag
+++ b/Test/hlsl.identifier.sample.frag
@@ -12,7 +12,7 @@
 {
     // HLSL allows this as an identifier as well.
     // However, this is not true of other qualifier keywords such as "linear".
-    int sample = 3;
+    float4 sample = float4(3,4,5,6);
 
-    return float4(0,0,0,0);
+    return sample.rgba; // 'sample' can participate in an expression.
 }
diff --git a/Test/spv.GeometryShaderPassthrough.geom b/Test/spv.GeometryShaderPassthrough.geom
new file mode 100644
index 0000000..9e6fe4c
--- /dev/null
+++ b/Test/spv.GeometryShaderPassthrough.geom
@@ -0,0 +1,17 @@
+#version 450

+#extension GL_NV_geometry_shader_passthrough : require

+

+layout(triangles) in;

+

+layout(passthrough) in gl_PerVertex {

+    vec4 gl_Position;

+};

+

+layout(passthrough) in Inputs {

+vec2 texcoord;

+vec4 baseColor;

+};

+

+void main()

+{

+}
\ No newline at end of file
diff --git a/Test/spv.sampleMaskOverrideCoverage.frag b/Test/spv.sampleMaskOverrideCoverage.frag
new file mode 100644
index 0000000..dd84062
--- /dev/null
+++ b/Test/spv.sampleMaskOverrideCoverage.frag
@@ -0,0 +1,7 @@
+#version 450
+#extension GL_NV_sample_mask_override_coverage : enable
+in vec4 color;
+layout(override_coverage) out int gl_SampleMask[];
+void main() {
+    gl_SampleMask[0] = int(0xFFFFFFFF);
+}
\ No newline at end of file
diff --git a/Test/tokenPaste.vert b/Test/tokenPaste.vert
new file mode 100644
index 0000000..c30892f
--- /dev/null
+++ b/Test/tokenPaste.vert
@@ -0,0 +1,70 @@
+#version 450
+
+// side test verifies multiple rounds of argument expansion
+#define bear SecondExpansion
+#define mmmB bear
+#define mmmA(a) a
+int mmmA(mmmB);                    // mmmB -> bear, and then in mmmA(), bear -> SecondExpansion
+
+// pasting skips the first round of expansion
+#define mmcatmmdog PostPasteExpansion
+#define mmcat cat
+#define mmdog dog
+#define mmp(a,b) a## b
+int mmp(mmcat, mmdog);             // mmcat/mmdog not expanded, mmcatmmdog -> PostPasteExpansion
+
+// multi-token pre
+#define mmtokpastepre(a) a##27
+mmtokpastepre(float foo);          // should declare "float foo27;"
+
+// multi-token post
+#define mmtokpastepost(a) uni ##a
+mmtokpastepost(form float foo155); // should declare "uniform float foo155;"
+
+// non-first argument
+#define foo ShouldntExpandToThis
+#define semi ;
+#define bothpaste(a,b) a##b
+float bothpaste(foo, 719);          // should declare "float foo719;"
+#define secpaste(a,b) a bar ## b
+secpaste(uniform float, foo semi)   // should declare "uniform float barfoo;"
+
+// no args
+#define noArg fl##oat
+noArg argless;
+
+// bad location
+#define bad1 ## float
+bad1 dc1;
+#define bad2 float ##
+bad2 dc2;
+
+// multiple ##
+#define multiPaste(a, b, c) a##or##b flo##at foo##c
+multiPaste(unif, m, 875);
+
+// too long
+#define simplePaste(a,b) a##b
+// 1020 + 5 characters
+float simplePaste(ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345, 12345);
+
+// non-identifiers
+int a = simplePaste(11,12);
+
+// operators
+#define MAKE_OP(L, R) L ## R

+const int aop = 10;

+const int bop = 4;

+int cop = aop MAKE_OP(<, <) bop;

+bool dop = aop MAKE_OP(!,=) bop;

+

+#define MAKE_OP3(L, M, R) L ## M ## R

+

+void foo()

+{

+    int e = 16;

+    e MAKE_OP3(>,>,=) 2;

+

+    // recovery from bad op

+    bool f = e MAKE_OP(>,!) 5;

+}
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 8745c7a..ae40465 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -599,6 +599,9 @@
         layoutFormat = ElfNone;
 
         layoutPushConstant = false;
+#ifdef NV_EXTENSIONS
+        layoutPassthrough = false;
+#endif
     }
     bool hasLayout() const
     {
@@ -652,6 +655,10 @@
 
     bool layoutPushConstant;
 
+#ifdef NV_EXTENSIONS
+    bool layoutPassthrough;
+#endif
+
     bool hasUniformLayout() const
     {
         return hasMatrix() ||
@@ -920,6 +927,10 @@
     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;
@@ -939,6 +950,9 @@
         earlyFragmentTests = false;
         layoutDepth = EldNone;
         blendEquation = false;
+#ifdef NV_EXTENSIONS 
+        layoutOverrideCoverage = false;
+#endif
     }
 
     // Merge in characteristics from the 'src' qualifier.  They can override when
@@ -975,6 +989,10 @@
             layoutDepth = src.layoutDepth;
         if (src.blendEquation)
             blendEquation = src.blendEquation;
+#ifdef NV_EXTENSIONS 
+        if (src.layoutOverrideCoverage)
+            layoutOverrideCoverage = src.layoutOverrideCoverage;
+#endif 
     }
 };
 
@@ -1525,6 +1543,13 @@
                     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 ");
+#endif
+
+
                 p += snprintf(p, end - p, ") ");
             }
         }
diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h
index 5fda0eb..5306125 100644
--- a/glslang/Include/revision.h
+++ b/glslang/Include/revision.h
@@ -2,5 +2,5 @@
 // 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.1689"
-#define GLSLANG_DATE "12-Dec-2016"
+#define GLSLANG_REVISION "Overload400-PrecQual.1721"
+#define GLSLANG_DATE "21-Dec-2016"
diff --git a/glslang/MachineIndependent/Constant.cpp b/glslang/MachineIndependent/Constant.cpp
index 804626f..61b6f67 100644
--- a/glslang/MachineIndependent/Constant.cpp
+++ b/glslang/MachineIndependent/Constant.cpp
@@ -57,7 +57,7 @@
     u.d = x;
     int bitPatternL = u.i[0];
     int bitPatternH = u.i[1];
-    return (bitPatternH & 0x7ff80000) == 0x7ff80000 && 
+    return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
            ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
 }
 
@@ -68,7 +68,7 @@
     u.d = x;
     int bitPatternL = u.i[0];
     int bitPatternH = u.i[1];
-    return (bitPatternH & 0x7ff00000) == 0x7ff00000 && 
+    return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
            (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
 }
 
@@ -131,7 +131,7 @@
             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);            
+            // for a case like vec4 f = 1.2 + vec4(2,3,4,5);
             newComps = constComps;
             rightUnionArray = rightNode->getConstArray();
             TConstUnionArray smearedArray(newComps, getConstArray()[0]);
@@ -626,7 +626,7 @@
 //
 // 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 (! areAllChildConst(aggrNode))
@@ -802,7 +802,7 @@
                 break;
             case EOpSmoothStep:
             {
-                double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) / 
+                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;
@@ -841,7 +841,7 @@
             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).
+            // 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)
@@ -968,7 +968,7 @@
 }
 
 //
-// Make a constant vector node or constant scalar node, representing a given 
+// Make a constant vector node or constant scalar node, representing a given
 // constant vector and constant swizzle into it.
 //
 TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc& loc)
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 9b6d4c6..999fd5d 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -2241,7 +2241,7 @@
 {
     TOperator op = node.getOp();
     TIntermSequence& args = node.getSequence();
-    const int numArgs = args.size();
+    const int numArgs = static_cast<int>(args.size());
 
     // Presently, only hlsl does intrinsic promotions.
     if (getSource() != EShSourceHlsl)
diff --git a/glslang/MachineIndependent/ParseContextBase.cpp b/glslang/MachineIndependent/ParseContextBase.cpp
index d084af8..d86e19d 100644
--- a/glslang/MachineIndependent/ParseContextBase.cpp
+++ b/glslang/MachineIndependent/ParseContextBase.cpp
@@ -472,7 +472,7 @@
 void TParseContextBase::finish()
 {
     if (!parsingBuiltins) {
-        // Transfer te linkage symbols to AST nodes
+        // 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);
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index ed043e0..67bb883 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -604,7 +604,11 @@
 void TParseContext::ioArrayCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
 {
     if (! type.isArray() && ! symbolTable.atBuiltInLevel()) {
-        if (type.getQualifier().isArrayedIo(language))
+        if (type.getQualifier().isArrayedIo(language)
+#ifdef NV_EXTENSIONS
+            && !type.getQualifier().layoutPassthrough
+#endif
+           )
             error(loc, "type must be an array:", type.getStorageQualifierString(), identifier.c_str());
     }
 }
@@ -3304,6 +3308,9 @@
          identifier == "gl_BackSecondaryColor"                                                      ||
          identifier == "gl_SecondaryColor"                                                          ||
         (identifier == "gl_Color"               && language == EShLangFragment)                     ||
+#ifdef NV_EXTENSIONS
+         identifier == "gl_SampleMask"                                                              ||
+#endif
          identifier == "gl_TexCoord") {
 
         // Find the existing symbol, if any.
@@ -3381,8 +3388,16 @@
                 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();
+        }
+#endif
+
         // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
 
         return symbol;
@@ -3448,6 +3463,20 @@
     //  - 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()) {
@@ -3917,6 +3946,14 @@
                 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);
 
@@ -4005,6 +4042,13 @@
                 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
     }
     error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
 }
@@ -4310,6 +4354,11 @@
 
         if (src.layoutPushConstant)
             dst.layoutPushConstant = true;
+
+#ifdef NV_EXTENSIONS
+        if (src.layoutPassthrough)
+            dst.layoutPassthrough = true;
+#endif
     }
 }
 
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 6234db6..f850f08 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -49,8 +49,7 @@
 #include "SymbolTable.h"
 #include "localintermediate.h"
 #include "Scan.h"
-#include <functional>
-
+#include <cstdarg>
 #include <functional>
 
 namespace glslang {
@@ -238,23 +237,23 @@
     bool obeyPrecisionQualifiers() const { return precisionManager.respectingPrecisionQualifiers(); };
     void setPrecisionDefaults();
 
-    void setLimits(const TBuiltInResource&);
-    bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
+    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);
-    bool lineContinuationCheck(const TSourceLoc&, bool endOfComment);
-    bool lineDirectiveShouldSetNextLine() const;
+    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>&);
+    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*&);
+    void makeEditable(TSymbol*&) override;
     bool isIoResizeArray(const TType&) const;
     void fixIoArraySize(const TSourceLoc&, TType&);
     void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
diff --git a/glslang/MachineIndependent/Scan.cpp b/glslang/MachineIndependent/Scan.cpp
index 3750645..3ea316d 100644
--- a/glslang/MachineIndependent/Scan.cpp
+++ b/glslang/MachineIndependent/Scan.cpp
@@ -638,13 +638,14 @@
     do {
         parserToken = &token;
         TPpToken ppToken;
-        tokenText = pp->tokenize(&ppToken);
-        if (tokenText == nullptr || tokenText[0] == 0)
+        int token = pp->tokenize(ppToken);
+        if (token == EndOfInput)
             return 0;
 
+        tokenText = ppToken.name;
         loc = ppToken.loc;
         parserToken->sType.lex.loc = loc;
-        switch (ppToken.token) {
+        switch (token) {
         case ';':  afterType = false;   return SEMICOLON;
         case ',':  afterType = false;   return COMMA;
         case ':':                       return COLON;
@@ -673,11 +674,11 @@
             parseContext.error(loc, "illegal use of escape character", "\\", "");
             break;
 
-        case PpAtomAdd:                return ADD_ASSIGN;
-        case PpAtomSub:                return SUB_ASSIGN;
-        case PpAtomMul:                return MUL_ASSIGN;
-        case PpAtomDiv:                return DIV_ASSIGN;
-        case PpAtomMod:                return MOD_ASSIGN;
+        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;
@@ -720,7 +721,7 @@
 
         default:
             char buf[2];
-            buf[0] = (char)ppToken.token;
+            buf[0] = token;
             buf[1] = 0;
             parseContext.error(loc, "unexpected token", buf, "");
             break;
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index e50b12f..9038a7f 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -868,7 +868,7 @@
         // 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 token;
+        glslang::TPpToken ppToken;
 
         parseContext.setScanner(&input);
         ppContext.setInput(input, versionWillBeError);
@@ -931,29 +931,33 @@
         });
 
         int lastToken = EndOfInput; // lastToken records the last token processed.
-        while (const char* tok = ppContext.tokenize(&token)) {
+        do {
+            int token = ppContext.tokenize(ppToken);
+            if (token == EndOfInput)
+                break;
+
             bool isNewString = lineSync.syncToMostRecentString();
-            bool isNewLine = lineSync.syncToLine(token.loc.line);
+            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(token.loc.column - 1, ' ');
+                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.token) == std::string::npos) &&
+                (unNeededSpaceTokens.find((char)token) == std::string::npos) &&
                 (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
-                (noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) {
+                (noSpaceBeforeTokens.find((char)token) == std::string::npos)) {
                 outputStream << " ";
             }
-            lastToken = token.token;
-            outputStream << tok;
-        }
+            lastToken = token;
+            outputStream << ppToken.name;
+        } while (true);
         outputStream << std::endl;
         *outputString = outputStream.str();
 
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 8a29cb3..afedb4f 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -195,6 +195,11 @@
     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;
+#endif
+
     // AEP
     extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
     extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
@@ -302,6 +307,11 @@
             "#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"
+#endif
             ;
     }
 
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index 17baf3b..fe9764f 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -142,6 +142,10 @@
 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";
+#endif
 
 // AEP
 const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 3834fde..b8ce6d7 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -469,9 +469,17 @@
     case EShLangGeometry:
         if (inputPrimitive == ElgNone)
             error(infoSink, "At least one shader must specify an input layout primitive");
-        if (outputPrimitive == ElgNone)
+        if (outputPrimitive == ElgNone
+#ifdef NV_EXTENSIONS
+            && !getGeoPassthroughEXT()
+#endif
+            )
             error(infoSink, "At least one shader must specify an output layout primitive");
-        if (vertices == TQualifier::layoutNotSet)
+        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:
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 6f6db92..34875c2 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -151,6 +151,10 @@
         shiftUboBinding(0),
         autoMapBindings(false),
         flattenUniformArrays(false),
+#ifdef NV_EXTENSIONS 
+        layoutOverrideCoverage(false),
+        geoPassthroughEXT(false),
+#endif
         useUnknownFormat(false)
     {
         localSize[0] = 1;
@@ -387,6 +391,13 @@
     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*);
@@ -447,6 +458,11 @@
     bool xfbMode;
     bool multiStream;
 
+#ifdef NV_EXTENSIONS 
+    bool layoutOverrideCoverage;
+    bool geoPassthroughEXT;
+#endif
+
     typedef std::list<TCall> TGraph;
     TGraph callGraph;
 
diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp
index 824a69a..595b729 100644
--- a/glslang/MachineIndependent/preprocessor/Pp.cpp
+++ b/glslang/MachineIndependent/preprocessor/Pp.cpp
@@ -75,9 +75,6 @@
 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 \****************************************************************************/
-//
-// cpp.c
-//
 
 #define _CRT_SECURE_NO_WARNINGS
 
@@ -91,20 +88,12 @@
 
 namespace glslang {
 
-int TPpContext::InitCPP()
-{
-    pool = mem_CreatePool(0, 0);
-
-    return 1;
-}
-
 // Handle #define
 int TPpContext::CPPdefine(TPpToken* ppToken)
 {
     MacroSymbol mac;
-    Symbol *symb;
 
-    // get macro name
+    // get the macro name
     int token = scanToken(ppToken);
     if (token != PpAtomIdentifier) {
         parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
@@ -115,38 +104,36 @@
         parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
     }
 
-    // save the original atom
-    const int defAtom = ppToken->atom;
+    // save the macro name
+    const int defAtom = atomStrings.getAddAtom(ppToken->name);
 
     // gather parameters to the macro, between (...)
     token = scanToken(ppToken);
     if (token == '(' && ! ppToken->space) {
-        int argc = 0;
-        int args[maxMacroArgs];
+        mac.emptyArgs = 1;
         do {
             token = scanToken(ppToken);
-            if (argc == 0 && token == ')') 
+            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 (int a = 0; a < argc; ++a) {
-                if (args[a] == ppToken->atom) {
+            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) {
-                if (argc < maxMacroArgs)
-                    args[argc++] = ppToken->atom;
-                else
-                    parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", "");
-            }
+            if (! duplicate)
+                mac.args.push_back(argAtom);
             token = scanToken(ppToken);
         } while (token == ',');
         if (token != ')') {
@@ -154,15 +141,12 @@
 
             return token;
         }
-        mac.argc = argc;
-        mac.args = (int*)mem_Alloc(pool, argc * sizeof(int));
-        memcpy(mac.args, args, argc * sizeof(int));
+
         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
-    mac.body = new TokenStream;
     while (token != '\n' && token != EndOfInput) {
         RecordToken(mac.body, token, ppToken);
         token = scanToken(ppToken);
@@ -171,40 +155,36 @@
     }
 
     // check for duplicate definition
-    symb = LookUpSymbol(defAtom);
-    if (symb) {
-        if (! symb->mac.undef) {
+    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 (symb->mac.argc != mac.argc)
-                parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom));
+            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 {
-                for (int argc = 0; argc < mac.argc; argc++) {
-                    if (symb->mac.args[argc] != mac.args[argc])
-                        parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom));
-                }
-                RewindTokenStream(symb->mac.body);
+                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(symb->mac.body, &oldPpToken);
+                    oldToken = ReadToken(existing->body, &oldPpToken);
                     newToken = ReadToken(mac.body, &newPpToken);
                     if (oldToken != newToken || oldPpToken != newPpToken) {
-                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom));
+                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
                         break; 
                     }
                 } while (newToken > 0);
             }
         }
+        *existing = mac;
     } else
-        symb = AddSymbol(defAtom);
-
-    delete symb->mac.body;
-    symb->mac = mac;
+        addMacroDef(defAtom, mac);
 
     return '\n';
 }
@@ -213,7 +193,6 @@
 int TPpContext::CPPundef(TPpToken* ppToken)
 {
     int token = scanToken(ppToken);
-    Symbol *symb;
     if (token != PpAtomIdentifier) {
         parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
 
@@ -222,10 +201,9 @@
 
     parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
 
-    symb = LookUpSymbol(ppToken->atom);
-    if (symb) {
-        symb->mac.undef = 1;
-    }
+    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", "");
@@ -240,7 +218,6 @@
 */
 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
 {
-    int atom;
     int depth = 0;
     int token = scanToken(ppToken);
 
@@ -259,13 +236,13 @@
         if ((token = scanToken(ppToken)) != PpAtomIdentifier)
             continue;
 
-        atom = ppToken->atom;
-        if (atom == PpAtomIf || atom == PpAtomIfdef || atom == PpAtomIfndef) {
+        int nextAtom = atomStrings.getAtom(ppToken->name);
+        if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
             depth++; 
             ifdepth++; 
             elsetracker++;
-        } else if (atom == PpAtomEndif) {
-            token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
+        } else if (nextAtom == PpAtomEndif) {
+            token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
             elseSeen[elsetracker] = false;
             --elsetracker;
             if (depth == 0) {
@@ -277,12 +254,12 @@
             --depth;
             --ifdepth;
         } else if (matchelse && depth == 0) {
-            if (atom == PpAtomElse) {
+            if (nextAtom == PpAtomElse) {
                 elseSeen[elsetracker] = true;
-                token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
+                token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
                 // found the #else we are looking for
                 break;
-            } else if (atom == PpAtomElif) {
+            } else if (nextAtom == PpAtomElif) {
                 if (elseSeen[elsetracker])
                     parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
                 /* we decrement ifdepth here, because CPPif will increment
@@ -295,13 +272,13 @@
 
                 return CPPif(ppToken);
             }
-        } else if (atom == PpAtomElse) {
+        } else if (nextAtom == PpAtomElse) {
             if (elseSeen[elsetracker])
                 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
             else
                 elseSeen[elsetracker] = true;
-            token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
-        } else if (atom == PpAtomElif) {
+            token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
+        } else if (nextAtom == PpAtomElif) {
             if (elseSeen[elsetracker])
                 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
         }
@@ -311,21 +288,21 @@
 }
 
 // Call when there should be no more tokens left on a line.
-int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token)
+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 (atom == PpAtomElse)
+        if (contextAtom == PpAtomElse)
             label = "#else";
-        else if (atom == PpAtomElif)
+        else if (contextAtom == PpAtomElif)
             label = "#elif";
-        else if (atom == PpAtomEndif)
+        else if (contextAtom == PpAtomEndif)
             label = "#endif";
-        else if (atom == PpAtomIf)
+        else if (contextAtom == PpAtomIf)
             label = "#if";
-        else if (atom == PpAtomLine)
+        else if (contextAtom == PpAtomLine)
             label = "#line";
         else
             label = "";
@@ -413,7 +390,7 @@
 {
     TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
     if (token == PpAtomIdentifier) {
-        if (ppToken->atom == PpAtomDefined) {
+        if (strcmp("defined", ppToken->name) == 0) {
             bool needclose = 0;
             token = scanToken(ppToken);
             if (token == '(') {
@@ -427,8 +404,9 @@
 
                 return token;
             }
-            Symbol* s = LookUpSymbol(ppToken->atom);
-            res = s ? ! s->mac.undef : 0;
+
+            MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
+            res = macro != nullptr ? !macro->undef : 0;
             token = scanToken(ppToken);
             if (needclose) {
                 if (token != ')') {
@@ -520,8 +498,8 @@
 // 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 && ppToken->atom != PpAtomDefined) {
-        int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false);
+    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;
@@ -568,7 +546,6 @@
 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
 {
     int token = scanToken(ppToken);
-    int name = ppToken->atom;
     if (++ifdepth > maxIfNesting) {
         parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
         return 0;
@@ -580,14 +557,14 @@
         else 
             parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
     } else {
-        Symbol *s = LookUpSymbol(name);
+        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 (((s && !s->mac.undef) ? 1 : 0) != defined)
+        if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
             token = CPPelse(1, ppToken);
     }
 
@@ -674,7 +651,7 @@
                 // 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 = GetAtomString(LookUpAddString(ppToken->name));
+                sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
                 parseContext.setCurrentSourceName(sourceName);
                 hasFile = true;
                 token = scanToken(ppToken);
@@ -713,7 +690,7 @@
         } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
             message.append(ppToken->name);
         } else {
-            message.append(GetAtomString(token));
+            message.append(atomStrings.getString(token));
         }
         message.append(" ");
         token = scanToken(ppToken);
@@ -790,9 +767,10 @@
         parseContext.notifyVersion(line, versionNumber, nullptr);
         return token;
     } else {
-        if (ppToken->atom != PpAtomCore &&
-            ppToken->atom != PpAtomCompatibility &&
-            ppToken->atom != PpAtomEs)
+        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);
@@ -853,7 +831,7 @@
     int token = scanToken(ppToken);
 
     if (token == PpAtomIdentifier) {
-        switch (ppToken->atom) {
+        switch (atomStrings.getAtom(ppToken->name)) {
         case PpAtomDefine:
             token = CPPdefine(ppToken);
             break;
@@ -933,36 +911,42 @@
     return token;
 }
 
-TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* a, TPpToken* ppToken, bool newLineOkay)
+// 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;
-    TokenStream *n;
-    RewindTokenStream(a);
+    RewindTokenStream(arg);
     do {
-        token = ReadToken(a, ppToken);
-        if (token == PpAtomIdentifier && LookUpSymbol(ppToken->atom))
+        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 a;
+        return nullptr;
 
-    n = new TokenStream;
+    // expand the argument
+    TokenStream* expandedArg = new TokenStream;
     pushInput(new tMarkerInput(this));
-    pushTokenStreamInput(a);
+    pushTokenStreamInput(arg);
     while ((token = scanToken(ppToken)) != tMarkerInput::marker) {
-        if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0)
+        if (token == PpAtomIdentifier && MacroExpand(ppToken, false, newLineOkay) != 0)
             continue;
-        RecordToken(n, token, ppToken);
+        RecordToken(*expandedArg, token, ppToken);
     }
     popInput();
-    delete a;
 
-    return n;
+    return expandedArg;
 }
 
 // 
-// Return the next token for a macro expansion, handling macro args.
+// 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)
 {
@@ -971,14 +955,50 @@
         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->argc - 1; i >= 0; i--)
-            if (mac->args[i] == ppToken->atom) 
+        for (i = mac->args.size() - 1; i >= 0; i--)
+            if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
                 break;
         if (i >= 0) {
-            pp->pushTokenStreamInput(args[i]);
+            TokenStream* arg = expandedArgs[i];
+            if (arg == nullptr || pasting)
+                arg = args[i];
+            pp->pushTokenStreamInput(*arg, prepaste);
 
             return pp->scanToken(ppToken);
         }
@@ -990,6 +1010,31 @@
     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)
 {
@@ -1005,17 +1050,18 @@
 }
 
 //
-// Check an identifier (atom) to see if it is a macro that should be expanded.
+// 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(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay)
+int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
 {
     ppToken->space = false;
-    switch (atom) {
+    int macroAtom = atomStrings.getAtom(ppToken->name);
+    switch (macroAtom) {
     case PpAtomLineMacro:
         ppToken->ival = parseContext.getCurrentLoc().line;
         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
@@ -1041,20 +1087,20 @@
         break;
     }
 
-    Symbol *sym = LookUpSymbol(atom);
+    MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
     int token;
     int depth = 0;
 
     // no recursive expansions
-    if (sym && sym->mac.busy)
+    if (macro != nullptr && macro->busy)
         return 0;
 
     // not expanding undefined macros
-    if ((! sym || sym->mac.undef) && ! expandUndef)
+    if ((macro == nullptr || macro->undef) && ! expandUndef)
         return 0;
 
     // 0 is the value of an undefined macro
-    if ((! sym || sym->mac.undef) && expandUndef) {
+    if ((macro == nullptr || macro->undef) && expandUndef) {
         pushInput(new tZeroInput(this));
         return -1;
     }
@@ -1062,49 +1108,50 @@
     tMacroInput *in = new tMacroInput(this);
 
     TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
-    in->mac = &sym->mac;
-    if (sym->mac.args) {
+    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", GetAtomString(atom));
+            parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom));
             UngetToken(token, ppToken);
-            ppToken->atom = atom;
-
             delete in;
             return 0;
         }
-        in->args.resize(in->mac->argc);
-        for (int i = 0; i < in->mac->argc; i++)
+        in->args.resize(in->mac->args.size());
+        for (size_t i = 0; i < in->mac->args.size(); i++)
             in->args[i] = new TokenStream;
-        int arg = 0;
+        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) {
-                    parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom));
+                    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", GetAtomString(atom));
+                        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", GetAtomString(atom));
+                    parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
                     delete in;
                     return 0;
                 }
-                if (in->mac->argc == 0 && token != ')')
+                if (in->mac->args.size() == 0 && token != ')')
                     break;
                 if (depth == 0 && (token == ',' || token == ')'))
                     break;
@@ -1112,20 +1159,20 @@
                     depth++;
                 if (token == ')')
                     depth--;
-                RecordToken(in->args[arg], token, ppToken);
+                RecordToken(*in->args[arg], token, ppToken);
                 tokenRecorded = true;
             }
             if (token == ')') {
-                if (in->mac->argc == 1 && tokenRecorded == 0)
+                if (in->mac->args.size() == 1 && tokenRecorded == 0)
                     break;
                 arg++;
                 break;
             }
             arg++;
-        } while (arg < in->mac->argc);
+        } while (arg < in->mac->args.size());
 
-        if (arg < in->mac->argc)
-            parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
+        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 != ')')) {
@@ -1137,19 +1184,22 @@
             }
 
             if (token == EndOfInput) {
-                parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom));
+                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", GetAtomString(atom));
+            parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
         }
-        for (int i = 0; i < in->mac->argc; i++)
-            in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay);
+
+        // 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);
-    sym->mac.busy = 1;
-    RewindTokenStream(sym->mac.body);
+    macro->busy = 1;
+    RewindTokenStream(macro->body);
 
     return 1;
 }
diff --git a/glslang/MachineIndependent/preprocessor/PpAtom.cpp b/glslang/MachineIndependent/preprocessor/PpAtom.cpp
index 2b21193..6948aad 100644
--- a/glslang/MachineIndependent/preprocessor/PpAtom.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpAtom.cpp
@@ -76,10 +76,6 @@
 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 \****************************************************************************/
 
-//
-// atom.c
-//
-
 #define _CRT_SECURE_NO_WARNINGS
 
 #include <cassert>
@@ -98,11 +94,12 @@
     const char* str;
 } tokens[] = {
 
-    { PpAtomAdd,            "+=" },
-    { PpAtomSub,            "-=" },
-    { PpAtomMul,            "*=" },
-    { PpAtomDiv,            "/=" },
-    { PpAtomMod,            "%=" },
+    { PPAtomAddAssign,      "+=" },
+    { PPAtomSubAssign,      "-=" },
+    { PPAtomMulAssign,      "*=" },
+    { PPAtomDivAssign,      "/=" },
+    { PPAtomModAssign,      "%=" },
+
     { PpAtomRight,          ">>" },
     { PpAtomLeft,           "<<" },
     { PpAtomAnd,            "&&" },
@@ -124,7 +121,6 @@
     { PpAtomIncrement,      "++" },
 
     { PpAtomDefine,         "define" },
-    { PpAtomDefined,        "defined" },
     { PpAtomUndef,          "undef" },
     { PpAtomIf,             "if" },
     { PpAtomElif,           "elif" },
@@ -154,47 +150,12 @@
 namespace glslang {
 
 //
-// Map a new or existing string to an atom, inventing a new atom if necessary.
-//
-int TPpContext::LookUpAddString(const char* s)
-{
-    auto it = atomMap.find(s);
-    if (it == atomMap.end()) {
-        AddAtomFixed(s, nextAtom);
-        return nextAtom++;
-    } else
-        return it->second;
-}
-
-//
-// Map an already created atom to its string.
-//
-const char* TPpContext::GetAtomString(int atom)
-{
-    if ((size_t)atom >= stringMap.size())
-        return "<bad token>";
-
-    const TString* atomString = stringMap[atom];
-
-    return atomString ? atomString->c_str() : "<bad token>";
-}
-
-//
-// Add forced mapping of string to atom.
-//
-void TPpContext::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, 0);
-    stringMap[atom] = &it->first;
-}
-
-//
 // Initialize the atom table.
 //
-void TPpContext::InitAtomTable()
+TStringAtomMap::TStringAtomMap()
 {
+    badToken.assign("<bad token>");
+
     // Add single character tokens to the atom table:
     const char* s = "~!%^&*()-+=|,.<>/?;:[]{}#\\";
     char t[2];
@@ -202,13 +163,13 @@
     t[1] = '\0';
     while (*s) {
         t[0] = *s;
-        AddAtomFixed(t, s[0]);
+        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);
+        addAtomFixed(tokens[ii].str, tokens[ii].val);
 
     nextAtom = PpAtomLast;
 }
diff --git a/glslang/MachineIndependent/preprocessor/PpContext.cpp b/glslang/MachineIndependent/preprocessor/PpContext.cpp
index 6791fef..e31127f 100644
--- a/glslang/MachineIndependent/preprocessor/PpContext.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpContext.cpp
@@ -83,13 +83,10 @@
 namespace glslang {
 
 TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) : 
-    preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false),
+    preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false),
     rootFileName(rootFileName),
     currentSourceFile(rootFileName)
 {
-    InitAtomTable();
-    InitScanner();
-
     ifdepth = 0;
     for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
         elseSeen[elsetracker] = false;
@@ -98,9 +95,6 @@
 
 TPpContext::~TPpContext()
 {
-    for (TSymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it)
-        delete it->second->mac.body;
-    mem_FreePool(pool);
     delete [] preamble;
 
     // free up the inputStack
diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h
index 013c90e..64f99ef 100644
--- a/glslang/MachineIndependent/preprocessor/PpContext.h
+++ b/glslang/MachineIndependent/preprocessor/PpContext.h
@@ -92,30 +92,85 @@
 
 class TPpToken {
 public:
-    TPpToken() : token(0), space(false), ival(0), dval(0.0), atom(0)
+    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 token == right.token && atom == right.atom &&
-               ival == right.ival && dval == right.dval &&
-               strcmp(name, right.name) == 0;
+        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;
-    int    token;
     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;
-    int    atom;
     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
@@ -128,7 +183,8 @@
 
     void setPreamble(const char* preamble, size_t length);
 
-    const char* tokenize(TPpToken* ppToken);
+    int tokenize(TPpToken& ppToken);
+    int tokenPaste(int token, TPpToken&);
 
     class tInput {
     public:
@@ -138,6 +194,8 @@
         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() {}
@@ -168,44 +226,33 @@
         size_t current;
     };
 
-    struct MemoryPool {
-        struct chunk        *next;
-        uintptr_t           free, end;
-        size_t              chunksize;
-        uintptr_t           alignmask;
-    };
-
     //
     // From Pp.cpp
     //
 
     struct MacroSymbol {
-        MacroSymbol() : argc(0), args(0), body(0), busy(0), undef(0) { }
-        int argc;
-        int *args;
-        TokenStream *body;
-        unsigned busy:1;
-        unsigned undef:1;
+        MacroSymbol() : emptyArgs(0), busy(0), undef(0) { }
+        TVector<int> args;
+        TokenStream body;
+        unsigned emptyArgs : 1;
+        unsigned busy      : 1;
+        unsigned undef     : 1;
     };
 
-    struct Symbol {
-        int atom;
-        MacroSymbol mac;
-    };
-
-    struct SymbolList {
-        struct SymbolList_Rec *next;
-        Symbol *symb;
-    };
-
-    MemoryPool *pool;
-    typedef TMap<int, Symbol*> TSymbolMap;
-    TSymbolMap symbols; // this has light use... just defined macros
+    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
@@ -235,8 +282,9 @@
     }
     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 maxMacroArgs = 64;
     static const int maxIfNesting = 64;
 
     int ifdepth;                  // current #if-#else-#endif nesting in the cpp.c file (pre-processor)    
@@ -245,24 +293,35 @@
 
     class tMacroInput : public tInput {
     public:
-        tMacroInput(TPpContext* pp) : tInput(pp) { }
+        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*);
-        virtual int getch() { assert(0); return EndOfInput; }
-        virtual void ungetch() { assert(0); }
+        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*)
+        virtual int scan(TPpToken*) override
         {
             if (done)
                 return EndOfInput;
@@ -270,17 +329,17 @@
 
             return marker;
         }
-        virtual int getch() { assert(0); return EndOfInput; }
-        virtual void ungetch() { assert(0); }
+        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*);
-        virtual int getch() { assert(0); return EndOfInput; }
-        virtual void ungetch() { assert(0); }
+        virtual int scan(TPpToken*) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
     };
 
     std::vector<tInput*> inputStack;
@@ -294,7 +353,6 @@
     // Used to obtain #include content.
     TShader::Includer& includer;
 
-    int InitCPP();
     int CPPdefine(TPpToken * ppToken);
     int CPPundef(TPpToken * ppToken);
     int CPPelse(int matchelse, TPpToken * ppToken);
@@ -310,44 +368,39 @@
     int CPPversion(TPpToken * ppToken);
     int CPPextension(TPpToken * ppToken);
     int readCPPline(TPpToken * ppToken);
-    TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken, bool newLineOkay);
-    int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay);
-
-    //
-    // from PpSymbols.cpp
-    //
-    Symbol *NewSymbol(int name);
-    Symbol *AddSymbol(int atom);
-    Symbol *LookUpSymbol(int atom);
+    TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay);
+    int MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay);
 
     //
     // From PpTokens.cpp
     //
-    void lAddByte(TokenStream *fTok, unsigned char fVal);
-    int lReadByte(TokenStream *pTok);
-    void lUnreadByte(TokenStream *pTok);
-    void RecordToken(TokenStream* pTok, int token, TPpToken* ppToken);
-    void RewindTokenStream(TokenStream *pTok);
-    int ReadToken(TokenStream* pTok, TPpToken* ppToken);
-    void pushTokenStreamInput(TokenStream *ts);
-    void UngetToken(int token, TPpToken* ppToken);
+    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) : tInput(pp), tokens(t) { }
-        virtual int scan(TPpToken *);
-        virtual int getch() { assert(0); return EndOfInput; }
-        virtual void ungetch() { assert(0); }
+        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;
+        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 *);
-        virtual int getch() { assert(0); return EndOfInput; }
-        virtual void ungetch() { assert(0); }
+        virtual int scan(TPpToken *) override;
+        virtual int getch() override { assert(0); return EndOfInput; }
+        virtual void ungetch() override { assert(0); }
     protected:
         int token;
         TPpToken lval;
@@ -359,12 +412,12 @@
     class tStringInput : public tInput {
     public:
         tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { }
-        virtual int scan(TPpToken*);
+        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()
+        int getch() override
         {
             int ch = input->get();
 
@@ -402,7 +455,7 @@
         // 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()
+        void ungetch() override
         {
             input->unget();
 
@@ -516,7 +569,6 @@
         tStringInput stringInput;
     };
 
-    int InitScanner();
     int ScanFromString(char* s);
     void missingEndifCheck();
     int lFloatConst(int len, int ch, TPpToken* ppToken);
@@ -540,31 +592,9 @@
     }
 
     bool inComment;
-
-    //
-    // From PpAtom.cpp
-    //
-    typedef TUnorderedMap<TString, int> TAtomMap;
-    typedef TVector<const TString*> TStringMap;
-
-    TAtomMap atomMap;
-    TStringMap stringMap;
+    std::string rootFileName;
     std::stack<TShader::Includer::IncludeResult*> includeStack;
     std::string currentSourceFile;
-    std::string rootFileName;
-    int nextAtom;
-    void InitAtomTable();
-    void AddAtomFixed(const char* s, int atom);
-    int LookUpAddString(const char* s);
-    const char* GetAtomString(int atom);
-
-    //
-    // From PpMemory.cpp
-    //
-    MemoryPool *mem_CreatePool(size_t chunksize, unsigned align);
-    void mem_FreePool(MemoryPool*);
-    void *mem_Alloc(MemoryPool* p, size_t size);
-    int mem_AddCleanup(MemoryPool* p, void (*fn)(void *, void*), void* arg1, void* arg2);
 };
 
 } // end namespace glslang
diff --git a/glslang/MachineIndependent/preprocessor/PpMemory.cpp b/glslang/MachineIndependent/preprocessor/PpMemory.cpp
index 6158a38..4d0f32a 100644
--- a/glslang/MachineIndependent/preprocessor/PpMemory.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpMemory.cpp
@@ -76,86 +76,6 @@
 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 \****************************************************************************/
 
-#include <cstddef>
-#include <cstdlib>
-#include <cstring>
-
-#include "PpContext.h"
-
-// default alignment and chunksize, if called with 0 arguments
-#define CHUNKSIZE       (64*1024)
-#define ALIGN           8
-
 namespace glslang {
 
-struct chunk {
-    struct chunk        *next;
-};
-
-TPpContext::MemoryPool* TPpContext::mem_CreatePool(size_t chunksize, unsigned int align)
-{
-    if (align == 0)
-        align = ALIGN;
-    if (chunksize == 0)
-        chunksize = CHUNKSIZE;
-    if (align & (align - 1))
-        return nullptr;
-    if (chunksize < sizeof(MemoryPool))
-        return nullptr;
-    if (chunksize & (align - 1))
-        return nullptr;
-
-    MemoryPool *pool = (MemoryPool*)malloc(chunksize);
-    if (! pool)
-        return nullptr;
-
-    pool->next = 0;
-    pool->chunksize = chunksize;
-    pool->alignmask = (uintptr_t)(align) - 1;  
-    pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask;
-    pool->end = (uintptr_t)pool + chunksize;
-    
-    return pool;
-}
-
-void TPpContext::mem_FreePool(MemoryPool *pool)
-{
-    struct chunk *p, *next;
-
-    for (p = (struct chunk *)pool; p; p = next) {
-        next = p->next;
-        free(p);
-    }
-}
-
-void* TPpContext::mem_Alloc(MemoryPool *pool, size_t size)
-{
-    struct chunk *ch;
-    void *rv = (void *)pool->free;
-    size = (size + pool->alignmask) & ~pool->alignmask;
-    if (size <= 0) size = pool->alignmask;
-    pool->free += size;
-    if (pool->free > pool->end || pool->free < (uintptr_t)rv) {
-        size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) & ~pool->alignmask;
-        pool->free = (uintptr_t)rv;
-        if (minreq >= pool->chunksize) {
-            // request size is too big for the chunksize, so allocate it as
-            // a single chunk of the right size
-            ch = (struct chunk*)malloc(minreq);
-            if (! ch)
-                return nullptr;
-        } else {
-            ch = (struct chunk*)malloc(pool->chunksize);
-            if (! ch)
-                return nullptr;
-            pool->free = (uintptr_t)ch + minreq;
-            pool->end = (uintptr_t)ch + pool->chunksize;
-        }
-        ch->next = pool->next;
-        pool->next = ch;
-        rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask);
-    }
-    return rv;
-}
-
 } // end namespace glslang
diff --git a/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/glslang/MachineIndependent/preprocessor/PpScanner.cpp
index 518dbde..4bb7c93 100644
--- a/glslang/MachineIndependent/preprocessor/PpScanner.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpScanner.cpp
@@ -75,9 +75,6 @@
 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 \****************************************************************************/
-//
-// scanner.c
-//
 
 #define _CRT_SECURE_NO_WARNINGS
 
@@ -90,17 +87,6 @@
 
 namespace glslang {
 
-int TPpContext::InitScanner()
-{
-    // Add various atoms needed by the CPP line scanner:
-    if (!InitCPP())
-        return 0;
-
-    previous_token = '\n';
-
-    return 1;
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////// Floating point constants: /////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -261,7 +247,6 @@
 //
 int TPpContext::tStringInput::scan(TPpToken* ppToken)
 {
-    char* tokenText = ppToken->name;
     int AlreadyComplained = 0;
     int len = 0;
     int ch = 0;
@@ -300,7 +285,7 @@
         case 'z':
             do {
                 if (len < MaxTokenLength) {
-                    tokenText[len++] = (char)ch;
+                    ppToken->name[len++] = (char)ch;
                     ch = getch();
                 } else {
                     if (! AlreadyComplained) {
@@ -318,9 +303,8 @@
             if (len == 0)
                 continue;
 
-            tokenText[len] = '\0';
+            ppToken->name[len] = '\0';
             ungetch();
-            ppToken->atom = pp->LookUpAddString(tokenText);
             return PpAtomIdentifier;
         case '0':
             ppToken->name[len++] = (char)ch;
@@ -545,7 +529,7 @@
             if (ch == '-') {
                 return PpAtomDecrement;
             } else if (ch == '=') {
-                return PpAtomSub;
+                return PPAtomSubAssign;
             } else {
                 ungetch();
                 return '-';
@@ -555,7 +539,7 @@
             if (ch == '+') {
                 return PpAtomIncrement;
             } else if (ch == '=') {
-                return PpAtomAdd;
+                return PPAtomAddAssign;
             } else {
                 ungetch();
                 return '+';
@@ -563,7 +547,7 @@
         case '*':
             ch = getch();
             if (ch == '=') {
-                return PpAtomMul;
+                return PPAtomMulAssign;
             } else {
                 ungetch();
                 return '*';
@@ -571,7 +555,7 @@
         case '%':
             ch = getch();
             if (ch == '=') {
-                return PpAtomMod;
+                return PPAtomModAssign;
             } else {
                 ungetch();
                 return '%';
@@ -697,7 +681,7 @@
                 // loop again to get the next token...
                 break;
             } else if (ch == '=') {
-                return PpAtomDiv;
+                return PPAtomDivAssign;
             } else {
                 ungetch();
                 return '/';
@@ -707,13 +691,13 @@
             ch = getch();
             while (ch != '"' && ch != '\n' && ch != EndOfInput) {
                 if (len < MaxTokenLength) {
-                    tokenText[len] = (char)ch;
+                    ppToken->name[len] = (char)ch;
                     len++;
                     ch = getch();
                 } else
                     break;
             };
-            tokenText[len] = '\0';
+            ppToken->name[len] = '\0';
             if (ch != '"') {
                 ungetch();
                 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
@@ -729,31 +713,31 @@
 // The main functional entry point into the preprocessor, which will
 // scan the source strings to figure out and return the next processing token.
 //
-// Return string pointer to next token.
-// Return 0 when no more tokens.
+// Return the token, or EndOfInput when no more tokens.
 //
-const char* TPpContext::tokenize(TPpToken* ppToken)
+int TPpContext::tokenize(TPpToken& ppToken)
 {
-    int token = '\n';
-
     for(;;) {
-        token = scanToken(ppToken);
-        ppToken->token = token;
+        int token = scanToken(&ppToken);
+
+        // Handle token-pasting logic
+        token = tokenPaste(token, ppToken);
+
         if (token == EndOfInput) {
             missingEndifCheck();
-            return nullptr;
+            return EndOfInput;
         }
         if (token == '#') {
             if (previous_token == '\n') {
-                token = readCPPline(ppToken);
+                token = readCPPline(&ppToken);
                 if (token == EndOfInput) {
                     missingEndifCheck();
-                    return nullptr;
+                    return EndOfInput;
                 }
                 continue;
             } else {
-                parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", "");
-                return nullptr;
+                parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", "");
+                return EndOfInput;
             }
         }
         previous_token = token;
@@ -762,10 +746,9 @@
             continue;
 
         // expand macros
-        if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0)
+        if (token == PpAtomIdentifier && MacroExpand(&ppToken, false, true) != 0)
             continue;
 
-        const char* tokenString = nullptr;
         switch (token) {
         case PpAtomIdentifier:
         case PpAtomConstInt:
@@ -777,29 +760,110 @@
 #ifdef AMD_EXTENSIONS
         case PpAtomConstFloat16:
 #endif
-            tokenString = ppToken->name;
+            if (ppToken.name[0] == '\0')
+                continue;
             break;
         case PpAtomConstString:
-            if (parseContext.intermediate.getSource() == EShSourceHlsl) {
+            if (parseContext.intermediate.getSource() != EShSourceHlsl) {
                 // HLSL allows string literals.
-                tokenString = ppToken->name;
-            } else {
-                parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
+                parseContext.ppError(ppToken.loc, "string literals not supported", "\"\"", "");
+                continue;
             }
             break;
         case '\'':
-            parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
-            break;
+            parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
+            continue;
         default:
-            tokenString = GetAtomString(token);
+            strcpy(ppToken.name, atomStrings.getString(token));
             break;
         }
 
-        if (tokenString)
-            return tokenString;
+        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()
 {
diff --git a/glslang/MachineIndependent/preprocessor/PpSymbols.cpp b/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
index b7f1df5..585bf2c 100644
--- a/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
@@ -75,60 +75,3 @@
 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 \****************************************************************************/
-//
-// symbols.c
-//
-
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-
-#include "PpContext.h"
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////// Symbol Table Variables: ///////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-namespace glslang {
-
-/*
-* Allocate a new symbol node;
-*
-*/
-TPpContext::Symbol* TPpContext::NewSymbol(int atom)
-{
-    Symbol* lSymb;
-    char* pch;
-    size_t ii;
-
-    lSymb = (Symbol *) mem_Alloc(pool, sizeof(Symbol));
-    lSymb->atom = atom;
-
-    // Clear macro
-    pch = (char*) &lSymb->mac;
-    for (ii = 0; ii < sizeof(lSymb->mac); ii++)
-        *pch++ = 0;
-
-    return lSymb;
-}
-
-TPpContext::Symbol* TPpContext::AddSymbol(int atom)
-{
-    Symbol *lSymb;
-
-    lSymb = NewSymbol(atom);
-    symbols[lSymb->atom] = lSymb;
-
-    return lSymb;
-}
-
-TPpContext::Symbol* TPpContext::LookUpSymbol(int atom)
-{
-    TSymbolMap::iterator it = symbols.find(atom);
-    if (it == symbols.end())
-        return nullptr;
-    else
-        return it->second;
-}
-
-} // end namespace glslang
diff --git a/glslang/MachineIndependent/preprocessor/PpTokens.cpp b/glslang/MachineIndependent/preprocessor/PpTokens.cpp
index 23b617d..471f26c 100644
--- a/glslang/MachineIndependent/preprocessor/PpTokens.cpp
+++ b/glslang/MachineIndependent/preprocessor/PpTokens.cpp
@@ -95,32 +95,32 @@
 
 namespace glslang {
 
-void TPpContext::lAddByte(TokenStream *fTok, unsigned char fVal)
+void TPpContext::lAddByte(TokenStream& fTok, unsigned char fVal)
 {
-    fTok->data.push_back(fVal);
+    fTok.data.push_back(fVal);
 }
 
 /*
 * Get the next byte from a stream.
 */
-int TPpContext::lReadByte(TokenStream *pTok)
+int TPpContext::lReadByte(TokenStream& pTok)
 {
-    if (pTok->current < pTok->data.size())
-        return pTok->data[pTok->current++];
+    if (pTok.current < pTok.data.size())
+        return pTok.data[pTok.current++];
     else
         return EndOfInput;
 }
 
-void TPpContext::lUnreadByte(TokenStream *pTok)
+void TPpContext::lUnreadByte(TokenStream& pTok)
 {
-    if (pTok->current > 0)
-        --pTok->current;
+    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)
+void TPpContext::RecordToken(TokenStream& pTok, int token, TPpToken* ppToken)
 {
     const char* s;
     char* str = NULL;
@@ -160,19 +160,18 @@
 }
 
 /*
-* Reset a token stream in preperation for reading.
+* Reset a token stream in preparation for reading.
 */
-void TPpContext::RewindTokenStream(TokenStream *pTok)
+void TPpContext::RewindTokenStream(TokenStream& pTok)
 {
-    pTok->current = 0;
+    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 TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
 {
-    char* tokenText = ppToken->name;
     int ltoken, len;
     int ch;
 
@@ -183,13 +182,11 @@
     switch (ltoken) {
     case '#':
         // Check for ##, unless the current # is the last character
-        if (pTok->current < pTok->data.size()) {
+        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 (##)");
-                parseContext.error(ppToken->loc, "token pasting not implemented (internal error)", "##", "");
-                //return PpAtomPaste;
-                return ReadToken(pTok, ppToken);
+                ltoken = PpAtomPaste;
             } else
                 lUnreadByte(pTok);
         }
@@ -209,7 +206,7 @@
         ch = lReadByte(pTok);
         while (ch != 0 && ch != EndOfInput) {
             if (len < MaxTokenLength) {
-                tokenText[len] = (char)ch;
+                ppToken->name[len] = (char)ch;
                 len++;
                 ch = lReadByte(pTok);
             } else {
@@ -217,11 +214,10 @@
                 break;
             }
         }
-        tokenText[len] = 0;
+        ppToken->name[len] = 0;
 
         switch (ltoken) {
         case PpAtomIdentifier:
-            ppToken->atom = LookUpAddString(tokenText);
             break;
         case PpAtomConstString:
             break;
@@ -233,8 +229,8 @@
             ppToken->dval = atof(ppToken->name);
             break;
         case PpAtomConstInt:
-            if (len > 0 && tokenText[0] == '0') {
-                if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
+            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);
@@ -242,8 +238,8 @@
                 ppToken->ival = atoi(ppToken->name);
             break;
         case PpAtomConstUint:
-            if (len > 0 && tokenText[0] == '0') {
-                if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
+            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);
@@ -251,8 +247,8 @@
                 ppToken->ival = (int)strtoul(ppToken->name, 0, 10);
             break;
         case PpAtomConstInt64:
-            if (len > 0 && tokenText[0] == '0') {
-                if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
+            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);
@@ -260,8 +256,8 @@
                 ppToken->i64val = atoll(ppToken->name);
             break;
         case PpAtomConstUint64:
-            if (len > 0 && tokenText[0] == '0') {
-                if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
+            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);
@@ -276,12 +272,37 @@
 
 int TPpContext::tTokenInput::scan(TPpToken* ppToken)
 {
-    return pp->ReadToken(tokens, ppToken);
+    return pp->ReadToken(*tokens, ppToken);
 }
 
-void TPpContext::pushTokenStreamInput(TokenStream* ts)
+// 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()
 {
-    pushInput(new tTokenInput(this, ts));
+    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);
 }
 
diff --git a/glslang/MachineIndependent/preprocessor/PpTokens.h b/glslang/MachineIndependent/preprocessor/PpTokens.h
index c84431d..20aeb10 100644
--- a/glslang/MachineIndependent/preprocessor/PpTokens.h
+++ b/glslang/MachineIndependent/preprocessor/PpTokens.h
@@ -86,11 +86,11 @@
 
     // Operators
 
-    PpAtomAdd,
-    PpAtomSub,
-    PpAtomMul,
-    PpAtomDiv,
-    PpAtomMod,
+    PPAtomAddAssign,
+    PPAtomSubAssign,
+    PPAtomMulAssign,
+    PPAtomDivAssign,
+    PPAtomModAssign,
 
     PpAtomRight,
     PpAtomLeft,
@@ -134,7 +134,6 @@
     // preprocessor "keywords"
 
     PpAtomDefine,
-    PpAtomDefined,
     PpAtomUndef,
 
     PpAtomIf,
diff --git a/gtests/AST.FromFile.cpp b/gtests/AST.FromFile.cpp
index a2e961e..7070533 100644
--- a/gtests/AST.FromFile.cpp
+++ b/gtests/AST.FromFile.cpp
@@ -178,6 +178,7 @@
         "syntaxError.frag",
         "test.frag",
         "texture.frag",
+        "tokenPaste.vert",
         "types.frag",
         "uniformArray.frag",
         "variableArrayIndex.frag",
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 414fa7b..c946ef7 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -216,6 +216,7 @@
         "spv.forwardFun.frag",
         "spv.functionCall.frag",
         "spv.functionSemantics.frag",
+        "spv.GeometryShaderPassthrough.geom",
         "spv.interpOps.frag",
         "spv.int64.frag",
         "spv.layoutNested.vert",
@@ -240,6 +241,7 @@
         "spv.precision.frag",
         "spv.prepost.frag",
         "spv.qualifiers.vert",
+        "spv.sampleMaskOverrideCoverage.frag",
         "spv.shaderBallot.comp",
         "spv.shaderDrawParams.vert",
         "spv.shaderGroupVote.comp",
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index e676e95..b874aa8 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -90,10 +90,11 @@
     // as "linear" or "centroid" NOT valid identifiers.  This code special cases "sample",
     // so e.g, "int sample;" is accepted.
     if (peekTokenClass(EHTokSample)) {
-        idToken.string     = NewPoolTString("sample");
-        idToken.tokenClass = EHTokIdentifier;
-        idToken.symbol     = nullptr;
-        idToken.loc        = token.loc;
+        token.string     = NewPoolTString("sample");
+        token.tokenClass = EHTokIdentifier;
+        token.symbol     = nullptr;
+
+        idToken          = token;
         advanceToken();
         return true;
     }
@@ -475,8 +476,15 @@
     TSourceLoc loc = token.loc;
 
     // type_specifier
-    if (! acceptType(type))
+    if (! acceptType(type)) {
+        // If this is not a type, we may have inadvertently gone down a wrong path
+        // py parsing "sample", which can be treated like either an identifier or a
+        // qualifier.  Back it out, if we did.
+        if (qualifier.sample)
+            recedeToken();
+
         return false;
+    }
     if (type.getBasicType() == EbtBlock) {
         // the type was a block, which set some parts of the qualifier
         parseContext.mergeQualifiers(type.getQualifier(), qualifier);
@@ -2203,7 +2211,7 @@
     } else if (acceptIdentifier(idToken)) {
         // identifier or function_call name
         if (! peekTokenClass(EHTokLeftParen)) {
-            node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
+            node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
         } else if (acceptFunctionCall(idToken, node)) {
             // function_call (nothing else to do yet)
         } else {
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 54cd10f..62dac4b 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -579,8 +579,10 @@
         }
 
         // Recovery, if it wasn't found or was not a variable.
-        if (! variable)
+        if (! variable) {
+            error(loc, "unknown variable", string->c_str(), "");
             variable = new TVariable(string, TType(EbtVoid));
+        }
 
         if (variable->getType().getQualifier().isFrontEndConstant())
             node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
@@ -957,13 +959,13 @@
         if (flattenData.nextBinding != TQualifier::layoutBindingEnd)
             memberVariable->getWritableType().getQualifier().layoutBinding = flattenData.nextBinding++;
 
-        flattenData.offsets.push_back(flattenData.members.size());
+        flattenData.offsets.push_back(static_cast<int>(flattenData.members.size()));
         flattenData.members.push_back(memberVariable);
 
         if (track)
             trackLinkageDeferred(*memberVariable);
 
-        return flattenData.offsets.size()-1; // location of the member reference
+        return static_cast<int>(flattenData.offsets.size())-1; // location of the member reference
     } else {
         // Further recursion required
         return flatten(loc, variable, type, flattenData, memberName);
@@ -985,7 +987,7 @@
     auto members = *type.getStruct();
 
     // Reserve space for this tree level.
-    int start = flattenData.offsets.size();
+    int start = static_cast<int>(flattenData.offsets.size());
     int pos   = start;
     flattenData.offsets.resize(int(pos + members.size()), -1);
 
@@ -1022,7 +1024,7 @@
         name = variable.getName();
 
     // Reserve space for this tree level.
-    int start = flattenData.offsets.size();
+    int start = static_cast<int>(flattenData.offsets.size());
     int pos   = start;
     flattenData.offsets.resize(int(pos + size), -1);
 
@@ -2781,7 +2783,7 @@
 //
 // Add any needed implicit conversions for function-call arguments to input parameters.
 //
-void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const
+void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments)
 {
     TIntermAggregate* aggregate = arguments->getAsAggregate();
     const auto setArg = [&](int argNum, TIntermNode* arg) {
@@ -2809,9 +2811,13 @@
         if (*function[i].type != arg->getType()) {
             // 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);
-            arg = intermediate.addShapeConversion(EOpFunctionCall, *function[i].type, arg);
-            setArg(i, arg);
+            TIntermTyped* convArg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg);
+            if (convArg != nullptr)
+                convArg = intermediate.addShapeConversion(EOpFunctionCall, *function[i].type, convArg);
+            if (convArg != nullptr)
+                setArg(i, convArg);
+            else
+                error(arg->getLoc(), "cannot convert input argument, argument", "", "%d", i);
         } else {
             if (wasFlattened(arg)) {
                 // Will make a two-level subtree.
@@ -4977,7 +4983,7 @@
         return addConstructor(loc, initList, arrayType);
     } else if (type.isStruct()) {
         // lengthen list to be long enough
-        lengthenList(loc, initList->getSequence(), type.getStruct()->size());
+        lengthenList(loc, initList->getSequence(), static_cast<int>(type.getStruct()->size()));
 
         if (type.getStruct()->size() != initList->getSequence().size()) {
             error(loc, "wrong number of structure members", "initializer list", "");
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 206df9b..d017a2a 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -50,18 +50,18 @@
                      const TString sourceEntryPointName,
                      bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
     virtual ~HlslParseContext();
-    void initializeExtensionBehavior();
+    void initializeExtensionBehavior() override;
 
-    void setLimits(const TBuiltInResource&);
-    bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
-    virtual const char* getGlobalUniformBlockName() { return "$Global"; }
+    void setLimits(const TBuiltInResource&) override;
+    bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) override;
+    virtual const char* getGlobalUniformBlockName() override { return "$Global"; }
 
-    void reservedPpErrorCheck(const TSourceLoc&, const char* /*name*/, const char* /*op*/) { }
-    bool lineContinuationCheck(const TSourceLoc&, bool /*endOfComment*/) { return true; }
-    bool lineDirectiveShouldSetNextLine() const { return true; }
+    void reservedPpErrorCheck(const TSourceLoc&, const char* /*name*/, const char* /*op*/) override { }
+    bool lineContinuationCheck(const TSourceLoc&, bool /*endOfComment*/) override { return true; }
+    bool lineDirectiveShouldSetNextLine() const override { return true; }
     bool builtInName(const TString&);
 
-    void handlePragma(const TSourceLoc&, const TVector<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);
     TIntermTyped* handleBracketOperator(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
@@ -84,7 +84,7 @@
     void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
     void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
     TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
-    void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
+    void addInputArgumentConversions(const TFunction&, TIntermNode*&);
     TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermOperator&);
     void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
     TFunction* handleConstructorCall(const TSourceLoc&, const TType&);
@@ -134,7 +134,7 @@
     TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
     TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
     void declareBlock(const TSourceLoc&, TType&, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
-    void finalizeGlobalUniformBlockLayout(TVariable& block);
+    void finalizeGlobalUniformBlockLayout(TVariable& block) override;
     void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
     void fixBlockXfbOffsets(TQualifier&, TTypeList&);
     void fixBlockUniformOffsets(const TQualifier&, TTypeList&);
diff --git a/hlsl/hlslScanContext.cpp b/hlsl/hlslScanContext.cpp
index 4e355ba..3ae19fc 100755
--- a/hlsl/hlslScanContext.cpp
+++ b/hlsl/hlslScanContext.cpp
@@ -394,13 +394,14 @@
     do {
         parserToken = &token;
         TPpToken ppToken;
-        tokenText = ppContext.tokenize(&ppToken);
-        if (tokenText == nullptr)
+        int token = ppContext.tokenize(ppToken);
+        if (token == EndOfInput)
             return EHTokNone;
 
+        tokenText = ppToken.name;
         loc = ppToken.loc;
         parserToken->loc = loc;
-        switch (ppToken.token) {
+        switch (token) {
         case ';':                       return EHTokSemicolon;
         case ',':                       return EHTokComma;
         case ':':                       return EHTokColon;
@@ -429,11 +430,11 @@
             parseContext.error(loc, "illegal use of escape character", "\\", "");
             break;
 
-        case PpAtomAdd:                return EHTokAddAssign;
-        case PpAtomSub:                return EHTokSubAssign;
-        case PpAtomMul:                return EHTokMulAssign;
-        case PpAtomDiv:                return EHTokDivAssign;
-        case PpAtomMod:                return EHTokModAssign;
+        case PPAtomAddAssign:          return EHTokAddAssign;
+        case PPAtomSubAssign:          return EHTokSubAssign;
+        case PPAtomMulAssign:          return EHTokMulAssign;
+        case PPAtomDivAssign:          return EHTokDivAssign;
+        case PPAtomModAssign:          return EHTokModAssign;
 
         case PpAtomRight:              return EHTokRightOp;
         case PpAtomLeft:               return EHTokLeftOp;
@@ -467,7 +468,7 @@
         }
 
         case PpAtomConstString: {
-            parserToken->string = NewPoolTString(ppToken.name);
+            parserToken->string = NewPoolTString(tokenText);
             return EHTokStringConstant;
         }
 
@@ -475,7 +476,7 @@
 
         default:
             char buf[2];
-            buf[0] = (char)ppToken.token;
+            buf[0] = (char)token;
             buf[1] = 0;
             parseContext.error(loc, "unexpected token", buf, "");
             break;