Implement ESSL3 modf
This is the first built-in function that has an out parameter, so l-value
checks are added for built-ins.
BUG=angle:918
Change-Id: Ifd5befe955224f706f864e25107879c9cdce9e9f
Reviewed-on: https://chromium-review.googlesource.com/250780
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index e88f7c4..d4f81c7 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -290,6 +290,20 @@
symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float1, float1, float3);
symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float1, float1, float4);
+ TType *outFloat1 = new TType(EbtFloat);
+ TType *outFloat2 = new TType(EbtFloat, 2);
+ TType *outFloat3 = new TType(EbtFloat, 3);
+ TType *outFloat4 = new TType(EbtFloat, 4);
+ outFloat1->setQualifier(EvqOut);
+ outFloat2->setQualifier(EvqOut);
+ outFloat3->setQualifier(EvqOut);
+ outFloat4->setQualifier(EvqOut);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "modf", float1, outFloat1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "modf", float2, outFloat2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "modf", float3, outFloat3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "modf", float4, outFloat4);
+
TType *bool1 = new TType(EbtBool);
TType *bool2 = new TType(EbtBool, 2);
TType *bool3 = new TType(EbtBool, 3);
@@ -905,6 +919,7 @@
symbolTable.relateToOperator(ESSL3_BUILTINS, "abs", EOpAbs);
symbolTable.relateToOperator(ESSL3_BUILTINS, "sign", EOpSign);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "modf", EOpModf);
symbolTable.relateToOperator(ESSL3_BUILTINS, "min", EOpMin);
symbolTable.relateToOperator(ESSL3_BUILTINS, "max", EOpMax);
symbolTable.relateToOperator(ESSL3_BUILTINS, "clamp", EOpClamp);
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index a534ab6..ef78607 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -94,6 +94,7 @@
case EOpCeil: return "ceil";
case EOpFract: return "fract";
case EOpMod: return "mod";
+ case EOpModf: return "modf";
case EOpMin: return "min";
case EOpMax: return "max";
case EOpClamp: return "clamp";
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 282e80f..4884f1c 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -114,6 +114,7 @@
EOpCeil,
EOpFract,
EOpMod,
+ EOpModf,
EOpMin,
EOpMax,
EOpClamp,
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 20fa74e..175edbd 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -864,6 +864,9 @@
case EOpMod:
writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
break;
+ case EOpModf:
+ writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
+ break;
case EOpPow:
writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
break;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 1615762..2a2c97c 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -2139,6 +2139,7 @@
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "mod(");
break;
+ case EOpModf: outputTriplet(visit, "modf(", ", ", ")"); break;
case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
case EOpAtan:
ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index ff57a8f..beac6b7 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -991,6 +991,26 @@
return false;
}
+bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate)
+{
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
+ {
+ TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut)
+ {
+ TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped();
+ if (lValueErrorCheck(node->getLine(), "assign", node))
+ {
+ error(node->getLine(),
+ "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ recover();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool TParseContext::supportsExtension(const char* extension)
{
const TExtensionBehavior& extbehavior = extensionBehavior();
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 35de1b5..2890bd0 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -108,6 +108,7 @@
bool extensionErrorCheck(const TSourceLoc& line, const TString&);
bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier);
bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
+ bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
const TPragma& pragma() const { return directiveHandler.pragma(); }
const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index d21d28b..3d857a1 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -360,6 +360,9 @@
aggregate->setType(fnCandidate->getReturnType());
aggregate->setPrecisionFromChildren();
$$ = aggregate;
+
+ // Some built-in functions have out parameters too.
+ context->functionCallLValueErrorCheck(fnCandidate, aggregate);
}
} else {
// This is a real function call
@@ -380,16 +383,7 @@
$$ = aggregate;
- TQualifier qual;
- for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
- qual = fnCandidate->getParam(i).type->getQualifier();
- if (qual == EvqOut || qual == EvqInOut) {
- if (context->lValueErrorCheck($$->getLine(), "assign", (*($$->getAsAggregate()->getSequence()))[i]->getAsTyped())) {
- context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
- context->recover();
- }
- }
- }
+ context->functionCallLValueErrorCheck(fnCandidate, aggregate);
}
} else {
// error message was put out by PaFindFunction()
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index d1c8d28..711bc52 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -688,32 +688,32 @@
static const yytype_uint16 yyrline[] =
{
0, 205, 205, 206, 209, 233, 236, 241, 246, 251,
- 256, 262, 265, 268, 271, 274, 277, 283, 291, 408,
- 411, 419, 422, 428, 432, 439, 445, 454, 462, 465,
- 475, 478, 481, 484, 494, 495, 496, 497, 505, 506,
- 509, 512, 519, 520, 523, 529, 530, 534, 541, 542,
- 545, 548, 551, 557, 558, 561, 567, 568, 575, 576,
- 583, 584, 591, 592, 598, 599, 605, 606, 612, 613,
- 630, 631, 644, 645, 646, 647, 651, 652, 653, 657,
- 661, 665, 669, 676, 679, 690, 698, 706, 733, 739,
- 750, 754, 758, 762, 769, 825, 828, 835, 843, 864,
- 885, 895, 923, 928, 938, 943, 953, 956, 959, 962,
- 968, 975, 978, 982, 986, 990, 997, 1001, 1005, 1012,
- 1016, 1020, 1027, 1036, 1042, 1045, 1051, 1057, 1064, 1073,
- 1082, 1090, 1093, 1100, 1104, 1111, 1114, 1118, 1122, 1131,
- 1140, 1148, 1158, 1170, 1173, 1176, 1182, 1189, 1192, 1198,
- 1201, 1204, 1210, 1213, 1228, 1232, 1236, 1240, 1244, 1248,
- 1253, 1258, 1263, 1268, 1273, 1278, 1283, 1288, 1293, 1298,
- 1303, 1308, 1313, 1318, 1323, 1328, 1333, 1338, 1343, 1348,
- 1353, 1357, 1361, 1365, 1369, 1373, 1377, 1381, 1385, 1389,
- 1393, 1397, 1401, 1405, 1409, 1413, 1421, 1429, 1433, 1446,
- 1446, 1449, 1449, 1455, 1458, 1474, 1477, 1486, 1490, 1496,
- 1503, 1518, 1522, 1526, 1527, 1533, 1534, 1535, 1536, 1537,
- 1541, 1542, 1542, 1542, 1552, 1553, 1557, 1557, 1558, 1558,
- 1563, 1566, 1576, 1579, 1585, 1586, 1590, 1598, 1602, 1612,
- 1617, 1634, 1634, 1639, 1639, 1646, 1646, 1654, 1657, 1663,
- 1666, 1672, 1676, 1683, 1690, 1697, 1704, 1715, 1724, 1728,
- 1735, 1738, 1744, 1744
+ 256, 262, 265, 268, 271, 274, 277, 283, 291, 402,
+ 405, 413, 416, 422, 426, 433, 439, 448, 456, 459,
+ 469, 472, 475, 478, 488, 489, 490, 491, 499, 500,
+ 503, 506, 513, 514, 517, 523, 524, 528, 535, 536,
+ 539, 542, 545, 551, 552, 555, 561, 562, 569, 570,
+ 577, 578, 585, 586, 592, 593, 599, 600, 606, 607,
+ 624, 625, 638, 639, 640, 641, 645, 646, 647, 651,
+ 655, 659, 663, 670, 673, 684, 692, 700, 727, 733,
+ 744, 748, 752, 756, 763, 819, 822, 829, 837, 858,
+ 879, 889, 917, 922, 932, 937, 947, 950, 953, 956,
+ 962, 969, 972, 976, 980, 984, 991, 995, 999, 1006,
+ 1010, 1014, 1021, 1030, 1036, 1039, 1045, 1051, 1058, 1067,
+ 1076, 1084, 1087, 1094, 1098, 1105, 1108, 1112, 1116, 1125,
+ 1134, 1142, 1152, 1164, 1167, 1170, 1176, 1183, 1186, 1192,
+ 1195, 1198, 1204, 1207, 1222, 1226, 1230, 1234, 1238, 1242,
+ 1247, 1252, 1257, 1262, 1267, 1272, 1277, 1282, 1287, 1292,
+ 1297, 1302, 1307, 1312, 1317, 1322, 1327, 1332, 1337, 1342,
+ 1347, 1351, 1355, 1359, 1363, 1367, 1371, 1375, 1379, 1383,
+ 1387, 1391, 1395, 1399, 1403, 1407, 1415, 1423, 1427, 1440,
+ 1440, 1443, 1443, 1449, 1452, 1468, 1471, 1480, 1484, 1490,
+ 1497, 1512, 1516, 1520, 1521, 1527, 1528, 1529, 1530, 1531,
+ 1535, 1536, 1536, 1536, 1546, 1547, 1551, 1551, 1552, 1552,
+ 1557, 1560, 1570, 1573, 1579, 1580, 1584, 1592, 1596, 1606,
+ 1611, 1628, 1628, 1633, 1633, 1640, 1640, 1648, 1651, 1657,
+ 1660, 1666, 1670, 1677, 1684, 1691, 1698, 1709, 1718, 1722,
+ 1729, 1732, 1738, 1738
};
#endif
@@ -2525,6 +2525,9 @@
aggregate->setType(fnCandidate->getReturnType());
aggregate->setPrecisionFromChildren();
(yyval.interm.intermTypedNode) = aggregate;
+
+ // Some built-in functions have out parameters too.
+ context->functionCallLValueErrorCheck(fnCandidate, aggregate);
}
} else {
// This is a real function call
@@ -2545,16 +2548,7 @@
(yyval.interm.intermTypedNode) = aggregate;
- TQualifier qual;
- for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
- qual = fnCandidate->getParam(i).type->getQualifier();
- if (qual == EvqOut || qual == EvqInOut) {
- if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (*((yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()))[i]->getAsTyped())) {
- context->error((yyvsp[0].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
- context->recover();
- }
- }
- }
+ context->functionCallLValueErrorCheck(fnCandidate, aggregate);
}
} else {
// error message was put out by PaFindFunction()
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index 3fef88d..614cdc4 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -421,6 +421,7 @@
case EOpVectorNotEqual: out << "NotEqual"; break;
case EOpMod: out << "mod"; break;
+ case EOpModf: out << "modf"; break;
case EOpPow: out << "pow"; break;
case EOpAtan: out << "arc tangent"; break;