From e406f1c71c338081e3ad4bf92c10ff804e79da6e Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Mon, 28 Jan 2013 23:52:49 +0000
Subject: [PATCH] Put in basic propagation algorithm for precision qualifiers. 
 Some corner cases are document as TODO.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20360 e7fa87d3-cd2b-0410-9028-fcbf551c1848
---
 Test/precision.frag                         |  6 ++-
 glslang/Include/intermediate.h              |  7 +--
 glslang/MachineIndependent/Intermediate.cpp | 50 ++++++++++++++++++++-
 glslang/MachineIndependent/ParseHelper.cpp  |  1 -
 glslang/MachineIndependent/intermOut.cpp    |  8 ++--
 5 files changed, 61 insertions(+), 11 deletions(-)

diff --git a/Test/precision.frag b/Test/precision.frag
index f0ea6598d..c9b1d7aba 100644
--- a/Test/precision.frag
+++ b/Test/precision.frag
@@ -35,17 +35,19 @@ void main()
         int level2_high;
         sum += level2_high;
         do {
-            if (1) {
+            if (true) {
                 precision mediump int;
                 int level4_medium;
                 sum += level4_medium;
             }
             int level3_high;
             sum += level3_high;
-        } while (1);	
+        } while (true);	
         int level2_high2;
         sum += level2_high2;
     }
     int level1_low3;
     sum += level1_low3;
+
+    sum += 4 + ((ivec2(level1_low3) * ivec2(level1_high) + ivec2((/* comma operator */level1_low3, level1_high)))).x;
 }
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index cbab65d0a..c6e234c6b 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -231,6 +231,7 @@ enum TOperator {
 
 class TIntermTraverser;
 class TIntermAggregate;
+class TIntermUnary;
 class TIntermBinary;
 class TIntermConstantUnion;
 class TIntermSelection;
@@ -253,6 +254,7 @@ public:
     virtual TIntermTyped*     getAsTyped()         { return 0; }
     virtual TIntermConstantUnion*     getAsConstantUnion()         { return 0; }
     virtual TIntermAggregate* getAsAggregate()     { return 0; }
+    virtual TIntermUnary*     getAsUnaryNode()     { return 0; }
     virtual TIntermBinary*    getAsBinaryNode()    { return 0; }
     virtual TIntermSelection* getAsSelectionNode() { return 0; }
     virtual TIntermMethod*    getAsMethodNode()    { return 0; }
@@ -270,9 +272,6 @@ struct TIntermNodePair {
     TIntermNode* node2;
 };
 
-class TIntermSymbol;
-class TIntermBinary;
-
 //
 // Intermediate class for nodes that have a type.
 //
@@ -286,6 +285,7 @@ public:
     
     virtual TBasicType getBasicType() const { return type.getBasicType(); }
     virtual TQualifier& getQualifier() { return type.getQualifier(); }
+    virtual void propagatePrecision(TPrecisionQualifier);
     virtual int getNominalSize() const { return type.getNominalSize(); }
     virtual int getSize() const { return type.getInstanceSize(); }
     virtual bool isMatrix() const { return type.isMatrix(); }
@@ -428,6 +428,7 @@ public:
     virtual void traverse(TIntermTraverser*);
     virtual void setOperand(TIntermTyped* o) { operand = o; }
     virtual TIntermTyped* getOperand() { return operand; }
+    virtual TIntermUnary* getAsUnaryNode() { return this; }
     virtual bool promote(TInfoSink&);
 protected:
     TIntermTyped* operand;
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 040de594a..389d4a9b7 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -836,6 +836,8 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
     // Fix precision qualifiers
     if (right->getQualifier().precision > getQualifier().precision)
         getQualifier().precision = right->getQualifier().precision;
+    left->propagatePrecision(getQualifier().precision);
+    right->propagatePrecision(getQualifier().precision);
 
     //
     // Array operations.
@@ -1078,7 +1080,53 @@ bool CompareStruct(const TType& leftNodeType, constUnion* rightUnionArray, const
         }
     }
     return true;
-} 
+}
+
+void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
+{
+    if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtFloat))
+        return;
+
+    getQualifier().precision = newPrecision;
+
+    TIntermBinary* binaryNode = getAsBinaryNode();
+    if (binaryNode) {
+        binaryNode->getLeft()->propagatePrecision(newPrecision);
+        binaryNode->getRight()->propagatePrecision(newPrecision);
+    }
+
+    TIntermUnary* unaryNode = getAsUnaryNode();
+    if (unaryNode)
+        unaryNode->getOperand()->propagatePrecision(newPrecision);
+
+    TIntermAggregate* aggregateNode = getAsAggregate();
+    if (aggregateNode) {
+        TIntermSequence operands = aggregateNode->getSequence();
+        for (unsigned int i = 0; i < operands.size(); ++i) {
+            TIntermTyped* typedNode = operands[i]->getAsTyped();
+            if (! typedNode)
+                break;
+            typedNode->propagatePrecision(newPrecision);
+        }
+    }
+
+    TIntermSelection* selectionNode = getAsSelectionNode();
+    if (selectionNode) {
+        TIntermTyped* typedNode = selectionNode->getTrueBlock()->getAsTyped();
+        if (typedNode) {
+            typedNode->propagatePrecision(newPrecision);
+            typedNode = selectionNode->getFalseBlock()->getAsTyped();
+            if (typedNode)
+                typedNode->propagatePrecision(newPrecision);
+        }
+    }
+
+    // TODO: propagate precision for
+    //    comma operator:  just through the last operand
+    //    ":?" and ",": where is this triggered?
+    //    built-in function calls: how much to propagate to arguments?
+    //    performance: don't do this for desktop profiles
+}
 
 bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray)
 {
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 797ec2512..13b3bc3d0 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -60,7 +60,6 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLangu
     defaultPrecision[EbtVoid]   = EpqNone;
     defaultPrecision[EbtDouble] = EpqNone;
     defaultPrecision[EbtBool]   = EpqNone;
-    defaultPrecision[EbtVoid]   = EpqNone;
 }
 
 //
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 42252f8c8..df07121e6 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -258,11 +258,11 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
     OutputTreeText(out, node, oit->depth);
 
     switch (node->getOp()) {
-    case EOpSequence:      out.debug << "Sequence\n"; return true;
-    case EOpComma:         out.debug << "Comma\n"; return true;
+    case EOpSequence:      out.debug << "Sequence\n";       return true;
+    case EOpComma:         out.debug << "Comma";            break;
     case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
-    case EOpFunctionCall:  out.debug << "Function Call: " << node->getName(); break;
-    case EOpParameters:    out.debug << "Function Parameters: ";              break;
+    case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
+    case EOpParameters:    out.debug << "Function Parameters: ";                    break;
     
     case EOpConstructFloat: out.debug << "Construct float"; break;
     case EOpConstructVec2:  out.debug << "Construct vec2";  break;
-- 
GitLab