Added type checking for Mod and bitwise ops

Added type checking and bitwise logic in a
few cases for Mod and bitwise operators for
TIntermediate, TIntermBinary and
TIntermConstantUnion.

Change-Id: Ic6ac624fd8d6d9f407f1b8fac40ae31f54a6c7da
Reviewed-on: https://swiftshader-review.googlesource.com/3113
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index 7f056fb..fad11c6 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -177,12 +177,27 @@
                 return 0;
             }
             break;
+        case EOpBitwiseOr:
+        case EOpBitwiseXor:
+        case EOpBitwiseAnd:
+            if ((left->getBasicType() != EbtInt && left->getBasicType() != EbtUInt) || left->isMatrix() || left->isArray()) {
+                return 0;
+            }
+            break;
         case EOpAdd:
         case EOpSub:
         case EOpDiv:
         case EOpMul:
-            if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+            if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) {
                 return 0;
+            }
+            break;
+        case EOpIMod:
+            // Note that this is only for the % operator, not for mod()
+            if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) {
+                return 0;
+            }
+            break;
         default: break;
     }
 
@@ -285,6 +300,12 @@
     }
 
     switch (op) {
+        case EOpBitwiseNot:
+            if ((child->getType().getBasicType() != EbtInt && child->getType().getBasicType() != EbtUInt) || child->getType().isMatrix() || child->getType().isArray()) {
+                return 0;
+            }
+            break;
+
         case EOpLogicalNot:
             if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
                 return 0;
@@ -659,6 +680,10 @@
             if (operand->getBasicType() != EbtBool)
                 return false;
             break;
+        case EOpBitwiseNot:
+            if(operand->getBasicType() != EbtInt && operand->getBasicType() != EbtUInt)
+                return false;
+            break;
         case EOpNegative:
         case EOpPostIncrement:
         case EOpPostDecrement:
@@ -726,13 +751,13 @@
         getTypePointer()->setQualifier(EvqTemporary);
     }
 
-    int size = std::max(left->getNominalSize(), right->getNominalSize());
-	int matrixSize = std::max(left->getSecondarySize(), right->getSecondarySize()); // FIXME: This will have to change for NxM matrices
+    int primarySize = std::max(left->getNominalSize(), right->getNominalSize());
+	int secondarySize = std::max(left->getSecondarySize(), right->getSecondarySize());
 
     //
     // All scalars. Code after this test assumes this case is removed!
     //
-    if (size == 1) {
+    if (primarySize == 1) {
         switch (op) {
             //
             // Promote to conditional
@@ -751,6 +776,7 @@
             //
             case EOpLogicalAnd:
             case EOpLogicalOr:
+            case EOpLogicalXor:
                 // Both operands must be of type bool.
                 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
                     return false;
@@ -794,12 +820,12 @@
                     op = EOpVectorTimesMatrix;
                 else {
                     op = EOpMatrixTimesScalar;
-                    setType(TType(basicType, higherPrecision, EvqTemporary, size, matrixSize));
+                    setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, secondarySize));
                 }
             } else if (left->isMatrix() && !right->isMatrix()) {
                 if (right->isVector()) {
                     op = EOpMatrixTimesVector;
-                    setType(TType(basicType, higherPrecision, EvqTemporary, size, 1));
+                    setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
                 } else {
                     op = EOpMatrixTimesScalar;
                 }
@@ -810,7 +836,7 @@
                     // leave as component product
                 } else if (left->isVector() || right->isVector()) {
                     op = EOpVectorTimesScalar;
-                    setType(TType(basicType, higherPrecision, EvqTemporary, size, 1));
+                    setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
                 }
             } else {
                 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
@@ -839,7 +865,7 @@
                     if (! left->isVector())
                         return false;
                     op = EOpVectorTimesScalarAssign;
-                    setType(TType(basicType, higherPrecision, EvqTemporary, size, 1));
+                    setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
                 }
             } else {
                 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
@@ -852,6 +878,12 @@
         case EOpAdd:
         case EOpSub:
         case EOpDiv:
+        case EOpIMod:
+        case EOpBitShiftLeft:
+        case EOpBitShiftRight:
+        case EOpBitwiseAnd:
+        case EOpBitwiseXor:
+        case EOpBitwiseOr:
         case EOpAddAssign:
         case EOpSubAssign:
         case EOpDivAssign:
@@ -864,7 +896,35 @@
             if ((left->isMatrix() && right->isVector()) ||
                 (left->isVector() && right->isMatrix()))
                 return false;
-            setType(TType(basicType, higherPrecision, EvqTemporary, size, matrixSize));
+
+            // Are the sizes compatible?
+            if(left->getNominalSize() != right->getNominalSize() ||
+               left->getSecondarySize() != right->getSecondarySize())
+            {
+                // If the nominal sizes of operands do not match:
+                // One of them must be a scalar.
+                if(!left->isScalar() && !right->isScalar())
+                    return false;
+
+                // In the case of compound assignment other than multiply-assign,
+                // the right side needs to be a scalar. Otherwise a vector/matrix
+                // would be assigned to a scalar. A scalar can't be shifted by a
+                // vector either.
+                if(!right->isScalar() && (modifiesState() || op == EOpBitShiftLeft || op == EOpBitShiftRight))
+                    return false;
+            }
+
+            {
+                setType(TType(basicType, higherPrecision, EvqTemporary,
+                    static_cast<unsigned char>(primarySize), static_cast<unsigned char>(secondarySize)));
+                if(left->isArray())
+                {
+                    ASSERT(left->getArraySize() == right->getArraySize());
+                    type.setArraySize(left->getArraySize());
+                }
+            }
+
+            setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, secondarySize));
             break;
 
         case EOpEqual:
@@ -1009,35 +1069,50 @@
                 }
                 break;
             case EOpDiv:
+            case EOpIMod:
                 tempConstArray = new ConstantUnion[objectSize];
                 {// support MSVC++6.0
                     for (int i = 0; i < objectSize; i++) {
                         switch (getType().getBasicType()) {
-            case EbtFloat:
-                if (rightUnionArray[i] == 0.0f) {
-                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
-                    tempConstArray[i].setFConst(FLT_MAX);
-                } else
-                    tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
-                break;
+                            case EbtFloat:
+                                if (rightUnionArray[i] == 0.0f) {
+                                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+                                    tempConstArray[i].setFConst(FLT_MAX);
+                                } else {
+                                    ASSERT(op == EOpDiv);
+                                    tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
+                                }
+                                break;
 
-            case EbtInt:
-                if (rightUnionArray[i] == 0) {
-                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
-                    tempConstArray[i].setIConst(INT_MAX);
-                } else
-                    tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
-                break;
-            case EbtUInt:
-                if (rightUnionArray[i] == 0) {
-                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
-                    tempConstArray[i].setUConst(UINT_MAX);
-                } else
-                    tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
-                break;
-            default:
-                infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
-                return 0;
+                            case EbtInt:
+                                if (rightUnionArray[i] == 0) {
+                                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+                                    tempConstArray[i].setIConst(INT_MAX);
+                                } else {
+                                    if(op == EOpDiv) {
+                                        tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
+                                    } else {
+                                        ASSERT(op == EOpIMod);
+                                        tempConstArray[i].setIConst(unionArray[i].getIConst() % rightUnionArray[i].getIConst());
+                                    }
+                                }
+                                break;
+                            case EbtUInt:
+                                if (rightUnionArray[i] == 0) {
+                                    infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+                                    tempConstArray[i].setUConst(UINT_MAX);
+                                } else {
+                                    if(op == EOpDiv) {
+                                        tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
+                                    } else {
+                                        ASSERT(op == EOpIMod);
+                                        tempConstArray[i].setUConst(unionArray[i].getUConst() % rightUnionArray[i].getUConst());
+                                    }
+                                }
+                                break;
+                            default:
+                                infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
+                                return 0;
                         }
                     }
                 }
@@ -1102,12 +1177,38 @@
                 {// support MSVC++6.0
                     for (int i = 0; i < objectSize; i++)
                         switch (getType().getBasicType()) {
-            case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
-            default: assert(false && "Default missing");
+                            case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
+                            default: assert(false && "Default missing");
                     }
                 }
                 break;
 
+            case EOpBitwiseAnd:
+                tempConstArray = new ConstantUnion[objectSize];
+                for(int i = 0; i < objectSize; i++)
+                    tempConstArray[i] = unionArray[i] & rightUnionArray[i];
+                break;
+            case EOpBitwiseXor:
+                tempConstArray = new ConstantUnion[objectSize];
+                for(int i = 0; i < objectSize; i++)
+                    tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
+                break;
+            case EOpBitwiseOr:
+                tempConstArray = new ConstantUnion[objectSize];
+                for(int i = 0; i < objectSize; i++)
+                    tempConstArray[i] = unionArray[i] | rightUnionArray[i];
+                break;
+            case EOpBitShiftLeft:
+                tempConstArray = new ConstantUnion[objectSize];
+                for(int i = 0; i < objectSize; i++)
+                    tempConstArray[i] = unionArray[i] << rightUnionArray[i];
+                break;
+            case EOpBitShiftRight:
+                tempConstArray = new ConstantUnion[objectSize];
+                for(int i = 0; i < objectSize; i++)
+                    tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
+                break;
+
             case EOpLessThan:
                 assert(objectSize == 1);
                 tempConstArray = new ConstantUnion[1];
@@ -1226,6 +1327,15 @@
                             return 0;
                     }
                     break;
+                case EOpBitwiseNot:
+                    switch(getType().getBasicType()) {
+                        case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break;
+                        case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break;
+                        default:
+                            infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+                            return 0;
+                    }
+                    break;
                 default:
                     return 0;
             }
diff --git a/src/OpenGL/compiler/glslang.y b/src/OpenGL/compiler/glslang.y
index 9fba3a7..0dff1c9 100644
--- a/src/OpenGL/compiler/glslang.y
+++ b/src/OpenGL/compiler/glslang.y
@@ -749,6 +749,7 @@
                 switch($1.op) {
                 case EOpNegative:   errorOp = "-"; break;
                 case EOpLogicalNot: errorOp = "!"; break;
+                case EOpBitwiseNot: errorOp = "~"; break;
                 default: break;
                 }
                 context->unaryOpError($1.line, errorOp, $2->getCompleteString());
diff --git a/src/OpenGL/compiler/glslang_tab.cpp b/src/OpenGL/compiler/glslang_tab.cpp
index d73a1f4..a672362 100644
--- a/src/OpenGL/compiler/glslang_tab.cpp
+++ b/src/OpenGL/compiler/glslang_tab.cpp
@@ -733,29 +733,29 @@
        0,   190,   190,   225,   228,   233,   238,   243,   248,   254,
      257,   336,   339,   440,   450,   463,   471,   571,   574,   582,
      586,   593,   597,   604,   610,   619,   627,   704,   711,   721,
-     724,   734,   744,   765,   766,   767,   768,   776,   777,   786,
-     795,   808,   809,   817,   828,   829,   838,   850,   851,   861,
-     871,   881,   894,   895,   905,   918,   919,   933,   934,   948,
-     949,   963,   964,   977,   978,   991,   992,  1005,  1006,  1023,
-    1024,  1037,  1038,  1039,  1040,  1042,  1043,  1044,  1046,  1048,
-    1050,  1052,  1057,  1060,  1071,  1079,  1106,  1111,  1121,  1159,
-    1162,  1169,  1177,  1198,  1219,  1230,  1259,  1264,  1274,  1279,
-    1289,  1292,  1295,  1298,  1304,  1311,  1314,  1336,  1354,  1378,
-    1401,  1405,  1423,  1431,  1463,  1483,  1571,  1580,  1603,  1606,
-    1612,  1618,  1625,  1634,  1643,  1646,  1649,  1656,  1660,  1667,
-    1671,  1676,  1681,  1687,  1693,  1702,  1712,  1719,  1722,  1725,
-    1731,  1738,  1741,  1747,  1750,  1753,  1759,  1762,  1777,  1781,
-    1785,  1789,  1793,  1797,  1802,  1807,  1812,  1817,  1822,  1827,
-    1832,  1837,  1842,  1847,  1852,  1857,  1863,  1869,  1875,  1881,
-    1887,  1893,  1899,  1905,  1911,  1916,  1921,  1930,  1935,  1940,
-    1945,  1950,  1955,  1960,  1965,  1970,  1975,  1980,  1985,  1990,
-    1995,  2000,  2013,  2013,  2027,  2027,  2036,  2039,  2054,  2086,
-    2090,  2096,  2104,  2120,  2124,  2128,  2129,  2135,  2136,  2137,
-    2138,  2139,  2143,  2144,  2144,  2144,  2154,  2155,  2159,  2159,
-    2160,  2160,  2165,  2168,  2178,  2181,  2187,  2188,  2192,  2200,
-    2204,  2214,  2219,  2236,  2236,  2241,  2241,  2248,  2248,  2256,
-    2259,  2265,  2268,  2274,  2278,  2285,  2292,  2299,  2306,  2317,
-    2326,  2330,  2337,  2340,  2346,  2346
+     724,   734,   744,   766,   767,   768,   769,   777,   778,   787,
+     796,   809,   810,   818,   829,   830,   839,   851,   852,   862,
+     872,   882,   895,   896,   906,   919,   920,   934,   935,   949,
+     950,   964,   965,   978,   979,   992,   993,  1006,  1007,  1024,
+    1025,  1038,  1039,  1040,  1041,  1043,  1044,  1045,  1047,  1049,
+    1051,  1053,  1058,  1061,  1072,  1080,  1107,  1112,  1122,  1160,
+    1163,  1170,  1178,  1199,  1220,  1231,  1260,  1265,  1275,  1280,
+    1290,  1293,  1296,  1299,  1305,  1312,  1315,  1337,  1355,  1379,
+    1402,  1406,  1424,  1432,  1464,  1484,  1572,  1581,  1604,  1607,
+    1613,  1619,  1626,  1635,  1644,  1647,  1650,  1657,  1661,  1668,
+    1672,  1677,  1682,  1688,  1694,  1703,  1713,  1720,  1723,  1726,
+    1732,  1739,  1742,  1748,  1751,  1754,  1760,  1763,  1778,  1782,
+    1786,  1790,  1794,  1798,  1803,  1808,  1813,  1818,  1823,  1828,
+    1833,  1838,  1843,  1848,  1853,  1858,  1864,  1870,  1876,  1882,
+    1888,  1894,  1900,  1906,  1912,  1917,  1922,  1931,  1936,  1941,
+    1946,  1951,  1956,  1961,  1966,  1971,  1976,  1981,  1986,  1991,
+    1996,  2001,  2014,  2014,  2028,  2028,  2037,  2040,  2055,  2087,
+    2091,  2097,  2105,  2121,  2125,  2129,  2130,  2136,  2137,  2138,
+    2139,  2140,  2144,  2145,  2145,  2145,  2155,  2156,  2160,  2160,
+    2161,  2161,  2166,  2169,  2179,  2182,  2188,  2189,  2193,  2201,
+    2205,  2215,  2220,  2237,  2237,  2242,  2242,  2249,  2249,  2257,
+    2260,  2266,  2269,  2275,  2279,  2286,  2293,  2300,  2307,  2318,
+    2327,  2331,  2338,  2341,  2347,  2347
 };
 #endif
 
@@ -2950,6 +2950,7 @@
                 switch((yyvsp[(1) - (2)].interm).op) {
                 case EOpNegative:   errorOp = "-"; break;
                 case EOpLogicalNot: errorOp = "!"; break;
+                case EOpBitwiseNot: errorOp = "~"; break;
                 default: break;
                 }
                 context->unaryOpError((yyvsp[(1) - (2)].interm).line, errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());