SPIR-V: Move from Version .99 Rev 31 to Version 1.0, Rev 2.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index c005197..c5342ac 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -60,7 +60,10 @@
 
 namespace {
 
-const int GlslangMagic = 0x51a;
+// For low-order part of the generator's magic number. Bump up
+// when there is a change in the style (e.g., if SSA form changes,
+// or a different instruction sequence to do something gets used).
+const int GeneratorVersion = 1;
 
 //
 // The main holder of information for translating glslang to SPIR-V.
@@ -113,13 +116,16 @@
     spv::Id createNoArgOperation(glslang::TOperator op);
     spv::Id getSymbolId(const glslang::TIntermSymbol* node);
     void addDecoration(spv::Id id, spv::Decoration dec);
+    void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
-    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
+    spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
+    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
     bool isTrivialLeaf(const glslang::TIntermTyped* node);
     bool isTrivial(const glslang::TIntermTyped* node);
     spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
 
     spv::Function* shaderEntry;
+    spv::Instruction* entryPoint;
     int sequenceDepth;
 
     // There is a 1:1 mapping between a spv builder and a module; this is thread safe
@@ -169,7 +175,7 @@
     case EShLangFragment:         return spv::ExecutionModelFragment;
     case EShLangCompute:          return spv::ExecutionModelGLCompute;
     default:
-        spv::MissingFunctionality("GLSL stage");
+        assert(0);
         return spv::ExecutionModelFragment;
     }
 }
@@ -191,12 +197,12 @@
         // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?
     } else {
         switch (type.getQualifier().storage) {
-        case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;
-        case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;
+        case glslang::EvqShared:        return spv::StorageClassWorkgroup;  break;
+        case glslang::EvqGlobal:        return spv::StorageClassPrivate;
         case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
         case glslang::EvqTemporary:     return spv::StorageClassFunction;
         default: 
-            spv::MissingFunctionality("unknown glslang storage class");
+            assert(0);
             return spv::StorageClassFunction;
         }
     }
@@ -206,14 +212,14 @@
 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
 {
     switch (sampler.dim) {
-    case glslang::Esd1D:     return spv::Dim1D;
-    case glslang::Esd2D:     return spv::Dim2D;
-    case glslang::Esd3D:     return spv::Dim3D;
-    case glslang::EsdCube:   return spv::DimCube;
-    case glslang::EsdRect:   return spv::DimRect;
-    case glslang::EsdBuffer: return spv::DimBuffer;
+    case glslang::Esd1D:      return spv::Dim1D;
+    case glslang::Esd2D:      return spv::Dim2D;
+    case glslang::Esd3D:      return spv::Dim3D;
+    case glslang::EsdCube:    return spv::DimCube;
+    case glslang::EsdRect:    return spv::DimRect;
+    case glslang::EsdBuffer:  return spv::DimBuffer;
     default:
-        spv::MissingFunctionality("unknown sampler dimension");
+        assert(0);
         return spv::Dim2D;
     }
 }
@@ -240,7 +246,7 @@
         case glslang::EvqVaryingIn:    return spv::DecorationBlock;
         case glslang::EvqVaryingOut:   return spv::DecorationBlock;
         default:
-            spv::MissingFunctionality("kind of block");
+            assert(0);
             break;
         }
     }
@@ -275,11 +281,10 @@
                 }
             case glslang::EvqVaryingIn:
             case glslang::EvqVaryingOut:
-                if (type.getQualifier().layoutPacking != glslang::ElpNone)
-                    spv::MissingFunctionality("in/out block layout");
+                assert(type.getQualifier().layoutPacking == glslang::ElpNone);
                 return (spv::Decoration)spv::BadValue;
             default:
-                spv::MissingFunctionality("block storage qualification");
+                assert(0);
                 return (spv::Decoration)spv::BadValue;
             }
         }
@@ -287,12 +292,16 @@
 }
 
 // Translate glslang type to SPIR-V interpolation decorations.
+// Returns spv::Decoration(spv::BadValue) when no decoration
+// should be applied.
 spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
 {
-    if (type.getQualifier().smooth)
-        return spv::DecorationSmooth;
+    if (type.getQualifier().smooth) {
+        // Smooth decoration doesn't exist in SPIR-V 1.0
+        return (spv::Decoration)spv::BadValue;
+    }
     if (type.getQualifier().nopersp)
-        return spv::DecorationNoperspective;
+        return spv::DecorationNoPerspective;
     else if (type.getQualifier().patch)
         return spv::DecorationPatch;
     else if (type.getQualifier().flat)
@@ -344,8 +353,6 @@
     case glslang::EbvSampleId:             return spv::BuiltInSampleId;
     case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;
     case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;
-    case glslang::EbvFragColor:            return spv::BuiltInFragColor;
-    case glslang::EbvFragData:             return spv::BuiltInFragColor;
     case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
     case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
     case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
@@ -414,7 +421,7 @@
 
 TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
     : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
-      builder(GlslangMagic),
+      builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion),
       inMain(false), mainTerminated(false), linkageOnly(false),
       glslangIntermediate(glslangIntermediate)
 {
@@ -425,7 +432,7 @@
     stdBuiltins = builder.import("GLSL.std.450");
     builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
     shaderEntry = builder.makeMain();
-    builder.addEntryPoint(executionModel, shaderEntry, "main");
+    entryPoint = builder.addEntryPoint(executionModel, shaderEntry, "main");
 
     // Add the source extensions
     const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
@@ -451,9 +458,9 @@
     case EShLangTessEvaluation:
         builder.addCapability(spv::CapabilityTessellation);
         switch (glslangIntermediate->getInputPrimitive()) {
-        case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;
-        case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;
-        case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;
+        case glslang::ElgTriangles:           mode = spv::ExecutionModeTriangles;     break;
+        case glslang::ElgQuads:               mode = spv::ExecutionModeQuads;         break;
+        case glslang::ElgIsolines:            mode = spv::ExecutionModeIsolines;      break;
         default:                              mode = spv::BadValue;                        break;
         }
         if (mode != spv::BadValue)
@@ -486,7 +493,7 @@
         case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
         case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
         case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
-        case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;
+        case glslang::ElgTriangles:          mode = spv::ExecutionModeTriangles;               break;
         case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
         default:                             mode = spv::BadValue;         break;
         }
@@ -520,7 +527,6 @@
             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
 
         switch(glslangIntermediate->getDepth()) {
-        case glslang::EldAny:      mode = spv::ExecutionModeDepthAny;     break;
         case glslang::EldGreater:  mode = spv::ExecutionModeDepthGreater; break;
         case glslang::EldLess:     mode = spv::ExecutionModeDepthLess;    break;
         default:                   mode = spv::BadValue;                  break;
@@ -591,6 +597,11 @@
             builder.setAccessChainRValue(id);
         else
             builder.setAccessChainLValue(id);
+    } else {
+        // finish off the entry-point SPV instruction by adding the Input/Output <id>
+        spv::StorageClass sc = builder.getStorageClass(id);
+        if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)
+            entryPoint->addIdOperand(id);
     }
 }
 
@@ -639,8 +650,7 @@
                                                node->getType().getBasicType());
 
                 // these all need their counterparts in createBinaryOperation()
-                if (rValue == 0)
-                    spv::MissingFunctionality("createBinaryOperation");
+                assert(rValue != spv::NoResult);
             }
 
             // store the result
@@ -660,20 +670,13 @@
 
             // Add the next element in the chain
 
-            int index = 0;
-            if (node->getRight()->getAsConstantUnion() == 0)
-                spv::MissingFunctionality("direct index without a constant node");
-            else 
-                index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
-
+            int index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
             if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
                 // This may be, e.g., an anonymous block-member selection, which generally need
                 // index remapping due to hidden members in anonymous blocks.
                 std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
-                if (remapper.size() == 0)
-                    spv::MissingFunctionality("block without member remapping");
-                else
-                    index = remapper[index];
+                assert(remapper.size() > 0);
+                index = remapper[index];
             }
 
             if (! node->getLeft()->getType().isArray() &&
@@ -766,7 +769,7 @@
                                    node->getLeft()->getType().getBasicType());
 
     if (! result) {
-        spv::MissingFunctionality("glslang binary operation");
+        spv::MissingFunctionality("unknown glslang binary operation");
     } else {
         builder.clearAccessChain();
         builder.setAccessChainRValue(result);
@@ -832,7 +835,7 @@
 
     // if not, then possibly an operation
     if (! result)
-        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType());
+        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
 
     if (result) {
         builder.clearAccessChain();
@@ -862,8 +865,7 @@
             spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 
                                                      convertGlslangToSpvType(node->getType()), operand, one, 
                                                      node->getType().getBasicType());
-            if (result == 0)
-                spv::MissingFunctionality("createBinaryOperation for unary");
+            assert(result != spv::NoResult);
 
             // The result of operation is always stored, but conditionally the
             // consumed result.  The consumed result is always an r-value.
@@ -886,7 +888,7 @@
         return false;
 
     default:
-        spv::MissingFunctionality("glslang unary");
+        spv::MissingFunctionality("unknown glslang unary");
         break;
     }
 
@@ -990,13 +992,7 @@
     {
         if (node->isUserDefined())
             result = handleUserFunctionCall(node);
-
-        if (! result) {
-            spv::MissingFunctionality("glslang function call");
-            glslang::TConstUnionArray emptyConsts;
-            int nextConst = 0;
-            result = createSpvConstant(node->getType(), emptyConsts, nextConst);
-        }
+        assert(result);
         builder.clearAccessChain();
         builder.setAccessChainRValue(result);
 
@@ -1053,12 +1049,10 @@
             for (int c = 0; c < (int)arguments.size(); ++c)
                 constituents.push_back(arguments[c]);
             constructed = builder.createCompositeConstruct(resultTypeId, constituents);
-        } else {
-            if (isMatrix)
-                constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
-            else
-                constructed = builder.createConstructor(precision, arguments, resultTypeId);
-        }
+        } else if (isMatrix)
+            constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
+        else
+            constructed = builder.createConstructor(precision, arguments, resultTypeId);
 
         builder.clearAccessChain();
         builder.setAccessChainRValue(constructed);
@@ -1131,21 +1125,6 @@
         atomic = true;
         break;
 
-    case glslang::EOpAddCarry:
-    case glslang::EOpSubBorrow:
-    case glslang::EOpUMulExtended:
-    case glslang::EOpIMulExtended:
-    case glslang::EOpBitfieldExtract:
-    case glslang::EOpBitfieldInsert:
-        spv::MissingFunctionality("integer aggregate");
-        break;
-
-    case glslang::EOpFma:
-    case glslang::EOpFrexp:
-    case glslang::EOpLdexp:
-        spv::MissingFunctionality("fma/frexp/ldexp aggregate");
-        break;
-
     default:
         break;
     }
@@ -1171,9 +1150,7 @@
                                        left->getType().getBasicType(), reduceComparison);
 
         // code above should only make binOp that exists in createBinaryOperation
-        if (result == 0)
-            spv::MissingFunctionality("createBinaryOperation for aggregate");
-
+        assert(result != spv::NoResult);
         builder.clearAccessChain();
         builder.setAccessChainRValue(result);
 
@@ -1192,7 +1169,7 @@
         // special case l-value operands; there are just a few
         bool lvalue = false;
         switch (node->getOp()) {
-        //case glslang::EOpFrexp:
+        case glslang::EOpFrexp:
         case glslang::EOpModf:
             if (arg == 1)
                 lvalue = true;
@@ -1208,9 +1185,16 @@
             if (arg == 0)
                 lvalue = true;
             break;
-        //case glslang::EOpUAddCarry:
-        //case glslang::EOpUSubBorrow:
-        //case glslang::EOpUMulExtended:
+        case glslang::EOpAddCarry:
+        case glslang::EOpSubBorrow:
+            if (arg == 2)
+                lvalue = true;
+            break;
+        case glslang::EOpUMulExtended:
+        case glslang::EOpIMulExtended:
+            if (arg >= 2)
+                lvalue = true;
+            break;
         default:
             break;
         }
@@ -1230,7 +1214,7 @@
             result = createNoArgOperation(node->getOp());
             break;
         case 1:
-            result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType());
+            result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType());
             break;
         default:
             result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
@@ -1242,7 +1226,7 @@
         return false;
 
     if (! result) {
-        spv::MissingFunctionality("glslang aggregate");
+        spv::MissingFunctionality("unknown glslang aggregate");
         return true;
     } else {
         builder.clearAccessChain();
@@ -1350,7 +1334,7 @@
 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
 {
     int nextConst = 0;
-    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
 
     builder.clearAccessChain();
     builder.setAccessChainRValue(constant);
@@ -1418,7 +1402,7 @@
         break;
 
     default:
-        spv::MissingFunctionality("branch type");
+        assert(0);
         break;
     }
 
@@ -1429,9 +1413,9 @@
 {
     // First, steer off constants, which are not SPIR-V variables, but 
     // can still have a mapping to a SPIR-V Id.
+    // This includes specialization constants.
     if (node->getQualifier().storage == glslang::EvqConst) {
-        int nextConst = 0;
-        return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+        return createSpvSpecConstant(*node);
     }
 
     // Now, handle actual variables
@@ -1453,7 +1437,7 @@
         case glslang::EbtInt:      return builder.makeIntType(32);
         case glslang::EbtUint:     return builder.makeUintType(32);
         default:
-            spv::MissingFunctionality("sampled type");
+            assert(0);
             return builder.makeFloatType(32);
     }
 }
@@ -1474,8 +1458,7 @@
     switch (type.getBasicType()) {
     case glslang::EbtVoid:
         spvType = builder.makeVoidType();
-        if (type.isArray())
-            spv::MissingFunctionality("array of void");
+        assert (! type.isArray());
         break;
     case glslang::EbtFloat:
         spvType = builder.makeFloatType(32);
@@ -1499,12 +1482,13 @@
     case glslang::EbtSampler:
         {
             const glslang::TSampler& sampler = type.getSampler();
-            spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
-                                            sampler.image ? 2 : 1, TranslateImageFormat(type));
-            // OpenGL "textures" need to be combined with a sampler
-            if (! sampler.image)
-                spvType = builder.makeSampledImageType(spvType);
-        }
+                // an image is present, make its type
+                spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
+                                                sampler.image ? 2 : 1, TranslateImageFormat(type));
+            if (! sampler.image) {
+                    spvType = builder.makeSampledImageType(spvType);
+                }
+            }
         break;
     case glslang::EbtStruct:
     case glslang::EbtBlock:
@@ -1593,7 +1577,7 @@
         }
         break;
     default:
-        spv::MissingFunctionality("basic type");
+        assert(0);
         break;
     }
 
@@ -1620,10 +1604,14 @@
             spvType = builder.makeArrayType(spvType, type.getOuterArraySize());
         }
 
-        // TODO: layout still needs to be done hierarchically for arrays of arrays, which 
+        // TODO: explicit layout still needs to be done hierarchically for arrays of arrays, which 
         // may still require additional "link time" support from the front-end 
         // for arrays of arrays
-        if (explicitLayout)
+
+        // We need to decorate array strides for types needing explicit layout,
+        // except for the very top if it is an array of blocks; that array is
+        // not laid out in memory in a way needing a stride.
+        if (explicitLayout && type.getBasicType() != glslang::EbtBlock)
             builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
     }
 
@@ -1883,8 +1871,11 @@
         operands.push_back(*(opIt++));
         if (node->getOp() == glslang::EOpImageStore)
             operands.push_back(*(opIt++));
-        // TODO: add 'sample' operand
         if (node->getOp() == glslang::EOpImageLoad) {
+            if (sampler.ms) {
+                operands.push_back(spv::ImageOperandsSampleMask);
+                operands.push_back(*(opIt++));
+            }
             return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
         } else if (node->getOp() == glslang::EOpImageStore) {
             builder.createNoResultOp(spv::OpImageWrite, operands);
@@ -1909,8 +1900,6 @@
     }
 
     // Check for texture functions other than queries
-    if (cracked.gather)
-        spv::MissingFunctionality("texture gather");
 
     // check for bias argument
     bool bias = false;
@@ -1925,14 +1914,18 @@
             bias = true;
     }
 
-    bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
-
     // set the rest of the arguments
+
     params.coords = arguments[1];
     int extraArgs = 0;
-    if (cubeCompare)
+
+    // sort out where Dref is coming from
+    if (sampler.shadow && sampler.dim == glslang::EsdCube && sampler.arrayed)
         params.Dref = arguments[2];
-    else if (sampler.shadow) {
+    else if (sampler.shadow && cracked.gather) {
+        params.Dref = arguments[2];
+        ++extraArgs;
+    } else if (sampler.shadow) {
         std::vector<spv::Id> indexes;
         int comp;
         if (cracked.proj)
@@ -1954,20 +1947,28 @@
         params.gradY = arguments[3 + extraArgs];
         extraArgs += 2;
     }
-    //if (gather && compare) {
-    //    params.compare = arguments[2 + extraArgs];
-    //    ++extraArgs;
-    //}
-    if (cracked.offset || cracked.offsets) {
+    if (cracked.offset) {
         params.offset = arguments[2 + extraArgs];
         ++extraArgs;
+    } else if (cracked.offsets) {
+        params.offsets = arguments[2 + extraArgs];
+        ++extraArgs;
     }
     if (bias) {
         params.bias = arguments[2 + extraArgs];
         ++extraArgs;
     }
+    if (cracked.gather && ! sampler.shadow) {
+        // default component is 0, if missing, otherwise an argument
+        if (2 + extraArgs < (int)arguments.size()) {
+            params.comp = arguments[2 + extraArgs];
+            ++extraArgs;
+        } else {
+            params.comp = builder.makeIntConstant(0);
+        }
+    }
 
-    return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, params);
+    return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, cracked.gather, params);
 }
 
 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
@@ -2308,6 +2309,7 @@
 {
     spv::Op unaryOp = spv::OpNop;
     int libCall = -1;
+    bool isUnsigned = typeProxy == glslang::EbtUint;
     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
 
     switch (op) {
@@ -2538,11 +2540,13 @@
         unaryOp = spv::OpBitCount;
         break;
     case glslang::EOpFindLSB:
-        libCall = spv::GLSLstd450FindILSB;
+        libCall = spv::GLSLstd450FindILsb;
         break;
     case glslang::EOpFindMSB:
-        spv::MissingFunctionality("signed vs. unsigned FindMSB");
-        libCall = spv::GLSLstd450FindSMSB;
+        if (isUnsigned)
+            libCall = spv::GLSLstd450FindUMsb;
+        else
+            libCall = spv::GLSLstd450FindSMsb;
         break;
 
     default:
@@ -2717,7 +2721,7 @@
         opCode = spv::OpAtomicLoad;
         break;
     default:
-        spv::MissingFunctionality("missing nested atomic");
+        assert(0);
         break;
     }
 
@@ -2754,6 +2758,11 @@
 
     spv::Op opCode = spv::OpNop;
     int libCall = -1;
+    int consumedOperands = operands.size();
+    spv::Id typeId0 = 0;
+    if (consumedOperands > 0)
+        typeId0 = builder.getTypeId(operands[0]);
+    spv::Id frexpIntType = 0;
 
     switch (op) {
     case glslang::EOpMin:
@@ -2794,7 +2803,10 @@
             libCall = spv::GLSLstd450SClamp;
         break;
     case glslang::EOpMix:
-        libCall = spv::GLSLstd450Mix;
+        if (isFloat)
+            libCall = spv::GLSLstd450FMix;
+        else
+            libCall = spv::GLSLstd450IMix;
         break;
     case glslang::EOpStep:
         libCall = spv::GLSLstd450Step;
@@ -2819,6 +2831,52 @@
         libCall = spv::GLSLstd450Refract;
         break;
 
+    case glslang::EOpAddCarry:
+        opCode = spv::OpIAddCarry;
+        typeId = builder.makeStructResultType(typeId0, typeId0);
+        consumedOperands = 2;
+        break;
+    case glslang::EOpSubBorrow:
+        opCode = spv::OpISubBorrow;
+        typeId = builder.makeStructResultType(typeId0, typeId0);
+        consumedOperands = 2;
+        break;
+    case glslang::EOpUMulExtended:
+        opCode = spv::OpUMulExtended;
+        typeId = builder.makeStructResultType(typeId0, typeId0);
+        consumedOperands = 2;
+        break;
+    case glslang::EOpIMulExtended:
+        opCode = spv::OpSMulExtended;
+        typeId = builder.makeStructResultType(typeId0, typeId0);
+        consumedOperands = 2;
+        break;
+    case glslang::EOpBitfieldExtract:
+        if (isUnsigned)
+            opCode = spv::OpBitFieldUExtract;
+        else
+            opCode = spv::OpBitFieldSExtract;
+        break;
+    case glslang::EOpBitfieldInsert:
+        opCode = spv::OpBitFieldInsert;
+        break;
+
+    case glslang::EOpFma:
+        libCall = spv::GLSLstd450Fma;
+        break;
+    case glslang::EOpFrexp:
+        libCall = spv::GLSLstd450FrexpStruct;
+        if (builder.getNumComponents(operands[0]) == 1)
+            frexpIntType = builder.makeIntegerType(32, true);
+        else
+            frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0]));
+        typeId = builder.makeStructResultType(typeId0, frexpIntType);
+        consumedOperands = 1;
+        break;
+    case glslang::EOpLdexp:
+        libCall = spv::GLSLstd450Ldexp;
+        break;
+
     default:
         return 0;
     }
@@ -2827,7 +2885,7 @@
     if (libCall >= 0)
         id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
     else {
-        switch (operands.size()) {
+        switch (consumedOperands) {
         case 0:
             // should all be handled by visitAggregate and createNoArgOperation
             assert(0);
@@ -2839,16 +2897,34 @@
         case 2:
             id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
             break;
-        case 3:
-            id = builder.createTriOp(opCode, typeId, operands[0], operands[1], operands[2]);
-            break;
         default:
-            // These do not exist yet
-            assert(0 && "operation with more than 3 operands");
+            // anything 3 or over doesn't have l-value operands, so all should be consumed
+            assert(consumedOperands == operands.size());
+            id = builder.createOp(opCode, typeId, operands);
             break;
         }
     }
 
+    // Decode the return types that were structures
+    switch (op) {
+    case glslang::EOpAddCarry:
+    case glslang::EOpSubBorrow:
+        builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
+        id = builder.createCompositeExtract(id, typeId0, 0);
+        break;
+    case glslang::EOpUMulExtended:
+    case glslang::EOpIMulExtended:
+        builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
+        builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
+        break;
+    case glslang::EOpFrexp:
+        builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
+        id = builder.createCompositeExtract(id, typeId0, 0);
+        break;
+    default:
+        break;
+    }
+
     builder.setPrecision(id, precision);
 
     return id;
@@ -2883,13 +2959,13 @@
         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
         return 0;
     case glslang::EOpMemoryBarrierShared:
-        builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
+        builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask);
         return 0;
     case glslang::EOpGroupMemoryBarrier:
-        builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
+        builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
         return 0;
     default:
-        spv::MissingFunctionality("operation with no arguments");
+        spv::MissingFunctionality("unknown operation with no arguments");
         return 0;
     }
 }
@@ -2945,31 +3021,57 @@
     if (builtIn != spv::BadValue)
         builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
 
-    if (linkageOnly)
-        builder.addDecoration(id, spv::DecorationNoStaticUse);
-
     return id;
 }
 
+// If 'dec' is valid, add no-operand decoration to an object
 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
 {
     if (dec != spv::BadValue)
         builder.addDecoration(id, dec);
 }
 
+// If 'dec' is valid, add a one-operand decoration to an object
+void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value)
+{
+    if (dec != spv::BadValue)
+        builder.addDecoration(id, dec, value);
+}
+
+// If 'dec' is valid, add a no-operand decoration to a struct member
 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
 {
     if (dec != spv::BadValue)
         builder.addMemberDecoration(id, (unsigned)member, dec);
 }
 
+// Make a full tree of instructions to build a SPIR-V specialization constant,
+// or regularly constant if possible.
+//
+// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
+//
+// Recursively walk the nodes.  The nodes form a tree whose leaves are
+// regular constants, which themselves are trees that createSpvConstant()
+// recursively walks.  So, this function walks the "top" of the tree:
+//  - emit specialization constant-building instructions for specConstant
+//  - when running into a non-spec-constant, switch to createSpvConstant()
+spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
+{
+    assert(node.getQualifier().storage == glslang::EvqConst);
+
+    // hand off to the non-spec-constant path
+    assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
+    int nextConst = 0;
+    return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, false);
+}
+
 // Use 'consts' as the flattened glslang source of scalar constants to recursively
 // build the aggregate SPIR-V constant.
 //
 // If there are not enough elements present in 'consts', 0 will be substituted;
 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
 //
-spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
+spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
 {
     // vector of constants for SPIR-V
     std::vector<spv::Id> spvConsts;
@@ -2980,15 +3082,15 @@
     if (glslangType.isArray()) {
         glslang::TType elementType(glslangType, 0);
         for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
-            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
+            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
     } else if (glslangType.isMatrix()) {
         glslang::TType vectorType(glslangType, 0);
         for (int col = 0; col < glslangType.getMatrixCols(); ++col)
-            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
+            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
     } else if (glslangType.getStruct()) {
         glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
         for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
-            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
+            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
     } else if (glslangType.isVector()) {
         for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
             bool zero = nextConst >= consts.size();
@@ -3009,7 +3111,7 @@
                 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
                 break;
             default:
-                spv::MissingFunctionality("constant vector type");
+                assert(0);
                 break;
             }
             ++nextConst;
@@ -3020,22 +3122,22 @@
         spv::Id scalar = 0;
         switch (glslangType.getBasicType()) {
         case glslang::EbtInt:
-            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
+            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
             break;
         case glslang::EbtUint:
-            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
+            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
             break;
         case glslang::EbtFloat:
-            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
+            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
             break;
         case glslang::EbtDouble:
-            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
+            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
             break;
         case glslang::EbtBool:
-            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
+            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
             break;
         default:
-            spv::MissingFunctionality("constant scalar type");
+            assert(0);
             break;
         }
         ++nextConst;
@@ -3180,7 +3282,7 @@
 {
     const int bufSize = 100;
     char buf[bufSize];
-    snprintf(buf, bufSize, "%d, Revision %d", spv::Version, spv::Revision);
+    snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
     version = buf;
 }