Spec Constant Operations

Approach:
Add a flag in `Builder` to indicate 'spec constant mode' and 'normal
mode'. When the builder is in 'normal mode', nothing changed. When the
builder is in 'spec constant mode', binary, unary and other instruction
creation rountines will be redirected to `createSpecConstantOp()` to
create instrution at module level with `OpSpecConstantOp <original
opcode> <operands>`.

'spec constant mode' should be enabled if and only if we are creating
spec constants. So a flager setter/recover guard is added when handling
binary/unary nodes in `createSpvConstantsFromConstSubTree()`.

Note when handling spec constants which are represented as ConstantUnion
Node, we should not use `OpSpecConstantOp` to initialize the composite
constant, so builder is set to 'normal mode'.

Tests:
Tests are added in Test/spv.specConstantOperations.vert, including:

1) Arithmetic, shift opeations for both scalar and composite type spec constants.
2) Size conversion from/to float and double for both scalar and vector.
3) Bitwise and/or/xor for both scalar and vector.
4) Unary negate/not for both scalar and vector.
5) Vector swizzles.
6) Comparisons for scalars.
7) == and != for composite type spec constants

Issues:
1) To implement == and != for composite type spec constants, the Spec needs
to allow OpAll, OpAny, OpFOrdEqual, OpFUnordEqual, OpOrdNotEqual,
OpFUnordNotEqual. Currently none of them are allowed in the Spec.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index dd5afd4..ee48b3c 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -130,7 +130,7 @@
     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
     spv::Id createSpvConstant(const glslang::TIntermTyped&);
     spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
-    spv::Id createSpvConstantFromConstSubTree(const glslang::TIntermTyped* subTree);
+    spv::Id createSpvConstantFromConstSubTree(glslang::TIntermTyped* subTree);
     bool isTrivialLeaf(const glslang::TIntermTyped* node);
     bool isTrivial(const glslang::TIntermTyped* node);
     spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
@@ -3854,15 +3854,37 @@
     return builder.makeCompositeConstant(typeId, spvConsts);
 }
 
+namespace {
+class SpecConstOpCodeGenerationSettingGuard{
+  public:
+    SpecConstOpCodeGenerationSettingGuard(spv::Builder* builder,
+                                         bool shouldGeneratingForSpecConst)
+        : builder_(builder) {
+        previous_flag_ = builder->isInSpecConstCodeGenMode();
+        shouldGeneratingForSpecConst ? builder->setToSpecConstCodeGenMode()
+                                     : builder->setToNormalCodeGenMode();
+    }
+    ~SpecConstOpCodeGenerationSettingGuard() {
+        previous_flag_ ? builder_->setToSpecConstCodeGenMode()
+                       : builder_->setToNormalCodeGenMode();
+    }
+
+  private:
+    spv::Builder* builder_;
+    bool previous_flag_;
+};
+}
+
 // Create constant ID from const initializer sub tree.
 spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree(
-    const glslang::TIntermTyped* subTree) {
+    glslang::TIntermTyped* subTree) {
     const glslang::TType& glslangType = subTree->getType();
     spv::Id typeId = convertGlslangToSpvType(glslangType);
     bool is_spec_const = subTree->getType().getQualifier().isSpecConstant();
     if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) {
         // Aggregate node, we should generate OpConstantComposite or
         // OpSpecConstantComposite instruction.
+
         std::vector<spv::Id> const_constituents;
         for (auto NI = an->getSequence().begin(); NI != an->getSequence().end();
              NI++) {
@@ -3881,17 +3903,27 @@
             return const_constituents.front();
         }
 
-    } else if (const glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) {
+    } else if (glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) {
         // Binary operation node, we should generate OpSpecConstantOp <binary op>
         // This case should only happen when Specialization Constants are involved.
-        spv::MissingFunctionality("OpSpecConstantOp <binary op> not implemented");
-        return spv::NoResult;
 
-    } else if (const glslang::TIntermUnary* un = subTree->getAsUnaryNode()) {
+        // Spec constants defined with binary operations and other constants requires
+        // OpSpecConstantOp instruction.
+        SpecConstOpCodeGenerationSettingGuard set_to_spec_const_mode(&builder, true);
+
+        bn->traverse(this);
+        return accessChainLoad(bn->getType());
+
+    } else if (glslang::TIntermUnary* un = subTree->getAsUnaryNode()) {
         // Unary operation node, similar to binary operation node, should only
         // happen when specialization constants are involved.
-        spv::MissingFunctionality("OpSpecConstantOp <unary op> not implemented");
-        return spv::NoResult;
+
+        // Spec constants defined with unary operations and other constants requires
+        // OpSpecConstantOp instruction.
+        SpecConstOpCodeGenerationSettingGuard set_to_spec_const_mode(&builder, true);
+
+        un->traverse(this);
+        return accessChainLoad(un->getType());
 
     } else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) {
         // ConstantUnion node, should redirect to