SPV: Partially address #2293: correct "const in" precision matching.

Track whether formal parameters declare reduced precision and match
that with arguments, and if they differ, make a copy to promote the
precision.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index b63d901..fb36212 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -5346,13 +5346,21 @@
             }
             ++lValueCount;
         } else {
+            const bool argIsRelaxedPrecision = TranslatePrecisionDecoration(*argTypes[a]) ==
+                spv::DecorationRelaxedPrecision;
             // process r-value, which involves a copy for a type mismatch
-            if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a])) {
+            if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a]) ||
+                argIsRelaxedPrecision != function->isReducedPrecisionParam(a))
+            {
                 spv::Id argCopy = builder.createVariable(spv::StorageClassFunction, function->getParamType(a), "arg");
+                if (function->isReducedPrecisionParam(a))
+                    builder.setPrecision(argCopy, spv::DecorationRelaxedPrecision);
                 builder.clearAccessChain();
                 builder.setAccessChainLValue(argCopy);
                 multiTypeStore(*argTypes[a], rValues[rValueCount]);
                 arg = builder.createLoad(argCopy);
+                if (function->isReducedPrecisionParam(a))
+                    builder.setPrecision(arg, spv::DecorationRelaxedPrecision);
             } else
                 arg = rValues[rValueCount];
             ++rValueCount;
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 62b7d0e..f884224 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -1298,8 +1298,11 @@
     // Set up the precisions
     setPrecision(function->getId(), precision);
     for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
-        for (int d = 0; d < (int)decorations[p].size(); ++d)
+        for (int d = 0; d < (int)decorations[p].size(); ++d) {
             addDecoration(firstParamId + p, decorations[p][d]);
+            if (decorations[p][d] == DecorationRelaxedPrecision)
+                function->addReducedPrecisionParam(p);
+        }
     }
 
     // CFG
diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h
index 6523035..6146518 100755
--- a/SPIRV/spvIR.h
+++ b/SPIRV/spvIR.h
@@ -55,6 +55,7 @@
 #include <iostream>
 #include <memory>
 #include <vector>
+#include <set>
 
 namespace spv {
 
@@ -355,6 +356,10 @@
     void setImplicitThis() { implicitThis = true; }
     bool hasImplicitThis() const { return implicitThis; }
 
+    void addReducedPrecisionParam(int p) { reducedPrecisionParams.insert(p); }
+    bool isReducedPrecisionParam(int p) const
+        { return reducedPrecisionParams.find(p) != reducedPrecisionParams.end(); }
+
     void dump(std::vector<unsigned int>& out) const
     {
         // OpFunction
@@ -379,6 +384,7 @@
     std::vector<Instruction*> parameterInstructions;
     std::vector<Block*> blocks;
     bool implicitThis;  // true if this is a member function expecting to be passed a 'this' as the first argument
+    std::set<int> reducedPrecisionParams;  // list of parameter indexes that need a relaxed precision arg
 };
 
 //