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