Precise and noContraction propagation

    Reimplement the whole workflow to make that: precise'ness of struct
    members won't spread to other non-precise members of the same struct
    instance.

    Approach:
    1. Build the map from symbols to their defining nodes. And for each
    object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
    accesschain path. Different AST nodes that indicating a same object
    should have the same accesschain path.

    2. Along the building phase in step 1, collect the initial set of
    'precise' (AST qualifier: 'noContraction') objects' accesschain paths.

    3. Start with the initial set of 'precise' accesschain paths, use it as
    a worklist, do as the following steps until the worklist is empty:

        1) Pop an accesschain path from worklist.
        2) Get the symbol part from the accesschain path.
        3) Find the defining nodes of that symbol.
        4) For each defining node, check whether it is defining a 'precise'
        object, or its assignee has nested 'precise' object. Get the
        incremental path from assignee to its nested 'precise' object (if
        any).
        5) Traverse the right side of the defining node, obtain the
        accesschain paths of the corresponding involved 'precise' objects.
        Update the worklist with those new objects' accesschain paths.
        Label involved operations with 'noContraction'.

    In each step, whenever we find the parent object of an nested object is
    'precise' (has 'noContraction' qualifier), we let the nested object
    inherit the 'precise'ness from its parent object.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 7aa62fb..d160e36 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -385,6 +385,15 @@
         return (spv::Decoration)spv::BadValue;
 }
 
+// If glslang type is noContraction, return SPIR-V NoContraction decoration.
+spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
+{
+    if (qualifier.noContraction)
+        return spv::DecorationNoContraction;
+    else
+        return (spv::Decoration)spv::BadValue;
+}
+
 // Translate glslang built-in variable to SPIR-V built in decoration.
 spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
 {
@@ -612,7 +621,8 @@
     // - struct members can inherit from a struct declaration
     // - effect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object)
     // - are not part of the offset/st430/etc or row/column-major layout
-    return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation();
+    return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation() ||
+           qualifier.noContraction;
 }
 
 //
@@ -877,6 +887,9 @@
                                                convertGlslangToSpvType(node->getType()), leftRValue, rValue,
                                                node->getType().getBasicType());
 
+                // Decorate this instruction, if this node has 'noContraction' qualifier.
+                addDecoration(rValue, TranslateNoContractionDecoration(node->getType().getQualifier()));
+
                 // these all need their counterparts in createBinaryOperation()
                 assert(rValue != spv::NoResult);
             }
@@ -1000,6 +1013,8 @@
         logger->missingFunctionality("unknown glslang binary operation");
         return true;  // pick up a child as the place-holder result
     } else {
+        // Decorate this instruction, if this node has 'noContraction' qualifier.
+        addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier()));
         builder.setAccessChainRValue(result);
         return false;
     }
@@ -1068,6 +1083,8 @@
         result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
 
     if (result) {
+        // Decorate this instruction, if this node has 'noContraction' qualifier.
+        addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier()));
         builder.clearAccessChain();
         builder.setAccessChainRValue(result);
 
@@ -1100,6 +1117,8 @@
                                                    convertGlslangToSpvType(node->getType()), operand, one,
                                                    node->getType().getBasicType());
             assert(result != spv::NoResult);
+            // Decorate this instruction, if this node has 'noContraction' qualifier.
+            addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier()));
 
             // The result of operation is always stored, but conditionally the
             // consumed result.  The consumed result is always an r-value.