SPV: RelaxedPrecision: Plumb this through the full AST->SPV translator.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index a75c7ca..94e37e8 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -93,6 +93,7 @@
     spv::Id getSampledType(const glslang::TSampler&);
     spv::Id convertGlslangToSpvType(const glslang::TType& type);
     spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&);
+    spv::Id accessChainLoad(const glslang::TType& type);
     glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
     int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
     int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
@@ -234,7 +235,6 @@
     switch (type.getQualifier().precision) {
     case glslang::EpqLow:    return spv::DecorationRelaxedPrecision;
     case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
-    case glslang::EpqHigh:   return spv::NoPrecision;
     default:
         return spv::NoPrecision;
     }
@@ -709,12 +709,12 @@
             // evaluate the right
             builder.clearAccessChain();
             node->getRight()->traverse(this);
-            spv::Id rValue = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
+            spv::Id rValue = accessChainLoad(node->getRight()->getType());
 
             if (node->getOp() != glslang::EOpAssign) {
                 // the left is also an r-value
                 builder.setAccessChain(lValue);
-                spv::Id leftRValue = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
+                spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
 
                 // do the operation
                 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 
@@ -782,7 +782,7 @@
             // compute the next index in the chain
             builder.clearAccessChain();
             node->getRight()->traverse(this);
-            spv::Id index = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
+            spv::Id index = accessChainLoad(node->getRight()->getType());
 
             // restore the saved access chain
             builder.setAccessChain(partial);
@@ -824,21 +824,20 @@
 
     // Assume generic binary op...
 
-    // Get the operands
+    // get right operand
     builder.clearAccessChain();
     node->getLeft()->traverse(this);
-    spv::Id left = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
+    spv::Id left = accessChainLoad(node->getLeft()->getType());
 
+    // get left operand
     builder.clearAccessChain();
     node->getRight()->traverse(this);
-    spv::Id right = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
+    spv::Id right = accessChainLoad(node->getRight()->getType());
 
-    spv::Id result;
-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
-
-    result = createBinaryOperation(node->getOp(), precision, 
-                                   convertGlslangToSpvType(node->getType()), left, right,
-                                   node->getLeft()->getType().getBasicType());
+    // get result
+    spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
+                                           convertGlslangToSpvType(node->getType()), left, right,
+                                           node->getLeft()->getType().getBasicType());
 
     builder.clearAccessChain();
     if (! result) {
@@ -896,7 +895,7 @@
         node->getOp() == glslang::EOpInterpolateAtCentroid)
         operand = builder.accessChainGetLValue(); // Special case l-value operands
     else
-        operand = builder.accessChainLoad(convertGlslangToSpvType(node->getOperand()->getType()));
+        operand = accessChainLoad(node->getOperand()->getType());
 
     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
 
@@ -1208,11 +1207,11 @@
 
         builder.clearAccessChain();
         left->traverse(this);
-        spv::Id leftId = builder.accessChainLoad(convertGlslangToSpvType(left->getType()));
+        spv::Id leftId = accessChainLoad(left->getType());
 
         builder.clearAccessChain();
         right->traverse(this);
-        spv::Id rightId = builder.accessChainLoad(convertGlslangToSpvType(right->getType()));
+        spv::Id rightId = accessChainLoad(right->getType());
 
         result = createBinaryOperation(binOp, precision, 
                                        convertGlslangToSpvType(node->getType()), leftId, rightId, 
@@ -1275,7 +1274,7 @@
         if (lvalue)
             operands.push_back(builder.accessChainGetLValue());
         else
-            operands.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangOperands[arg]->getAsTyped()->getType())));
+            operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
     }
 
     if (atomic) {
@@ -1325,13 +1324,13 @@
     node->getCondition()->traverse(this);
 
     // make an "if" based on the value created by the condition
-    spv::Builder::If ifBuilder(builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getType())), builder);
+    spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), builder);
 
     if (node->getTrueBlock()) {
         // emit the "then" statement
         node->getTrueBlock()->traverse(this);
         if (result)
-            builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getTrueBlock()->getAsTyped()->getType())), result);
+            builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result);
     }
 
     if (node->getFalseBlock()) {
@@ -1339,7 +1338,7 @@
         // emit the "else" statement
         node->getFalseBlock()->traverse(this);
         if (result)
-            builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getFalseBlock()->getAsTyped()->getType())), result);
+            builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result);
     }
 
     ifBuilder.makeEndIf();
@@ -1360,7 +1359,7 @@
 {
     // emit and get the condition before doing anything with switch
     node->getCondition()->traverse(this);
-    spv::Id selector = builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getAsTyped()->getType()));
+    spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
 
     // browse the children to sort out code segments
     int defaultSegment = -1;
@@ -1433,7 +1432,7 @@
         builder.setBuildPoint(&test);
         node->getTest()->traverse(this);
         spv::Id condition =
-            builder.accessChainLoad(convertGlslangToSpvType(node->getTest()->getType()));
+            accessChainLoad(node->getTest()->getType());
         builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
 
         builder.setBuildPoint(&blocks.body);
@@ -1463,7 +1462,7 @@
         if (node->getTest()) {
             node->getTest()->traverse(this);
             spv::Id condition =
-                builder.accessChainLoad(convertGlslangToSpvType(node->getTest()->getType()));
+                accessChainLoad(node->getTest()->getType());
             builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
         } else {
             // TODO: unless there was a break/return/discard instruction
@@ -1497,7 +1496,7 @@
         break;
     case glslang::EOpReturn:
         if (node->getExpression())
-            builder.makeReturn(false, builder.accessChainLoad(convertGlslangToSpvType(node->getExpression()->getType())));
+            builder.makeReturn(false, accessChainLoad(node->getExpression()->getType()));
         else
             builder.makeReturn(false);
 
@@ -1765,6 +1764,11 @@
     return spvType;
 }
 
+spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
+{
+    return builder.accessChainLoad(TranslatePrecisionDecoration(type), convertGlslangToSpvType(type));
+}
+
 // Decide whether or not this type should be
 // decorated with offsets and strides, and if so
 // whether std140 or std430 rules should be applied.
@@ -1885,6 +1889,7 @@
         // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
 
         std::vector<spv::Id> paramTypes;
+        std::vector<spv::Decoration> paramPrecisions;
         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
 
         for (int p = 0; p < (int)parameters.size(); ++p) {
@@ -1894,12 +1899,14 @@
                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
             else
                 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
+            paramPrecisions.push_back(TranslatePrecisionDecoration(paramType));
             paramTypes.push_back(typeId);
         }
 
         spv::Block* functionBlock;
-        spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
-                                                              paramTypes, &functionBlock);
+        spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
+                                                            convertGlslangToSpvType(glslFunction->getType()),
+                                                            glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock);
 
         // Track function to emit/call later
         functionMap[glslFunction->getName().c_str()] = function;
@@ -2028,7 +2035,7 @@
         if (lvalue)
             arguments.push_back(builder.accessChainGetLValue());
         else
-            arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangArguments[i]->getAsTyped()->getType())));
+            arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
     }
 }
 
@@ -2036,7 +2043,7 @@
 {
     builder.clearAccessChain();
     node.getOperand()->traverse(this);
-    arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(node.getOperand()->getType())));
+    arguments.push_back(accessChainLoad(node.getOperand()->getType()));
 }
 
 spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
@@ -2241,19 +2248,19 @@
     // 1. Evaluate the arguments
     std::vector<spv::Builder::AccessChain> lValues;
     std::vector<spv::Id> rValues;
-    std::vector<spv::Id> argTypes;
+    std::vector<const glslang::TType*> argTypes;
     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
         // build l-value
         builder.clearAccessChain();
         glslangArgs[a]->traverse(this);
-        argTypes.push_back(convertGlslangToSpvType(glslangArgs[a]->getAsTyped()->getType()));
+        argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());
         // keep outputs as l-values, evaluate input-only as r-values
         if (qualifiers[a] != glslang::EvqConstReadOnly) {
             // save l-value
             lValues.push_back(builder.getAccessChain());
         } else {
             // process r-value
-            rValues.push_back(builder.accessChainLoad(argTypes.back()));
+            rValues.push_back(accessChainLoad(*argTypes.back()));
         }
     }
 
@@ -2273,7 +2280,7 @@
             if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
                 // need to copy the input into output space
                 builder.setAccessChain(lValues[lValueCount]);
-                spv::Id copy = builder.accessChainLoad(argTypes[a]);
+                spv::Id copy = accessChainLoad(*argTypes[a]);
                 builder.createStore(copy, arg);
             }
             ++lValueCount;
@@ -2286,6 +2293,7 @@
 
     // 3. Make the call.
     spv::Id result = builder.createFunctionCall(function, spvArgs);
+    builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
 
     // 4. Copy back out an "out" arguments.
     lValueCount = 0;
@@ -2446,10 +2454,7 @@
         if (needMatchingVectors)
             builder.promoteScalar(precision, left, right);
 
-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
-        builder.setPrecision(id, precision);
-
-        return id;
+        return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision);
     }
 
     if (! comparison)
@@ -2514,12 +2519,8 @@
         break;
     }
 
-    if (binOp != spv::OpNop) {
-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
-        builder.setPrecision(id, precision);
-
-        return id;
-    }
+    if (binOp != spv::OpNop)
+        return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision);
 
     return 0;
 }
@@ -2574,12 +2575,8 @@
         break;
     }
 
-    if (firstClass) {
-        spv::Id id = builder.createBinOp(op, typeId, left, right);
-        builder.setPrecision(id, precision);
-
-        return id;
-    }
+    if (firstClass)
+        return builder.setPrecision(builder.createBinOp(op, typeId, left, right), precision);
 
     // Handle component-wise +, -, *, and / for all combinations of type.
     // The result type of all of them is the same type as the (a) matrix operand.
@@ -2619,9 +2616,7 @@
         }
 
         // put the pieces together
-        spv::Id id = builder.createCompositeConstruct(typeId, results);
-        builder.setPrecision(id, precision);
-        return id;
+        return  builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision);
     }
     default:
         assert(0);
@@ -2899,13 +2894,11 @@
     if (libCall >= 0) {
         std::vector<spv::Id> args;
         args.push_back(operand);
-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
+        id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, args);
     } else
         id = builder.createUnaryOp(unaryOp, typeId, operand);
 
-    builder.setPrecision(id, precision);
-
-    return id;
+    return builder.setPrecision(id, precision);
 }
 
 // Create a unary operation on a matrix
@@ -2935,10 +2928,7 @@
     }
 
     // put the pieces together
-    spv::Id id = builder.createCompositeConstruct(typeId, results);
-    builder.setPrecision(id, precision);
-
-    return id;
+    return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision);
 }
 
 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
@@ -3031,9 +3021,7 @@
     } else
         result = builder.createUnaryOp(convOp, destType, operand);
 
-    builder.setPrecision(result, precision);
-
-    return result;
+    return builder.setPrecision(result, precision);
 }
 
 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
@@ -3277,7 +3265,7 @@
         // Construct the call arguments, without modifying the original operands vector.
         // We might need the remaining arguments, e.g. in the EOpFrexp case.
         std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, callArguments);
+        id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, callArguments);
     } else {
         switch (consumedOperands) {
         case 0:
@@ -3320,9 +3308,7 @@
         break;
     }
 
-    builder.setPrecision(id, precision);
-
-    return id;
+    return builder.setPrecision(id, precision);
 }
 
 // Intrinsics with no arguments, no return value, and no precision.
@@ -3644,7 +3630,7 @@
     // emit left operand
     builder.clearAccessChain();
     left.traverse(this);
-    spv::Id leftId = builder.accessChainLoad(boolTypeId);
+    spv::Id leftId = builder.accessChainLoad(spv::NoPrecision, boolTypeId);
 
     // Operands to accumulate OpPhi operands
     std::vector<spv::Id> phiOperands;
@@ -3667,7 +3653,7 @@
     // emit right operand as the "then" part of the "if"
     builder.clearAccessChain();
     right.traverse(this);
-    spv::Id rightId = builder.accessChainLoad(boolTypeId);
+    spv::Id rightId = builder.accessChainLoad(spv::NoPrecision, boolTypeId);
 
     // accumulate left operand's phi information
     phiOperands.push_back(rightId);
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 237496e..1594da3 100755
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -192,7 +192,7 @@
 // See makeStructResultType() for non-decorated structs
 // needed as the result of some instructions, which does
 // check for duplicates.
-Id Builder::makeStructType(std::vector<Id>& members, const char* name)
+Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
 {
     // Don't look for previous one, because in the general case,
     // structs can be duplicated except for decorations.
@@ -321,7 +321,7 @@
     return type->getResultId();
 }
 
-Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
+Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
 {
     // try to find it
     Instruction* type;
@@ -805,19 +805,28 @@
 
     Block* entry;
     std::vector<Id> params;
+    std::vector<Decoration> precisions;
 
-    mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
+    mainFunction = makeFunctionEntry(NoPrecision, makeVoidType(), "main", params, precisions, &entry);
 
     return mainFunction;
 }
 
 // Comments in header
-Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
+Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
+                                     const std::vector<Id>& paramTypes, const std::vector<Decoration>& precisions, Block **entry)
 {
+    // Make the function and initial instructions in it
     Id typeId = makeFunctionType(returnType, paramTypes);
     Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
     Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
 
+    // Set up the precisions
+    setPrecision(function->getId(), precision);
+    for (unsigned p = 0; p < (unsigned)precisions.size(); ++p)
+        setPrecision(firstParamId + p, precisions[p]);
+
+    // CFG
     if (entry) {
         *entry = new Block(getUniqueId(), *function);
         function->addBlock(*entry);
@@ -1117,10 +1126,10 @@
 }
 
 // Comments in header
-Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
+Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels)
 {
     if (channels.size() == 1)
-        return createCompositeExtract(source, typeId, channels.front());
+        return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
 
     Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
     assert(isVector(source));
@@ -1130,7 +1139,7 @@
         swizzle->addImmediateOperand(channels[i]);
     buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
 
-    return swizzle->getResultId();
+    return setPrecision(swizzle->getResultId(), precision);
 }
 
 // Comments in header
@@ -1178,7 +1187,7 @@
 }
 
 // Comments in header
-Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
+Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
 {
     assert(getNumComponents(scalar) == 1);
     assert(getTypeId(scalar) == getScalarTypeId(vectorType));
@@ -1192,11 +1201,11 @@
         smear->addIdOperand(scalar);
     buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
 
-    return smear->getResultId();
+    return setPrecision(smear->getResultId(), precision);
 }
 
 // Comments in header
-Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
+Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
 {
     Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
     inst->addIdOperand(builtins);
@@ -1205,6 +1214,7 @@
         inst->addIdOperand(args[arg]);
 
     buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
+
     return inst->getResultId();
 }
 
@@ -1386,6 +1396,7 @@
         // Decode the return type that was a special structure
         createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
         resultId = createCompositeExtract(resultId, typeId0, 0);
+        setPrecision(resultId, precision);
     } else {
         // When a smear is needed, do it, as per what was computed
         // above when resultType was changed to a scalar type.
@@ -1492,7 +1503,6 @@
         if (isScalarType(valueType)) {
             // scalar
             resultId = createBinOp(op, boolType, value1, value2);
-            setPrecision(resultId, precision);
         } else {
             // vector
             resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
@@ -1501,7 +1511,7 @@
             resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
         }
 
-        return resultId;
+        return setPrecision(resultId, precision);
     }
 
     // Only structs, arrays, and matrices should be left.
@@ -1521,7 +1531,7 @@
         if (constituent == 0)
             resultId = subResultId;
         else
-            resultId = createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId);
+            resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
     }
 
     return resultId;
@@ -1543,7 +1553,7 @@
 // Vector or scalar constructor
 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
 {
-    Id result = 0;
+    Id result = NoResult;
     unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
     unsigned int targetComponent = 0;
 
@@ -1566,7 +1576,7 @@
             if (sourceSize > 1) {
                 std::vector<unsigned> swiz;
                 swiz.push_back(s);
-                arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
+                arg = createRvalueSwizzle(precision, scalarTypeId, arg, swiz);
             }
 
             if (numTargetComponents > 1)
@@ -1583,9 +1593,7 @@
     if (constituents.size() > 0)
         result = createCompositeConstruct(resultTypeId, constituents);
 
-    setPrecision(result, precision);
-
-    return result;
+    return setPrecision(result, precision);
 }
 
 // Comments in header
@@ -1666,11 +1674,13 @@
         std::vector<Id> vectorComponents;
         for (int row = 0; row < numRows; ++row)
             vectorComponents.push_back(ids[col][row]);
-        matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
+        Id column = createCompositeConstruct(columnTypeId, vectorComponents);
+        setPrecision(column, precision);
+        matrixColumns.push_back(column);
     }
 
     // make the matrix
-    return createCompositeConstruct(resultTypeId, matrixColumns);
+    return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
 }
 
 // Comments in header
@@ -1895,7 +1905,7 @@
 }
 
 // Comments in header
-Id Builder::accessChainLoad(Id resultType)
+Id Builder::accessChainLoad(Decoration precision, Id resultType)
 {
     Id id;
 
@@ -1904,7 +1914,7 @@
         transferAccessChainSwizzle(false);
         if (accessChain.indexChain.size() > 0) {
             Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
-        
+
             // if all the accesses are constants, we can use OpCompositeExtract
             std::vector<unsigned> indexes;
             bool constant = true;
@@ -1933,12 +1943,14 @@
                 // load through the access chain
                 id = createLoad(collapseAccessChain());
             }
+            setPrecision(id, precision);
         } else
-            id = accessChain.base;
+            id = accessChain.base;  // no precision, it was set when this was defined
     } else {
         transferAccessChainSwizzle(true);
         // load through the access chain
         id = createLoad(collapseAccessChain());
+        setPrecision(id, precision);
     }
 
     // Done, unless there are swizzles to do
@@ -1952,12 +1964,12 @@
         Id swizzledType = getScalarTypeId(getTypeId(id));
         if (accessChain.swizzle.size() > 1)
             swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
-        id = createRvalueSwizzle(swizzledType, id, accessChain.swizzle);
+        id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
     }
 
     // dynamic single-component selection
     if (accessChain.component != NoResult)
-        id = createVectorExtractDynamic(id, resultType, accessChain.component);
+        id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
 
     return id;
 }
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index fbfbfad..00516c8 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -100,13 +100,13 @@
     Id makeIntType(int width) { return makeIntegerType(width, true); }
     Id makeUintType(int width) { return makeIntegerType(width, false); }
     Id makeFloatType(int width);
-    Id makeStructType(std::vector<Id>& members, const char*);
+    Id makeStructType(const std::vector<Id>& members, const char*);
     Id makeStructResultType(Id type0, Id type1);
     Id makeVectorType(Id component, int size);
     Id makeMatrixType(Id component, int cols, int rows);
     Id makeArrayType(Id element, unsigned size, int stride);  // 0 means no stride decoration
     Id makeRuntimeArray(Id element);
-    Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
+    Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
     Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
     Id makeSamplerType();
     Id makeSampledImageType(Id imageType);
@@ -210,7 +210,8 @@
     // Make a shader-style function, and create its entry block if entry is non-zero.
     // Return the function, pass back the entry.
     // The returned pointer is only valid for the lifetime of this builder.
-    Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
+    Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
+                                const std::vector<Decoration>& precisions, Block **entry = 0);
 
     // Create a return. An 'implicit' return is one not appearing in the source
     // code.  In the case of an implicit return, no post-return block is inserted.
@@ -225,7 +226,7 @@
     // Create a global or function local or IO variable.
     Id createVariable(StorageClass, Id type, const char* name = 0);
 
-    // Create an imtermediate with an undefined value.
+    // Create an intermediate with an undefined value.
     Id createUndefined(Id type);
 
     // Store into an Id and return the l-value
@@ -262,7 +263,7 @@
 
     // Take an rvalue (source) and a set of channels to extract from it to
     // make a new rvalue, which is returned.
-    Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
+    Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
 
     // Take a copy of an lvalue (target) and a source of components, and set the
     // source components into the lvalue where the 'channels' say to put them.
@@ -270,13 +271,15 @@
     // (No true lvalue or stores are used.)
     Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
 
-    // If the value passed in is an instruction and the precision is not NoPrecision,
-    // it gets tagged with the requested precision.
-    void setPrecision(Id /* value */, Decoration precision)
+    // If both the id and precision are valid, the id
+    // gets tagged with the requested precision.
+    // The passed in id is always the returned id, to simplify use patterns.
+    Id setPrecision(Id id, Decoration precision)
     {
-        if (precision != NoPrecision) {
-            ;// TODO
-        }
+        if (precision != NoPrecision && id != NoResult)
+            addDecoration(id, precision);
+
+        return id;
     }
 
     // Can smear a scalar to a vector for the following forms:
@@ -299,7 +302,7 @@
     Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
 
     // Create a call to a built-in function.
-    Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
+    Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
 
     // List of parameters used to create a texture operation
     struct TextureParameters {
@@ -330,7 +333,7 @@
     Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
     Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
 
-    // Reduction comparision for composites:  For equal and not-equal resulting in a scalar.
+    // Reduction comparison for composites:  For equal and not-equal resulting in a scalar.
     Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
 
     // OpCompositeConstruct
@@ -498,7 +501,7 @@
     void accessChainStore(Id rvalue);
 
     // use accessChain and swizzle to load an r-value
-    Id accessChainLoad(Id ResultType);
+    Id accessChainLoad(Decoration precision, Id ResultType);
 
     // get the direct pointer for an l-value
     Id accessChainGetLValue();