Unsigned int GLSL parsing fixed

Unsigned integers in GLSL were being parsed using the regular
integer parser, so it was limited to INT_MAX. All values from
INT_MAX + 1 to UINT_MAX could not be parsed properly.

Also, added constant folding for the 4 bit conversion glsl
functions.

Fixes shader compilation issue in the Epic Zen Garden example:
https://s3.amazonaws.com/mozilla-games/ZenGarden/EpicZenGarden.html
(unfortunately, the screen is still black, so there are other
 issues left)

Fixes WebGL 2 test: conformance2/glsl3/float-parsing.html

Change-Id: Iae52b2c8e083f0e1a22599e5a583297b9850444d
Reviewed-on: https://swiftshader-review.googlesource.com/16648
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Common/Math.hpp b/src/Common/Math.hpp
index bae3c12..dd2bc9c 100644
--- a/src/Common/Math.hpp
+++ b/src/Common/Math.hpp
@@ -74,6 +74,18 @@
 		b = t;
 	}
 
+	template <typename destType, typename sourceType>
+	destType bitCast(const sourceType &source)
+	{
+		union
+		{
+			sourceType s;
+			destType d;
+		} sd;
+		sd.s = source;
+		return sd.d;
+	}
+
 	inline int iround(float x)
 	{
 		return (int)floor(x + 0.5f);
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index 4293868..fbcb16b 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -1778,10 +1778,12 @@
 		//
 		TIntermConstantUnion *newNode = 0;
 		ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+		TType type = getType();
+		TBasicType basicType = type.getBasicType();
 		for (size_t i = 0; i < objectSize; i++) {
 			switch(op) {
 				case EOpNegative:
-					switch (getType().getBasicType()) {
+					switch (basicType) {
 						case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
 						case EbtInt:   tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
 						default:
@@ -1790,7 +1792,7 @@
 					}
 					break;
 				case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
-					switch (getType().getBasicType()) {
+					switch (basicType) {
 						case EbtBool:  tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
 						default:
 							infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1798,7 +1800,7 @@
 					}
 					break;
 				case EOpBitwiseNot:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 						case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break;
 						case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break;
 						default:
@@ -1807,7 +1809,7 @@
 					}
 					break;
 				case EOpRadians:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 1.74532925e-2f); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1815,7 +1817,7 @@
 					}
 					break;
 				case EOpDegrees:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 5.72957795e+1f); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1823,7 +1825,7 @@
 					}
 					break;
 				case EOpSin:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sinf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1831,7 +1833,7 @@
 					}
 					break;
 				case EOpCos:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(cosf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1839,7 +1841,7 @@
 					}
 					break;
 				case EOpTan:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(tanf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1847,7 +1849,7 @@
 					}
 					break;
 				case EOpAsin:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(asinf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1855,7 +1857,7 @@
 					}
 					break;
 				case EOpAcos:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(acosf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1863,7 +1865,7 @@
 					}
 					break;
 				case EOpAtan:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(atanf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1871,7 +1873,7 @@
 					}
 					break;
 				case EOpSinh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sinhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1879,7 +1881,7 @@
 					}
 					break;
 				case EOpCosh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(coshf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1887,7 +1889,7 @@
 					}
 					break;
 				case EOpTanh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(tanhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1895,7 +1897,7 @@
 					}
 					break;
 				case EOpAsinh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(asinhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1903,7 +1905,7 @@
 					}
 					break;
 				case EOpAcosh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(acoshf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1911,7 +1913,7 @@
 					}
 					break;
 				case EOpAtanh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(atanhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1919,7 +1921,7 @@
 					}
 					break;
 				case EOpLog:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(logf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1927,7 +1929,7 @@
 					}
 					break;
 				case EOpLog2:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sw::log2(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1935,7 +1937,7 @@
 					}
 					break;
 				case EOpExp:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(expf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1943,7 +1945,7 @@
 					}
 					break;
 				case EOpExp2:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(exp2f(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1951,7 +1953,7 @@
 					}
 					break;
 				case EOpSqrt:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sqrtf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1959,18 +1961,63 @@
 					}
 					break;
 				case EOpInverseSqrt:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(1.0f / sqrtf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
 						return 0;
 					}
 					break;
+				case EOpFloatBitsToInt:
+					switch(basicType) {
+					case EbtFloat:
+						tempConstArray[i].setIConst(sw::bitCast<int>(unionArray[i].getFConst()));
+						type.setBasicType(EbtInt);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+					break;
+				case EOpFloatBitsToUint:
+					switch(basicType) {
+					case EbtFloat:
+						tempConstArray[i].setUConst(sw::bitCast<unsigned int>(unionArray[i].getFConst()));
+						type.setBasicType(EbtUInt);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+				case EOpIntBitsToFloat:
+					switch(basicType) {
+					case EbtInt:
+						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getIConst()));
+						type.setBasicType(EbtFloat);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+				case EOpUintBitsToFloat:
+					switch(basicType) {
+					case EbtUInt:
+						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getUConst()));
+						type.setBasicType(EbtFloat);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
 				default:
 					return 0;
 			}
 		}
-		newNode = new TIntermConstantUnion(tempConstArray, getType());
+		newNode = new TIntermConstantUnion(tempConstArray, type);
 		newNode->setLine(getLine());
 		return newNode;
 	}
diff --git a/src/OpenGL/compiler/glslang.l b/src/OpenGL/compiler/glslang.l
index cc40dc2..fdc3977 100644
--- a/src/OpenGL/compiler/glslang.l
+++ b/src/OpenGL/compiler/glslang.l
@@ -492,7 +492,7 @@
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+    if (!atou_clamp(yytext, &(yylval->lex.u)))
         yyextra->warning(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
diff --git a/src/OpenGL/compiler/glslang_lex.cpp b/src/OpenGL/compiler/glslang_lex.cpp
index 55b6ffb..0cf1555 100644
--- a/src/OpenGL/compiler/glslang_lex.cpp
+++ b/src/OpenGL/compiler/glslang_lex.cpp
@@ -3724,7 +3724,7 @@
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+    if (!atou_clamp(yytext, &(yylval->lex.u)))
         yyextra->warning(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
diff --git a/src/OpenGL/compiler/util.cpp b/src/OpenGL/compiler/util.cpp
index 2905c1d..bd9783c 100644
--- a/src/OpenGL/compiler/util.cpp
+++ b/src/OpenGL/compiler/util.cpp
@@ -32,3 +32,11 @@
 		*value = std::numeric_limits<int>::max();
 	return success;
 }
+
+bool atou_clamp(const char *str, unsigned int *value)
+{
+	bool success = pp::numeric_lex_int(str, value);
+	if(!success)
+		*value = std::numeric_limits<unsigned int>::max();
+	return success;
+}
diff --git a/src/OpenGL/compiler/util.h b/src/OpenGL/compiler/util.h
index a5c4842..563407e 100644
--- a/src/OpenGL/compiler/util.h
+++ b/src/OpenGL/compiler/util.h
@@ -21,14 +21,18 @@
 
 // atof_clamp is like atof but
 //   1. it forces C locale, i.e. forcing '.' as decimal point.
-//   2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
+//   2. it sets the value to FLT_MAX if overflow happens.
 // Return false if overflow happens.
 bool atof_clamp(const char *str, float *value);
 
-// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// If overflow happens, value is set to INT_MAX.
 // Return false if overflow happens.
 bool atoi_clamp(const char *str, int *value);
 
+// If overflow happens, value is set to UINT_MAX.
+// Return false if overflow happens.
+bool atou_clamp(const char *str, unsigned int *value);
+
 #ifdef __cplusplus
 } // end extern "C"
 #endif