Commit ffe6edfd by Olli Etuaho

Add basic support for the length() method of arrays

Support expressions where the expression that .length() is called on does not have side effects. Tested with WebGL 2 test sdk/tests/deqp/data/gles3/shaders/arrays.html TEST=WebGL 2 conformance tests BUG=angleproject:972 Change-Id: Ib4f8377a51da61179b6e47fbcf6b4d915e351fbd Reviewed-on: https://chromium-review.googlesource.com/265654Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent a2d53039
...@@ -3138,14 +3138,48 @@ TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, ...@@ -3138,14 +3138,48 @@ TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue,
return intermediate.addBranch(op, returnValue, loc); return intermediate.addBranch(op, returnValue, loc);
} }
TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *paramNode, TIntermNode *thisNode,
const TSourceLoc &loc, bool *fatalError) const TSourceLoc &loc, bool *fatalError)
{ {
*fatalError = false; *fatalError = false;
TOperator op = fnCall->getBuiltInOp(); TOperator op = fnCall->getBuiltInOp();
TIntermTyped *callNode = nullptr; TIntermTyped *callNode = nullptr;
if (op != EOpNull) if (thisNode != nullptr)
{
ConstantUnion *unionArray = new ConstantUnion[1];
unsigned int arraySize = 0;
TIntermTyped *typedThis = thisNode->getAsTyped();
if (fnCall->getName() != "length")
{
error(loc, "invalid method", fnCall->getName().c_str());
recover();
}
else if (paramNode != nullptr)
{
error(loc, "method takes no parameters", "length");
recover();
}
else if (typedThis == nullptr || !typedThis->isArray())
{
error(loc, "length can only be called on arrays", "length");
recover();
}
else
{
arraySize = static_cast<unsigned int>(typedThis->getArraySize());
if (typedThis->hasSideEffects())
{
// This code path can be hit with an expression like this:
// (a = b).length()
// where a and b are both arrays.
UNIMPLEMENTED();
}
}
unionArray->setUConst(arraySize);
callNode = intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), loc);
}
else if (op != EOpNull)
{ {
// //
// Then this should be a constructor. // Then this should be a constructor.
...@@ -3153,12 +3187,12 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN ...@@ -3153,12 +3187,12 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
// Their parameters will be verified algorithmically. // Their parameters will be verified algorithmically.
// //
TType type(EbtVoid, EbpUndefined); // use this to get the type back TType type(EbtVoid, EbpUndefined); // use this to get the type back
if (!constructorErrorCheck(loc, node, *fnCall, op, &type)) if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type))
{ {
// //
// It's a constructor, of type 'type'. // It's a constructor, of type 'type'.
// //
callNode = addConstructor(node, &type, op, fnCall, loc); callNode = addConstructor(paramNode, &type, op, fnCall, loc);
} }
if (callNode == nullptr) if (callNode == nullptr)
...@@ -3197,21 +3231,21 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN ...@@ -3197,21 +3231,21 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
// //
// Treat it like a built-in unary operator. // Treat it like a built-in unary operator.
// //
callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType()); callNode = createUnaryMath(op, paramNode->getAsTyped(), loc, &fnCandidate->getReturnType());
if (callNode == nullptr) if (callNode == nullptr)
{ {
std::stringstream extraInfoStream; std::stringstream extraInfoStream;
extraInfoStream << "built in unary operator function. Type: " extraInfoStream << "built in unary operator function. Type: "
<< static_cast<TIntermTyped*>(node)->getCompleteString(); << static_cast<TIntermTyped*>(paramNode)->getCompleteString();
std::string extraInfo = extraInfoStream.str(); std::string extraInfo = extraInfoStream.str();
error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); error(paramNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
*fatalError = true; *fatalError = true;
return nullptr; return nullptr;
} }
} }
else else
{ {
TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc); TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, op, loc);
aggregate->setType(fnCandidate->getReturnType()); aggregate->setType(fnCandidate->getReturnType());
aggregate->setPrecisionFromChildren(); aggregate->setPrecisionFromChildren();
callNode = aggregate; callNode = aggregate;
...@@ -3224,7 +3258,7 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN ...@@ -3224,7 +3258,7 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
{ {
// This is a real function call // This is a real function call
TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc); TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
aggregate->setType(fnCandidate->getReturnType()); aggregate->setType(fnCandidate->getReturnType());
// this is how we know whether the given function is a builtIn function or a user defined function // this is how we know whether the given function is a builtIn function or a user defined function
......
...@@ -209,7 +209,7 @@ struct TParseContext { ...@@ -209,7 +209,7 @@ struct TParseContext {
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *paramNode, TIntermNode *thisNode,
const TSourceLoc &loc, bool *fatalError); const TSourceLoc &loc, bool *fatalError);
TIntermTyped *addTernarySelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, TIntermTyped *addTernarySelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
......
...@@ -296,7 +296,7 @@ integer_expression ...@@ -296,7 +296,7 @@ integer_expression
function_call function_call
: function_call_or_method { : function_call_or_method {
bool fatalError = false; bool fatalError = false;
$$ = context->addFunctionCallOrMethod($1.function, $1.intermNode, @1, &fatalError); $$ = context->addFunctionCallOrMethod($1.function, $1.nodePair.node1, $1.nodePair.node2, @1, &fatalError);
if (fatalError) if (fatalError)
{ {
YYERROR; YYERROR;
...@@ -307,11 +307,12 @@ function_call ...@@ -307,11 +307,12 @@ function_call
function_call_or_method function_call_or_method
: function_call_generic { : function_call_generic {
$$ = $1; $$ = $1;
$$.nodePair.node2 = nullptr;
} }
| postfix_expression DOT function_call_generic { | postfix_expression DOT function_call_generic {
context->error(@3, "methods are not supported", ""); ES3_ONLY("", @3, "methods");
context->recover();
$$ = $3; $$ = $3;
$$.nodePair.node2 = $1;
} }
; ;
...@@ -327,11 +328,11 @@ function_call_generic ...@@ -327,11 +328,11 @@ function_call_generic
function_call_header_no_parameters function_call_header_no_parameters
: function_call_header VOID_TYPE { : function_call_header VOID_TYPE {
$$.function = $1; $$.function = $1;
$$.intermNode = 0; $$.nodePair.node1 = nullptr;
} }
| function_call_header { | function_call_header {
$$.function = $1; $$.function = $1;
$$.intermNode = 0; $$.nodePair.node1 = nullptr;
} }
; ;
...@@ -340,13 +341,13 @@ function_call_header_with_parameters ...@@ -340,13 +341,13 @@ function_call_header_with_parameters
TParameter param = { 0, new TType($2->getType()) }; TParameter param = { 0, new TType($2->getType()) };
$1->addParameter(param); $1->addParameter(param);
$$.function = $1; $$.function = $1;
$$.intermNode = $2; $$.nodePair.node1 = $2;
} }
| function_call_header_with_parameters COMMA assignment_expression { | function_call_header_with_parameters COMMA assignment_expression {
TParameter param = { 0, new TType($3->getType()) }; TParameter param = { 0, new TType($3->getType()) };
$1.function->addParameter(param); $1.function->addParameter(param);
$$.function = $1.function; $$.function = $1.function;
$$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2); $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2);
} }
; ;
......
...@@ -693,32 +693,32 @@ static const yytype_uint16 yyrline[] = ...@@ -693,32 +693,32 @@ static const yytype_uint16 yyrline[] =
{ {
0, 211, 211, 212, 215, 239, 242, 247, 252, 257, 0, 211, 211, 212, 215, 239, 242, 247, 252, 257,
262, 268, 271, 274, 277, 280, 283, 289, 297, 308, 262, 268, 271, 274, 277, 280, 283, 289, 297, 308,
311, 319, 322, 328, 332, 339, 345, 354, 362, 368, 312, 320, 323, 329, 333, 340, 346, 355, 363, 369,
375, 385, 388, 391, 394, 404, 405, 406, 407, 415, 376, 386, 389, 392, 395, 405, 406, 407, 408, 416,
416, 419, 422, 429, 430, 433, 439, 440, 444, 451, 417, 420, 423, 430, 431, 434, 440, 441, 445, 452,
452, 455, 458, 461, 467, 468, 471, 477, 478, 485, 453, 456, 459, 462, 468, 469, 472, 478, 479, 486,
486, 493, 494, 501, 502, 508, 509, 515, 516, 522, 487, 494, 495, 502, 503, 509, 510, 516, 517, 523,
523, 529, 530, 538, 539, 540, 541, 545, 546, 547, 524, 530, 531, 539, 540, 541, 542, 546, 547, 548,
551, 555, 559, 563, 570, 573, 584, 592, 600, 628, 552, 556, 560, 564, 571, 574, 585, 593, 601, 629,
634, 645, 649, 653, 657, 664, 720, 723, 730, 738, 635, 646, 650, 654, 658, 665, 721, 724, 731, 739,
759, 780, 790, 818, 823, 833, 838, 848, 851, 854, 760, 781, 791, 819, 824, 834, 839, 849, 852, 855,
857, 863, 870, 873, 877, 881, 886, 891, 898, 902, 858, 864, 871, 874, 878, 882, 887, 892, 899, 903,
906, 910, 915, 920, 924, 931, 941, 947, 950, 956, 907, 911, 916, 921, 925, 932, 942, 948, 951, 957,
962, 969, 978, 987, 995, 998, 1005, 1009, 1016, 1019, 963, 970, 979, 988, 996, 999, 1006, 1010, 1017, 1020,
1023, 1027, 1036, 1045, 1053, 1063, 1075, 1078, 1081, 1087, 1024, 1028, 1037, 1046, 1054, 1064, 1076, 1079, 1082, 1088,
1094, 1097, 1103, 1106, 1109, 1115, 1118, 1123, 1138, 1142, 1095, 1098, 1104, 1107, 1110, 1116, 1119, 1124, 1139, 1143,
1146, 1150, 1154, 1158, 1163, 1168, 1173, 1178, 1183, 1188, 1147, 1151, 1155, 1159, 1164, 1169, 1174, 1179, 1184, 1189,
1193, 1198, 1203, 1208, 1213, 1218, 1223, 1228, 1233, 1238, 1194, 1199, 1204, 1209, 1214, 1219, 1224, 1229, 1234, 1239,
1243, 1248, 1253, 1258, 1263, 1267, 1271, 1275, 1279, 1283, 1244, 1249, 1254, 1259, 1264, 1268, 1272, 1276, 1280, 1284,
1287, 1291, 1295, 1299, 1303, 1307, 1311, 1315, 1319, 1323, 1288, 1292, 1296, 1300, 1304, 1308, 1312, 1316, 1320, 1324,
1331, 1339, 1343, 1356, 1356, 1359, 1359, 1365, 1368, 1384, 1332, 1340, 1344, 1357, 1357, 1360, 1360, 1366, 1369, 1385,
1387, 1396, 1400, 1406, 1413, 1428, 1432, 1436, 1437, 1443, 1388, 1397, 1401, 1407, 1414, 1429, 1433, 1437, 1438, 1444,
1444, 1445, 1446, 1447, 1448, 1449, 1453, 1454, 1454, 1454, 1445, 1446, 1447, 1448, 1449, 1450, 1454, 1455, 1455, 1455,
1464, 1465, 1469, 1469, 1470, 1470, 1475, 1478, 1488, 1491, 1465, 1466, 1470, 1470, 1471, 1471, 1476, 1479, 1489, 1492,
1497, 1498, 1502, 1510, 1514, 1521, 1521, 1528, 1531, 1538, 1498, 1499, 1503, 1511, 1515, 1522, 1522, 1529, 1532, 1539,
1543, 1558, 1558, 1563, 1563, 1570, 1570, 1578, 1581, 1587, 1544, 1559, 1559, 1564, 1564, 1571, 1571, 1579, 1582, 1588,
1590, 1596, 1600, 1607, 1610, 1613, 1616, 1619, 1628, 1632, 1591, 1597, 1601, 1608, 1611, 1614, 1617, 1620, 1629, 1633,
1639, 1642, 1648, 1648 1640, 1643, 1649, 1649
}; };
#endif #endif
...@@ -2495,7 +2495,7 @@ yyreduce: ...@@ -2495,7 +2495,7 @@ yyreduce:
{ {
bool fatalError = false; bool fatalError = false;
(yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).intermNode, (yylsp[0]), &fatalError); (yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).nodePair.node1, (yyvsp[0].interm).nodePair.node2, (yylsp[0]), &fatalError);
if (fatalError) if (fatalError)
{ {
YYERROR; YYERROR;
...@@ -2508,6 +2508,7 @@ yyreduce: ...@@ -2508,6 +2508,7 @@ yyreduce:
{ {
(yyval.interm) = (yyvsp[0].interm); (yyval.interm) = (yyvsp[0].interm);
(yyval.interm).nodePair.node2 = nullptr;
} }
break; break;
...@@ -2515,9 +2516,9 @@ yyreduce: ...@@ -2515,9 +2516,9 @@ yyreduce:
case 20: case 20:
{ {
context->error((yylsp[0]), "methods are not supported", ""); ES3_ONLY("", (yylsp[0]), "methods");
context->recover();
(yyval.interm) = (yyvsp[0].interm); (yyval.interm) = (yyvsp[0].interm);
(yyval.interm).nodePair.node2 = (yyvsp[-2].interm.intermTypedNode);
} }
break; break;
...@@ -2542,7 +2543,7 @@ yyreduce: ...@@ -2542,7 +2543,7 @@ yyreduce:
{ {
(yyval.interm).function = (yyvsp[-1].interm.function); (yyval.interm).function = (yyvsp[-1].interm.function);
(yyval.interm).intermNode = 0; (yyval.interm).nodePair.node1 = nullptr;
} }
break; break;
...@@ -2551,7 +2552,7 @@ yyreduce: ...@@ -2551,7 +2552,7 @@ yyreduce:
{ {
(yyval.interm).function = (yyvsp[0].interm.function); (yyval.interm).function = (yyvsp[0].interm.function);
(yyval.interm).intermNode = 0; (yyval.interm).nodePair.node1 = nullptr;
} }
break; break;
...@@ -2562,7 +2563,7 @@ yyreduce: ...@@ -2562,7 +2563,7 @@ yyreduce:
TParameter param = { 0, new TType((yyvsp[0].interm.intermTypedNode)->getType()) }; TParameter param = { 0, new TType((yyvsp[0].interm.intermTypedNode)->getType()) };
(yyvsp[-1].interm.function)->addParameter(param); (yyvsp[-1].interm.function)->addParameter(param);
(yyval.interm).function = (yyvsp[-1].interm.function); (yyval.interm).function = (yyvsp[-1].interm.function);
(yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); (yyval.interm).nodePair.node1 = (yyvsp[0].interm.intermTypedNode);
} }
break; break;
...@@ -2573,7 +2574,7 @@ yyreduce: ...@@ -2573,7 +2574,7 @@ yyreduce:
TParameter param = { 0, new TType((yyvsp[0].interm.intermTypedNode)->getType()) }; TParameter param = { 0, new TType((yyvsp[0].interm.intermTypedNode)->getType()) };
(yyvsp[-2].interm).function->addParameter(param); (yyvsp[-2].interm).function->addParameter(param);
(yyval.interm).function = (yyvsp[-2].interm).function; (yyval.interm).function = (yyvsp[-2].interm).function;
(yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); (yyval.interm).nodePair.node1 = context->intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
} }
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment