Add support for constant folding of clamp()

Fixes: dEQP-GLES3.functional.shaders.constant_expressions.other.complex*
Bug: b/116598062
Change-Id: Ife2dd2edad17d6ebbd02653f484637672ce6af0a
Reviewed-on: https://swiftshader-review.googlesource.com/20828
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index b795c06..bf731ea 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -3629,24 +3629,48 @@
 
 					callNode = aggregate;
 
-					if(fnCandidate->getParamCount() == 2)
+					if(op == EOpClamp)
 					{
+						// Special case for clamp -- try to fold it as min(max(t, minVal), maxVal)
 						TIntermSequence &parameters = paramNode->getAsAggregate()->getSequence();
-						TIntermTyped *left = parameters[0]->getAsTyped();
-						TIntermTyped *right = parameters[1]->getAsTyped();
+						TIntermConstantUnion *valConstant = parameters[0]->getAsTyped()->getAsConstantUnion();
+						TIntermConstantUnion *minConstant = parameters[1]->getAsTyped()->getAsConstantUnion();
+						TIntermConstantUnion *maxConstant = parameters[2]->getAsTyped()->getAsConstantUnion();
 
-						TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
-						TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
-						if (leftTempConstant && rightTempConstant)
+						if (valConstant && minConstant && maxConstant)
 						{
-							TIntermTyped *typedReturnNode = leftTempConstant->fold(op, rightTempConstant, infoSink());
-
-							if(typedReturnNode)
+							TIntermTyped *typedReturnNode = valConstant->fold(EOpMax, minConstant, infoSink());
+							if (typedReturnNode && typedReturnNode->getAsConstantUnion())
+							{
+								typedReturnNode = maxConstant->fold(EOpMin, typedReturnNode->getAsConstantUnion(), infoSink());
+							}
+							if (typedReturnNode)
 							{
 								callNode = typedReturnNode;
 							}
 						}
 					}
+					else
+					{
+						if(fnCandidate->getParamCount() == 2)
+						{
+							TIntermSequence &parameters = paramNode->getAsAggregate()->getSequence();
+							TIntermTyped *left = parameters[0]->getAsTyped();
+							TIntermTyped *right = parameters[1]->getAsTyped();
+
+							TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+							TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+							if (leftTempConstant && rightTempConstant)
+							{
+								TIntermTyped *typedReturnNode = leftTempConstant->fold(op, rightTempConstant, infoSink());
+
+								if(typedReturnNode)
+								{
+									callNode = typedReturnNode;
+								}
+							}
+						}
+					}
 				}
 			}
 			else