Avoid precision emulation overhead on unused values

Avoid rounding intermediate values when the intermediate value is not
consumed. For example, this avoids rounding the return value of
assignment, so "b = a;" becomes "b = frm(a);" instead of "frm(b =
frm(a))".

BUG=angle:874
TEST=compiler_tests

Change-Id: Ifcdb53fb1d07a2cf24e429cc237c2d0262dc32f8
Reviewed-on: https://chromium-review.googlesource.com/241852
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 9f77261..3729b0e 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -228,6 +228,28 @@
     return callNode;
 }
 
+bool parentUsesResult(TIntermNode* parent, TIntermNode* node)
+{
+    if (!parent)
+    {
+        return false;
+    }
+
+    TIntermAggregate *aggParent = parent->getAsAggregate();
+    // If the parent's op is EOpSequence, the result is not assigned anywhere,
+    // so rounding it is not needed. In particular, this can avoid a lot of
+    // unnecessary rounding of unused return values of assignment.
+    if (aggParent && aggParent->getOp() == EOpSequence)
+    {
+        return false;
+    }
+    if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node))
+    {
+        return false;
+    }
+    return true;
+}
+
 }  // namespace anonymous
 
 EmulatePrecision::EmulatePrecision()
@@ -293,6 +315,10 @@
           case EOpMatrixTimesMatrix:
           {
             TIntermNode *parent = getParentNode();
+            if (!parentUsesResult(parent, node))
+            {
+                break;
+            }
             TIntermNode *replacement = createRoundingFunctionCallNode(node);
             mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
             break;
@@ -395,8 +421,11 @@
         bool inFunctionMap = (mFunctionMap.find(node->getName()) != mFunctionMap.end());
         if (visit == PreVisit)
         {
-            if (canRoundFloat(node->getType()) && !inFunctionMap) {
-                TIntermNode *parent = getParentNode();
+            // User-defined function return values are not rounded, this relies on that
+            // calculations producing the value were rounded.
+            TIntermNode *parent = getParentNode();
+            if (canRoundFloat(node->getType()) && !inFunctionMap && parentUsesResult(parent, node))
+            {
                 TIntermNode *replacement = createRoundingFunctionCallNode(node);
                 mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
             }
@@ -437,9 +466,9 @@
         break;
       }
       default:
-        if (canRoundFloat(node->getType()) && visit == PreVisit)
+        TIntermNode *parent = getParentNode();
+        if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node))
         {
-            TIntermNode *parent = getParentNode();
             TIntermNode *replacement = createRoundingFunctionCallNode(node);
             mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
         }