Vulkan: SPIR-V Gen: Fix precision of findMsb

In GLSL, findMsb operates on a highp operand, while returning a lowp
result.  In SPIR-V, RelaxedPrecision cannot be applied on the FindSMsb
instruction as that affects the operand as well.  This change makes sure
RelaxedPrecision is not applied to a FindSMsb instruction.

Bug: angleproject:4889
Bug: angleproject:6132
Change-Id: I6a0defbbd53ec703c7ecbad5cd5c79d215b11c32
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3158506
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/BuildSPIRV.cpp b/src/compiler/translator/BuildSPIRV.cpp
index aa52769..a80852e 100644
--- a/src/compiler/translator/BuildSPIRV.cpp
+++ b/src/compiler/translator/BuildSPIRV.cpp
@@ -675,10 +675,37 @@
     return decorations;
 }
 
-SpirvDecorations SPIRVBuilder::getArithmeticDecorations(const TType &type, bool isPrecise)
+SpirvDecorations SPIRVBuilder::getArithmeticDecorations(const TType &type,
+                                                        bool isPrecise,
+                                                        TOperator op)
 {
     SpirvDecorations decorations = getDecorations(type);
 
+    // In GLSL, findMsb operates on a highp operand, while returning a lowp result.  In SPIR-V,
+    // RelaxedPrecision cannot be applied on the Find*Msb instructions as that affects the operand
+    // as well:
+    //
+    // > The RelaxedPrecision Decoration can be applied to:
+    // > ...
+    // > The Result <id> of an instruction that operates on numerical types, meaning the instruction
+    // > is to operate at relaxed precision. The instruction's operands may also be truncated to the
+    // > relaxed precision.
+    // > ...
+    //
+    // Here, we remove RelaxedPrecision from such problematic instructions.
+    switch (op)
+    {
+        case EOpFindMSB:
+            // Currently getDecorations() only adds RelaxedPrecision, so removing the
+            // RelaxedPrecision decoration is simply done by clearing the vector.
+            ASSERT(decorations.empty() ||
+                   (decorations.size() == 1 && decorations[0] == spv::DecorationRelaxedPrecision));
+            decorations.clear();
+            break;
+        default:
+            break;
+    }
+
     // Handle |precise|.
     if (isPrecise)
     {
diff --git a/src/compiler/translator/BuildSPIRV.h b/src/compiler/translator/BuildSPIRV.h
index c3be402..4b30401 100644
--- a/src/compiler/translator/BuildSPIRV.h
+++ b/src/compiler/translator/BuildSPIRV.h
@@ -316,7 +316,7 @@
     // Decorations that may apply to intermediate instructions (in addition to variables).
     // |precise| is only applicable to arithmetic nodes.
     SpirvDecorations getDecorations(const TType &type);
-    SpirvDecorations getArithmeticDecorations(const TType &type, bool isPrecise);
+    SpirvDecorations getArithmeticDecorations(const TType &type, bool isPrecise, TOperator op);
 
     // Extended instructions
     spirv::IdRef getExtInstImportIdStd();
diff --git a/src/compiler/translator/OutputSPIRV.cpp b/src/compiler/translator/OutputSPIRV.cpp
index c6a3233..ce89b7a 100644
--- a/src/compiler/translator/OutputSPIRV.cpp
+++ b/src/compiler/translator/OutputSPIRV.cpp
@@ -2851,7 +2851,7 @@
     }
 
     const SpirvDecorations decorations =
-        mBuilder.getArithmeticDecorations(node->getType(), node->isPrecise());
+        mBuilder.getArithmeticDecorations(node->getType(), node->isPrecise(), op);
     spirv::IdRef result;
     if (node->getType().getBasicType() != EbtVoid)
     {
@@ -2959,7 +2959,7 @@
         {
             const spirv::IdRef one           = mBuilder.getFloatConstant(1);
             const spirv::IdRef invertedParam = mBuilder.getNewId(
-                mBuilder.getArithmeticDecorations(secondChild->getType(), node->isPrecise()));
+                mBuilder.getArithmeticDecorations(secondChild->getType(), node->isPrecise(), op));
             spirv::WriteFDiv(mBuilder.getSpirvCurrentFunctionBlock(), parameterTypeIds.back(),
                              invertedParam, one, parameters[1]);
             parameters[1] = invertedParam;