Fix parsing GLSL loop conditions that declare a variable
Now the variable declaration is included in the AST, so that the loop
body may refer to the variable. The variable declaration is placed in
a block that wraps the loop. This way we can still only have
TIntermTyped loop conditions in the AST, which keeps the code dealing
with loops fairly simple and type safe.
This change includes reversing the return value of executeInitializer,
so that it returns true on success and false on error. This is more in
line with other ParseContext member functions.
BUG=angleproject:2073
TEST=angle_end2end_tests
Change-Id: I5c4ecbf1b438d3fff6d6237c0dcf191e2a19664c
Reviewed-on: https://chromium-review.googlesource.com/539639
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/Intermediate.cpp b/src/compiler/translator/Intermediate.cpp
index dae539e..c607ecb 100644
--- a/src/compiler/translator/Intermediate.cpp
+++ b/src/compiler/translator/Intermediate.cpp
@@ -226,22 +226,6 @@
}
//
-// Create loop nodes.
-//
-TIntermNode *TIntermediate::addLoop(TLoopType type,
- TIntermNode *init,
- TIntermTyped *cond,
- TIntermTyped *expr,
- TIntermNode *body,
- const TSourceLoc &line)
-{
- TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
- node->setLine(line);
-
- return node;
-}
-
-//
// Add branches.
//
TIntermBranch *TIntermediate::addBranch(TOperator branchOp, const TSourceLoc &line)
diff --git a/src/compiler/translator/Intermediate.h b/src/compiler/translator/Intermediate.h
index eb1d1d0..f996d76 100644
--- a/src/compiler/translator/Intermediate.h
+++ b/src/compiler/translator/Intermediate.h
@@ -50,12 +50,7 @@
TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
const TType &type,
const TSourceLoc &line);
- TIntermNode *addLoop(TLoopType,
- TIntermNode *,
- TIntermTyped *,
- TIntermTyped *,
- TIntermNode *,
- const TSourceLoc &);
+
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression,
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index f3bd179..73994f6 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1673,12 +1673,10 @@
}
}
-//
// 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
-//
+// Returns true on success.
bool TParseContext::executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
@@ -1706,7 +1704,7 @@
}
if (!declareVariable(line, identifier, type, &variable))
{
- return true;
+ return false;
}
bool globalInitWarning = false;
@@ -1716,7 +1714,7 @@
// Error message does not completely match behavior with ESSL 1.00, but
// we want to steer developers towards only using constant expressions.
error(line, "global variable initializers must be constant expressions", "=");
- return true;
+ return false;
}
if (globalInitWarning)
{
@@ -1735,7 +1733,7 @@
{
error(line, " cannot initialize this type of qualifier ",
variable->getType().getQualifierString());
- return true;
+ return false;
}
//
// test for and propagate constant
@@ -1751,14 +1749,14 @@
std::string reason = reasonStream.str();
error(line, reason.c_str(), "=");
variable->getType().setQualifier(EvqTemporary);
- return true;
+ return false;
}
if (type != initializer->getType())
{
error(line, " non-matching types for const initializer ",
variable->getType().getQualifierString());
variable->getType().setQualifier(EvqTemporary);
- return true;
+ return false;
}
// Save the constant folded value to the variable if possible. For example array
@@ -1769,8 +1767,8 @@
if (initializer->getAsConstantUnion())
{
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
- *initNode = nullptr;
- return false;
+ ASSERT(*initNode == nullptr);
+ return true;
}
else if (initializer->getAsSymbolNode())
{
@@ -1782,8 +1780,8 @@
if (constArray)
{
variable->shareConstPointer(constArray);
- *initNode = nullptr;
- return false;
+ ASSERT(*initNode == nullptr);
+ return true;
}
}
}
@@ -1794,10 +1792,80 @@
if (*initNode == nullptr)
{
assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
- return true;
+ return false;
}
- return false;
+ return true;
+}
+
+TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType,
+ const TString &identifier,
+ TIntermTyped *initializer,
+ const TSourceLoc &loc)
+{
+ checkIsScalarBool(loc, pType);
+ TIntermBinary *initNode = nullptr;
+ if (executeInitializer(loc, identifier, pType, initializer, &initNode))
+ {
+ // The initializer is valid. The init condition needs to have a node - either the
+ // initializer node, or a constant node in case the initialized variable is const and won't
+ // be recorded in the AST.
+ if (initNode == nullptr)
+ {
+ return initializer;
+ }
+ else
+ {
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->appendDeclarator(initNode);
+ return declaration;
+ }
+ }
+ return nullptr;
+}
+
+TIntermNode *TParseContext::addLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermNode *cond,
+ TIntermTyped *expr,
+ TIntermNode *body,
+ const TSourceLoc &line)
+{
+ TIntermNode *node = nullptr;
+ TIntermTyped *typedCond = nullptr;
+ if (cond)
+ {
+ typedCond = cond->getAsTyped();
+ }
+ if (cond == nullptr || typedCond)
+ {
+ node = new TIntermLoop(type, init, typedCond, expr, TIntermediate::EnsureBlock(body));
+ node->setLine(line);
+ return node;
+ }
+
+ TIntermDeclaration *declaration = cond->getAsDeclarationNode();
+ ASSERT(declaration);
+ TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode();
+ ASSERT(declarator->getLeft()->getAsSymbolNode());
+
+ // The condition is a declaration. In the AST representation we don't support declarations as
+ // loop conditions. Wrap the loop to a block that declares the condition variable and contains
+ // the loop.
+ TIntermBlock *block = new TIntermBlock();
+
+ TIntermDeclaration *declareCondition = new TIntermDeclaration();
+ declareCondition->appendDeclarator(declarator->getLeft()->deepCopy());
+ block->appendStatement(declareCondition);
+
+ TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(),
+ declarator->getRight()->deepCopy());
+ TIntermLoop *loop =
+ new TIntermLoop(type, init, conditionInit, expr, TIntermediate::EnsureBlock(body));
+ block->appendStatement(loop);
+ loop->setLine(line);
+ block->setLine(line);
+ return block;
}
void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
@@ -2171,7 +2239,7 @@
declaration->setLine(identifierLocation);
TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
+ if (executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
{
if (initNode)
{
@@ -2217,7 +2285,7 @@
// initNode will correspond to the whole of "type b[n] = initializer".
TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
if (initNode)
{
@@ -2376,7 +2444,7 @@
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
+ if (executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
{
//
// build the intermediate representation
@@ -2424,7 +2492,7 @@
// initNode will correspond to the whole of "b[n] = initializer".
TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
if (initNode)
{
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 626f335..d0d7ed5 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -175,11 +175,23 @@
const char *value,
bool stdgl);
+ // Returns true on success. *initNode may still be nullptr on success in case the initialization
+ // is not needed in the AST.
bool executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
TIntermTyped *initializer,
TIntermBinary **initNode);
+ TIntermNode *addConditionInitializer(const TPublicType &pType,
+ const TString &identifier,
+ TIntermTyped *initializer,
+ const TSourceLoc &loc);
+ TIntermNode *addLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermNode *cond,
+ TIntermTyped *expr,
+ TIntermNode *body,
+ const TSourceLoc &loc);
void addFullySpecifiedType(TPublicType *typeSpecifier);
TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 03784dc..4be7673 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -212,8 +212,9 @@
%type <interm.intermTypedNode> conditional_expression constant_expression
%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
-%type <interm.intermTypedNode> function_call initializer condition conditionopt
+%type <interm.intermTypedNode> function_call initializer
+%type <interm.intermNode> condition conditionopt
%type <interm.intermBlock> translation_unit
%type <interm.intermNode> function_definition statement simple_statement
%type <interm.intermBlock> statement_list compound_statement compound_statement_no_new_scope
@@ -1451,32 +1452,25 @@
context->checkIsScalarBool($1->getLine(), $1);
}
| fully_specified_type identifier EQUAL initializer {
- TIntermBinary *initNode = nullptr;
- context->checkIsScalarBool(@2, $1);
-
- if (!context->executeInitializer(@2, *$2.string, $1, $4, &initNode))
- $$ = $4;
- else {
- $$ = 0;
- }
+ $$ = context->addConditionInitializer($1, *$2.string, $4, @2);
}
;
iteration_statement
: WHILE LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } condition RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
- $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
+ $$ = context->addLoop(ELoopWhile, 0, $4, 0, $6, @1);
context->decrLoopNestingLevel();
}
| DO { context->incrLoopNestingLevel(); } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
context->checkIsScalarBool(@8, $6);
- $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
+ $$ = context->addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
context->decrLoopNestingLevel();
}
| FOR LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
- $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
+ $$ = context->addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
context->decrLoopNestingLevel();
}
;
@@ -1495,7 +1489,7 @@
$$ = $1;
}
| /* May be null */ {
- $$ = 0;
+ $$ = nullptr;
}
;
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 7c6da64..1eef14c 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -752,36 +752,36 @@
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 255, 255, 256, 259, 269, 272, 277, 282, 287,
- 292, 300, 306, 309, 312, 315, 318, 321, 327, 334,
- 340, 344, 352, 355, 361, 365, 372, 377, 384, 392,
- 398, 404, 413, 416, 419, 422, 432, 433, 434, 435,
- 443, 444, 447, 450, 457, 458, 461, 467, 468, 472,
- 479, 480, 483, 486, 489, 495, 496, 499, 505, 506,
- 513, 514, 521, 522, 529, 530, 536, 537, 543, 544,
- 550, 551, 557, 558, 565, 566, 567, 568, 572, 573,
- 574, 578, 582, 586, 590, 597, 600, 606, 613, 620,
- 623, 626, 635, 639, 643, 647, 651, 658, 665, 668,
- 675, 683, 703, 713, 721, 746, 750, 754, 758, 765,
- 772, 775, 779, 783, 788, 793, 800, 804, 808, 812,
- 817, 822, 829, 833, 839, 842, 848, 852, 859, 865,
- 869, 873, 876, 879, 888, 894, 902, 905, 925, 944,
- 951, 955, 959, 962, 965, 968, 971, 974, 982, 989,
- 992, 995, 1001, 1008, 1011, 1017, 1020, 1023, 1026, 1032,
- 1035, 1040, 1051, 1054, 1057, 1060, 1063, 1066, 1070, 1074,
- 1078, 1082, 1086, 1090, 1094, 1098, 1102, 1106, 1110, 1114,
- 1118, 1122, 1126, 1130, 1134, 1138, 1142, 1146, 1150, 1156,
- 1159, 1162, 1165, 1168, 1171, 1174, 1177, 1180, 1183, 1186,
- 1189, 1192, 1195, 1198, 1201, 1204, 1207, 1210, 1217, 1223,
- 1229, 1232, 1235, 1238, 1241, 1244, 1247, 1250, 1253, 1256,
- 1259, 1262, 1265, 1268, 1271, 1283, 1283, 1286, 1286, 1292,
- 1295, 1301, 1304, 1311, 1315, 1321, 1327, 1339, 1343, 1347,
- 1348, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1364, 1365,
- 1365, 1365, 1374, 1375, 1379, 1379, 1380, 1380, 1385, 1388,
- 1397, 1402, 1409, 1410, 1414, 1421, 1425, 1432, 1432, 1439,
- 1442, 1449, 1453, 1466, 1466, 1471, 1471, 1477, 1477, 1485,
- 1488, 1494, 1497, 1503, 1507, 1514, 1517, 1520, 1523, 1526,
- 1535, 1541, 1547, 1550, 1556, 1556
+ 0, 256, 256, 257, 260, 270, 273, 278, 283, 288,
+ 293, 301, 307, 310, 313, 316, 319, 322, 328, 335,
+ 341, 345, 353, 356, 362, 366, 373, 378, 385, 393,
+ 399, 405, 414, 417, 420, 423, 433, 434, 435, 436,
+ 444, 445, 448, 451, 458, 459, 462, 468, 469, 473,
+ 480, 481, 484, 487, 490, 496, 497, 500, 506, 507,
+ 514, 515, 522, 523, 530, 531, 537, 538, 544, 545,
+ 551, 552, 558, 559, 566, 567, 568, 569, 573, 574,
+ 575, 579, 583, 587, 591, 598, 601, 607, 614, 621,
+ 624, 627, 636, 640, 644, 648, 652, 659, 666, 669,
+ 676, 684, 704, 714, 722, 747, 751, 755, 759, 766,
+ 773, 776, 780, 784, 789, 794, 801, 805, 809, 813,
+ 818, 823, 830, 834, 840, 843, 849, 853, 860, 866,
+ 870, 874, 877, 880, 889, 895, 903, 906, 926, 945,
+ 952, 956, 960, 963, 966, 969, 972, 975, 983, 990,
+ 993, 996, 1002, 1009, 1012, 1018, 1021, 1024, 1027, 1033,
+ 1036, 1041, 1052, 1055, 1058, 1061, 1064, 1067, 1071, 1075,
+ 1079, 1083, 1087, 1091, 1095, 1099, 1103, 1107, 1111, 1115,
+ 1119, 1123, 1127, 1131, 1135, 1139, 1143, 1147, 1151, 1157,
+ 1160, 1163, 1166, 1169, 1172, 1175, 1178, 1181, 1184, 1187,
+ 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1211, 1218, 1224,
+ 1230, 1233, 1236, 1239, 1242, 1245, 1248, 1251, 1254, 1257,
+ 1260, 1263, 1266, 1269, 1272, 1284, 1284, 1287, 1287, 1293,
+ 1296, 1302, 1305, 1312, 1316, 1322, 1328, 1340, 1344, 1348,
+ 1349, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1365, 1366,
+ 1366, 1366, 1375, 1376, 1380, 1380, 1381, 1381, 1386, 1389,
+ 1398, 1403, 1410, 1411, 1415, 1422, 1426, 1433, 1433, 1440,
+ 1443, 1450, 1454, 1460, 1460, 1465, 1465, 1471, 1471, 1479,
+ 1482, 1488, 1491, 1497, 1501, 1508, 1511, 1514, 1517, 1520,
+ 1529, 1535, 1541, 1544, 1550, 1550
};
#endif
@@ -4828,7 +4828,7 @@
case 271:
{
- (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermTypedNode);
context->checkIsScalarBool((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode));
}
@@ -4837,14 +4837,7 @@
case 272:
{
- TIntermBinary *initNode = nullptr;
- context->checkIsScalarBool((yylsp[-2]), (yyvsp[-3].interm.type));
-
- if (!context->executeInitializer((yylsp[-2]), *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), (yyvsp[0].interm.intermTypedNode), &initNode))
- (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
- else {
- (yyval.interm.intermTypedNode) = 0;
- }
+ (yyval.interm.intermNode) = context->addConditionInitializer((yyvsp[-3].interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode), (yylsp[-2]));
}
break;
@@ -4859,7 +4852,7 @@
{
context->symbolTable.pop();
- (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
+ (yyval.interm.intermNode) = context->addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
context->decrLoopNestingLevel();
}
@@ -4876,7 +4869,7 @@
{
context->checkIsScalarBool((yylsp[0]), (yyvsp[-2].interm.intermTypedNode));
- (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
+ (yyval.interm.intermNode) = context->addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
context->decrLoopNestingLevel();
}
@@ -4892,7 +4885,7 @@
{
context->symbolTable.pop();
- (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
+ (yyval.interm.intermNode) = context->addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
context->decrLoopNestingLevel();
}
@@ -4917,7 +4910,7 @@
case 281:
{
- (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
}
break;
@@ -4925,7 +4918,7 @@
case 282:
{
- (yyval.interm.intermTypedNode) = 0;
+ (yyval.interm.intermNode) = nullptr;
}
break;
@@ -4933,7 +4926,7 @@
case 283:
{
- (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode);
+ (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermNode);
(yyval.interm.nodePair).node2 = 0;
}
@@ -4942,7 +4935,7 @@
case 284:
{
- (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode);
+ (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode);
(yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode);
}
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index da72e38..f608a67 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -3080,6 +3080,36 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that a loop condition that has an initializer declares a variable.
+TEST_P(GLSLTest_ES3, ConditionInitializerDeclaresVariable)
+{
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " float i = 0.0;\n"
+ " while (bool foo = (i < 1.5))\n"
+ " {\n"
+ " if (!foo)\n"
+ " {\n"
+ " ++i;\n"
+ " }\n"
+ " if (i > 3.5)\n"
+ " {\n"
+ " break;\n"
+ " }\n"
+ " ++i;\n"
+ " }\n"
+ " my_FragColor = vec4(i * 0.5 - 1.0, i * 0.5, 0.0, 1.0);\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
+ drawQuad(program.get(), "inputAttribute", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(),