Add a new invariant declaration operator.

BUG=angle:711

Change-Id: I54a48b636a68c317b8d44ee2d578847b80095289
Reviewed-on: https://chromium-review.googlesource.com/213500
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index 7260799..324b066 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -69,7 +69,6 @@
     EbtStruct,
     EbtInterfaceBlock,
     EbtAddress,            // should be deprecated??
-    EbtInvariant          // used as a type when qualifying a previously declared variable as being invariant
 };
 
 const char* getBasicString(TBasicType t);
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 892f284..ec440da 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -37,6 +37,7 @@
     EOpParameters,      // an aggregate listing the parameters to a function
 
     EOpDeclaration,
+    EOpInvariantDeclaration, // Specialized declarations for attributing invariance
     EOpPrototype,
 
     //
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 09f7ad9..6d07ccc 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -81,8 +81,7 @@
 {
     TInfoSinkBase &out = objSink();
     TQualifier qualifier = type.getQualifier();
-    if (qualifier != EvqTemporary && qualifier != EvqGlobal &&
-        type.getBasicType() != EbtInvariant)
+    if (qualifier != EvqTemporary && qualifier != EvqGlobal)
     {
         out << type.getQualifierString() << " ";
     }
@@ -650,6 +649,17 @@
             mDeclaringVariables = false;
         }
         break;
+      case EOpInvariantDeclaration: {
+            // Invariant declaration.
+            ASSERT(visit == PreVisit);
+            const TIntermSequence *sequence = node->getSequence();
+            ASSERT(sequence && sequence->size() == 1);
+            const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
+            ASSERT(symbol);
+            out << "invariant " << symbol->getSymbol() << ";";
+            visitChildren = false;
+            break;
+        }
       case EOpConstructFloat:
         writeTriplet(visit, "float(", NULL, ")");
         break;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 93994ba..e0a90ec 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1937,12 +1937,6 @@
             }
             else if (variable && IsVaryingOut(variable->getQualifier()))
             {
-                // Skip translation of invariant declarations
-                if (variable->getBasicType() == EbtInvariant)
-                {
-                    return false;
-                }
-
                 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
                 {
                     TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
@@ -1966,6 +1960,9 @@
             out << ", ";
         }
         break;
+      case EOpInvariantDeclaration:
+        // Do not do any translation
+        return false;
       case EOpPrototype:
         if (visit == PreVisit)
         {
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 04797da..ff0a496 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1089,6 +1089,8 @@
 // Initializers show up in several places in the grammar.  Have one set of
 // code to handle them here.
 //
+// Returns true on error, false if no error
+//
 bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, 
                                        TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
 {
@@ -1352,6 +1354,7 @@
                                                            const TString *identifier,
                                                            const TSymbol *symbol)
 {
+    // invariant declaration
     if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
     {
         recover();
@@ -1366,21 +1369,20 @@
     }
     else
     {
-        TType type(EbtInvariant);
-        type.setQualifier(EvqInvariantVaryingOut);
-        TIntermSymbol *symbol = intermediate.addSymbol(0, *identifier, type, identifierLoc);
-        return intermediate.makeAggregate(symbol, identifierLoc);
+        const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
+        ASSERT(variable);
+        const TType &type = variable->getType();
+        TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(),
+                                                             *identifier, type, identifierLoc);
+
+        TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
+        aggregate->setOp(EOpInvariantDeclaration);
+        return aggregate;
     }
 }
 
 TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
 {
-    if (publicType.type == EbtInvariant && !identifierSymbol)
-    {
-        error(identifierLocation, "undeclared identifier declared as invariant", identifier.c_str());
-        recover();
-    }
-
     TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
     TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
 
diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp
index d39ab01..d36936f 100644
--- a/src/compiler/translator/Types.cpp
+++ b/src/compiler/translator/Types.cpp
@@ -41,7 +41,6 @@
       case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; break;
       case EbtStruct:               return "structure";            break;
       case EbtInterfaceBlock:       return "interface block";      break;
-      case EbtInvariant:            return "invariant";            break;
       default: UNREACHABLE();       return "unknown type";
     }
 }
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 0bd95cb..54129d4 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -346,12 +346,7 @@
                     visitInfoList(sequence, mUniforms);
                     break;
                   default:
-                    // do not traverse invariant declarations such as
-                    //  "invariant gl_Position;"
-                    if (typedNode.getBasicType() != EbtInvariant)
-                    {
-                        visitInfoList(sequence, mVaryings);
-                    }
+                    visitInfoList(sequence, mVaryings);
                     break;
                 }
 
diff --git a/src/compiler/translator/VersionGLSL.cpp b/src/compiler/translator/VersionGLSL.cpp
index 12dc9e0..8edbd00 100644
--- a/src/compiler/translator/VersionGLSL.cpp
+++ b/src/compiler/translator/VersionGLSL.cpp
@@ -67,6 +67,9 @@
             }
             break;
         }
+      case EOpInvariantDeclaration:
+        updateVersion(GLSL_VERSION_120);
+        break;
       case EOpParameters:
         {
             const TIntermSequence &params = *(node->getSequence());
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index c0479f6..5c945ad 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -1072,8 +1072,7 @@
         $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
     }
     | INVARIANT IDENTIFIER {
-        VERTEX_ONLY("invariant declaration", @1);
-        $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, @2);
+        // $$.type is not used in invariant declarations.
         $$.intermAggregate = context->parseInvariantDeclaration(@1, @2, $2.string, $2.symbol);
     }
     ;
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 2fb9089..6d483b1 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -805,22 +805,22 @@
      730,   733,   744,   752,   760,   787,   793,   804,   808,   812,
      816,   823,   879,   882,   889,   897,   918,   939,   949,   977,
      982,   992,   997,  1007,  1010,  1013,  1016,  1022,  1029,  1032,
-    1036,  1040,  1044,  1051,  1055,  1059,  1066,  1070,  1074,  1082,
-    1091,  1097,  1100,  1106,  1112,  1119,  1128,  1137,  1145,  1148,
-    1155,  1159,  1166,  1169,  1173,  1177,  1186,  1195,  1203,  1213,
-    1225,  1228,  1231,  1237,  1244,  1247,  1253,  1256,  1259,  1265,
-    1268,  1283,  1287,  1291,  1295,  1299,  1303,  1308,  1313,  1318,
-    1323,  1328,  1333,  1338,  1343,  1348,  1353,  1358,  1363,  1368,
-    1373,  1378,  1383,  1388,  1393,  1398,  1403,  1408,  1412,  1416,
-    1420,  1424,  1428,  1432,  1436,  1440,  1444,  1448,  1452,  1456,
-    1460,  1464,  1468,  1476,  1484,  1488,  1501,  1501,  1504,  1504,
-    1510,  1513,  1529,  1532,  1541,  1545,  1551,  1558,  1573,  1577,
-    1581,  1582,  1588,  1589,  1590,  1591,  1592,  1596,  1597,  1597,
-    1597,  1607,  1608,  1612,  1612,  1613,  1613,  1618,  1621,  1631,
-    1634,  1640,  1641,  1645,  1653,  1657,  1667,  1672,  1689,  1689,
-    1694,  1694,  1701,  1701,  1709,  1712,  1718,  1721,  1727,  1731,
-    1738,  1745,  1752,  1759,  1770,  1779,  1783,  1790,  1793,  1799,
-    1799
+    1036,  1040,  1044,  1051,  1055,  1059,  1066,  1070,  1074,  1081,
+    1090,  1096,  1099,  1105,  1111,  1118,  1127,  1136,  1144,  1147,
+    1154,  1158,  1165,  1168,  1172,  1176,  1185,  1194,  1202,  1212,
+    1224,  1227,  1230,  1236,  1243,  1246,  1252,  1255,  1258,  1264,
+    1267,  1282,  1286,  1290,  1294,  1298,  1302,  1307,  1312,  1317,
+    1322,  1327,  1332,  1337,  1342,  1347,  1352,  1357,  1362,  1367,
+    1372,  1377,  1382,  1387,  1392,  1397,  1402,  1407,  1411,  1415,
+    1419,  1423,  1427,  1431,  1435,  1439,  1443,  1447,  1451,  1455,
+    1459,  1463,  1467,  1475,  1483,  1487,  1500,  1500,  1503,  1503,
+    1509,  1512,  1528,  1531,  1540,  1544,  1550,  1557,  1572,  1576,
+    1580,  1581,  1587,  1588,  1589,  1590,  1591,  1595,  1596,  1596,
+    1596,  1606,  1607,  1611,  1611,  1612,  1612,  1617,  1620,  1630,
+    1633,  1639,  1640,  1644,  1652,  1656,  1666,  1671,  1688,  1688,
+    1693,  1693,  1700,  1700,  1708,  1711,  1717,  1720,  1726,  1730,
+    1737,  1744,  1751,  1758,  1769,  1778,  1782,  1789,  1792,  1798,
+    1798
 };
 #endif
 
@@ -3689,8 +3689,7 @@
   case 108:
 
     {
-        VERTEX_ONLY("invariant declaration", (yylsp[(1) - (2)]));
-        (yyval.interm).type.setBasic(EbtInvariant, EvqInvariantVaryingOut, (yylsp[(2) - (2)]));
+        // $$.type is not used in invariant declarations.
         (yyval.interm).intermAggregate = context->parseInvariantDeclaration((yylsp[(1) - (2)]), (yylsp[(2) - (2)]), (yyvsp[(2) - (2)].lex).string, (yyvsp[(2) - (2)].lex).symbol);
     }
     break;
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index 52a6f51..56340c6 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -342,6 +342,7 @@
       case EOpMul:           out << "component-wise multiply"; break;
 
       case EOpDeclaration:   out << "Declaration: ";   break;
+      case EOpInvariantDeclaration: out << "Invariant Declaration: "; break;
 
       default:
         out.prefix(EPrefixError);