OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/simplified-lowering.h" | 5 #include "src/compiler/simplified-lowering.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/address-map.h" | 9 #include "src/address-map.h" |
10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
(...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 void ChangeToInt32OverflowOp(Node* node) { | 1068 void ChangeToInt32OverflowOp(Node* node) { |
1069 NodeProperties::ChangeOp(node, Int32OverflowOp(node)); | 1069 NodeProperties::ChangeOp(node, Int32OverflowOp(node)); |
1070 } | 1070 } |
1071 | 1071 |
1072 void ChangeToUint32OverflowOp(Node* node) { | 1072 void ChangeToUint32OverflowOp(Node* node) { |
1073 NodeProperties::ChangeOp(node, Uint32OverflowOp(node)); | 1073 NodeProperties::ChangeOp(node, Uint32OverflowOp(node)); |
1074 } | 1074 } |
1075 | 1075 |
1076 void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation, | 1076 void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation, |
1077 SimplifiedLowering* lowering) { | 1077 SimplifiedLowering* lowering) { |
1078 if (truncation.IsUnused()) return VisitUnused(node); | 1078 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can |
| 1079 // only eliminate an unused speculative number operation if we know that |
| 1080 // the inputs are PlainPrimitive, which excludes everything that's might |
| 1081 // have side effects or throws during a ToNumber conversion. |
| 1082 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1083 if (truncation.IsUnused()) return VisitUnused(node); |
| 1084 } |
1079 if (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) && | 1085 if (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) && |
1080 NodeProperties::GetType(node)->Is(Type::Signed32())) { | 1086 NodeProperties::GetType(node)->Is(Type::Signed32())) { |
1081 // int32 + int32 = int32 ==> signed Int32Add/Sub | 1087 // int32 + int32 = int32 ==> signed Int32Add/Sub |
1082 VisitInt32Binop(node); | 1088 VisitInt32Binop(node); |
1083 if (lower()) ChangeToPureOp(node, Int32Op(node)); | 1089 if (lower()) ChangeToPureOp(node, Int32Op(node)); |
1084 return; | 1090 return; |
1085 } | 1091 } |
1086 | 1092 |
1087 // Use truncation if available. | 1093 // Use truncation if available. |
1088 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) && | 1094 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) && |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1129 return; | 1135 return; |
1130 } | 1136 } |
1131 | 1137 |
1132 // Dispatching routine for visiting the node {node} with the usage {use}. | 1138 // Dispatching routine for visiting the node {node} with the usage {use}. |
1133 // Depending on the operator, propagate new usage info to the inputs. | 1139 // Depending on the operator, propagate new usage info to the inputs. |
1134 void VisitNode(Node* node, Truncation truncation, | 1140 void VisitNode(Node* node, Truncation truncation, |
1135 SimplifiedLowering* lowering) { | 1141 SimplifiedLowering* lowering) { |
1136 // Unconditionally eliminate unused pure nodes (only relevant if there's | 1142 // Unconditionally eliminate unused pure nodes (only relevant if there's |
1137 // a pure operation in between two effectful ones, where the last one | 1143 // a pure operation in between two effectful ones, where the last one |
1138 // is unused). | 1144 // is unused). |
1139 if (node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) { | 1145 // Note: We must not do this for constants, as they are cached and we |
1140 return VisitUnused(node); | 1146 // would thus kill the cached {node} during lowering (i.e. replace all |
| 1147 // uses with Dead), but at that point some node lowering might have |
| 1148 // already taken the constant {node} from the cache (while it was in |
| 1149 // a sane state still) and we would afterwards replace that use with |
| 1150 // Dead as well. |
| 1151 if (node->op()->ValueInputCount() > 0 && |
| 1152 node->op()->HasProperty(Operator::kPure)) { |
| 1153 if (truncation.IsUnused()) return VisitUnused(node); |
1141 } | 1154 } |
1142 switch (node->opcode()) { | 1155 switch (node->opcode()) { |
1143 //------------------------------------------------------------------ | 1156 //------------------------------------------------------------------ |
1144 // Common operators. | 1157 // Common operators. |
1145 //------------------------------------------------------------------ | 1158 //------------------------------------------------------------------ |
1146 case IrOpcode::kStart: | 1159 case IrOpcode::kStart: |
1147 // We use Start as a terminator for the frame state chain, so even | 1160 // We use Start as a terminator for the frame state chain, so even |
1148 // tho Start doesn't really produce a value, we have to say Tagged | 1161 // tho Start doesn't really produce a value, we have to say Tagged |
1149 // here, otherwise the input conversion will fail. | 1162 // here, otherwise the input conversion will fail. |
1150 return VisitLeaf(node, MachineRepresentation::kTagged); | 1163 return VisitLeaf(node, MachineRepresentation::kTagged); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1254 return; | 1267 return; |
1255 } | 1268 } |
1256 | 1269 |
1257 case IrOpcode::kSpeculativeNumberAdd: | 1270 case IrOpcode::kSpeculativeNumberAdd: |
1258 case IrOpcode::kSpeculativeNumberSubtract: | 1271 case IrOpcode::kSpeculativeNumberSubtract: |
1259 return VisitSpeculativeAdditiveOp(node, truncation, lowering); | 1272 return VisitSpeculativeAdditiveOp(node, truncation, lowering); |
1260 | 1273 |
1261 case IrOpcode::kSpeculativeNumberLessThan: | 1274 case IrOpcode::kSpeculativeNumberLessThan: |
1262 case IrOpcode::kSpeculativeNumberLessThanOrEqual: | 1275 case IrOpcode::kSpeculativeNumberLessThanOrEqual: |
1263 case IrOpcode::kSpeculativeNumberEqual: { | 1276 case IrOpcode::kSpeculativeNumberEqual: { |
1264 if (truncation.IsUnused()) return VisitUnused(node); | 1277 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we |
| 1278 // can only eliminate an unused speculative number operation if we know |
| 1279 // that the inputs are PlainPrimitive, which excludes everything that's |
| 1280 // might have side effects or throws during a ToNumber conversion. |
| 1281 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1282 if (truncation.IsUnused()) return VisitUnused(node); |
| 1283 } |
1265 // Number comparisons reduce to integer comparisons for integer inputs. | 1284 // Number comparisons reduce to integer comparisons for integer inputs. |
1266 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) && | 1285 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) && |
1267 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) { | 1286 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) { |
1268 // => unsigned Int32Cmp | 1287 // => unsigned Int32Cmp |
1269 VisitUint32Cmp(node); | 1288 VisitUint32Cmp(node); |
1270 if (lower()) ChangeToPureOp(node, Uint32Op(node)); | 1289 if (lower()) ChangeToPureOp(node, Uint32Op(node)); |
1271 return; | 1290 return; |
1272 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) && | 1291 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) && |
1273 TypeOf(node->InputAt(1))->Is(Type::Signed32())) { | 1292 TypeOf(node->InputAt(1))->Is(Type::Signed32())) { |
1274 // => signed Int32Cmp | 1293 // => signed Int32Cmp |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1309 VisitWord32TruncatingBinop(node); | 1328 VisitWord32TruncatingBinop(node); |
1310 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); | 1329 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); |
1311 } else { | 1330 } else { |
1312 // => Float64Add/Sub | 1331 // => Float64Add/Sub |
1313 VisitFloat64Binop(node); | 1332 VisitFloat64Binop(node); |
1314 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 1333 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
1315 } | 1334 } |
1316 return; | 1335 return; |
1317 } | 1336 } |
1318 case IrOpcode::kSpeculativeNumberMultiply: { | 1337 case IrOpcode::kSpeculativeNumberMultiply: { |
1319 if (truncation.IsUnused()) return VisitUnused(node); | 1338 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we |
| 1339 // can only eliminate an unused speculative number operation if we know |
| 1340 // that the inputs are PlainPrimitive, which excludes everything that's |
| 1341 // might have side effects or throws during a ToNumber conversion. |
| 1342 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1343 if (truncation.IsUnused()) return VisitUnused(node); |
| 1344 } |
1320 if (BothInputsAre(node, Type::Integral32()) && | 1345 if (BothInputsAre(node, Type::Integral32()) && |
1321 (NodeProperties::GetType(node)->Is(Type::Signed32()) || | 1346 (NodeProperties::GetType(node)->Is(Type::Signed32()) || |
1322 NodeProperties::GetType(node)->Is(Type::Unsigned32()) || | 1347 NodeProperties::GetType(node)->Is(Type::Unsigned32()) || |
1323 (truncation.IsUsedAsWord32() && | 1348 (truncation.IsUsedAsWord32() && |
1324 NodeProperties::GetType(node)->Is( | 1349 NodeProperties::GetType(node)->Is( |
1325 type_cache_.kSafeIntegerOrMinusZero)))) { | 1350 type_cache_.kSafeIntegerOrMinusZero)))) { |
1326 // Multiply reduces to Int32Mul if the inputs are integers, and | 1351 // Multiply reduces to Int32Mul if the inputs are integers, and |
1327 // (a) the output is either known to be Signed32, or | 1352 // (a) the output is either known to be Signed32, or |
1328 // (b) the output is known to be Unsigned32, or | 1353 // (b) the output is known to be Unsigned32, or |
1329 // (c) the uses are truncating and the result is in the safe | 1354 // (c) the uses are truncating and the result is in the safe |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 VisitWord32TruncatingBinop(node); | 1409 VisitWord32TruncatingBinop(node); |
1385 if (lower()) ChangeToPureOp(node, Int32Op(node)); | 1410 if (lower()) ChangeToPureOp(node, Int32Op(node)); |
1386 return; | 1411 return; |
1387 } | 1412 } |
1388 // Number x Number => Float64Mul | 1413 // Number x Number => Float64Mul |
1389 VisitFloat64Binop(node); | 1414 VisitFloat64Binop(node); |
1390 if (lower()) ChangeToPureOp(node, Float64Op(node)); | 1415 if (lower()) ChangeToPureOp(node, Float64Op(node)); |
1391 return; | 1416 return; |
1392 } | 1417 } |
1393 case IrOpcode::kSpeculativeNumberDivide: { | 1418 case IrOpcode::kSpeculativeNumberDivide: { |
1394 if (truncation.IsUnused()) return VisitUnused(node); | 1419 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we |
| 1420 // can only eliminate an unused speculative number operation if we know |
| 1421 // that the inputs are PlainPrimitive, which excludes everything that's |
| 1422 // might have side effects or throws during a ToNumber conversion. |
| 1423 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1424 if (truncation.IsUnused()) return VisitUnused(node); |
| 1425 } |
1395 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) { | 1426 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) { |
1396 // => unsigned Uint32Div | 1427 // => unsigned Uint32Div |
1397 VisitWord32TruncatingBinop(node); | 1428 VisitWord32TruncatingBinop(node); |
1398 if (lower()) DeferReplacement(node, lowering->Uint32Div(node)); | 1429 if (lower()) DeferReplacement(node, lowering->Uint32Div(node)); |
1399 return; | 1430 return; |
1400 } | 1431 } |
1401 if (BothInputsAreSigned32(node)) { | 1432 if (BothInputsAreSigned32(node)) { |
1402 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { | 1433 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { |
1403 // => signed Int32Div | 1434 // => signed Int32Div |
1404 VisitInt32Binop(node); | 1435 VisitInt32Binop(node); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1490 return; | 1521 return; |
1491 } | 1522 } |
1492 // Checked float64 x float64 => float64 | 1523 // Checked float64 x float64 => float64 |
1493 DCHECK_EQ(IrOpcode::kSpeculativeNumberDivide, node->opcode()); | 1524 DCHECK_EQ(IrOpcode::kSpeculativeNumberDivide, node->opcode()); |
1494 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(), | 1525 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(), |
1495 MachineRepresentation::kFloat64, Type::Number()); | 1526 MachineRepresentation::kFloat64, Type::Number()); |
1496 if (lower()) ChangeToPureOp(node, Float64Op(node)); | 1527 if (lower()) ChangeToPureOp(node, Float64Op(node)); |
1497 return; | 1528 return; |
1498 } | 1529 } |
1499 case IrOpcode::kSpeculativeNumberModulus: { | 1530 case IrOpcode::kSpeculativeNumberModulus: { |
1500 if (truncation.IsUnused()) return VisitUnused(node); | 1531 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we |
| 1532 // can only eliminate an unused speculative number operation if we know |
| 1533 // that the inputs are PlainPrimitive, which excludes everything that's |
| 1534 // might have side effects or throws during a ToNumber conversion. |
| 1535 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1536 if (truncation.IsUnused()) return VisitUnused(node); |
| 1537 } |
1501 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) { | 1538 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) { |
1502 // => unsigned Uint32Mod | 1539 // => unsigned Uint32Mod |
1503 VisitWord32TruncatingBinop(node); | 1540 VisitWord32TruncatingBinop(node); |
1504 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node)); | 1541 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node)); |
1505 return; | 1542 return; |
1506 } | 1543 } |
1507 if (BothInputsAreSigned32(node)) { | 1544 if (BothInputsAreSigned32(node)) { |
1508 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { | 1545 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { |
1509 // => signed Int32Mod | 1546 // => signed Int32Mod |
1510 VisitInt32Binop(node); | 1547 VisitInt32Binop(node); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 case IrOpcode::kNumberShiftLeft: { | 1641 case IrOpcode::kNumberShiftLeft: { |
1605 Type* rhs_type = GetUpperBound(node->InputAt(1)); | 1642 Type* rhs_type = GetUpperBound(node->InputAt(1)); |
1606 VisitBinop(node, UseInfo::TruncatingWord32(), | 1643 VisitBinop(node, UseInfo::TruncatingWord32(), |
1607 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32); | 1644 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32); |
1608 if (lower()) { | 1645 if (lower()) { |
1609 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type); | 1646 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type); |
1610 } | 1647 } |
1611 return; | 1648 return; |
1612 } | 1649 } |
1613 case IrOpcode::kSpeculativeNumberShiftLeft: { | 1650 case IrOpcode::kSpeculativeNumberShiftLeft: { |
1614 if (truncation.IsUnused()) return VisitUnused(node); | 1651 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we |
| 1652 // can only eliminate an unused speculative number operation if we know |
| 1653 // that the inputs are PlainPrimitive, which excludes everything that's |
| 1654 // might have side effects or throws during a ToNumber conversion. |
| 1655 if (BothInputsAre(node, Type::PlainPrimitive())) { |
| 1656 if (truncation.IsUnused()) return VisitUnused(node); |
| 1657 } |
1615 if (BothInputsAre(node, Type::NumberOrOddball())) { | 1658 if (BothInputsAre(node, Type::NumberOrOddball())) { |
1616 Type* rhs_type = GetUpperBound(node->InputAt(1)); | 1659 Type* rhs_type = GetUpperBound(node->InputAt(1)); |
1617 VisitBinop(node, UseInfo::TruncatingWord32(), | 1660 VisitBinop(node, UseInfo::TruncatingWord32(), |
1618 UseInfo::TruncatingWord32(), | 1661 UseInfo::TruncatingWord32(), |
1619 MachineRepresentation::kWord32); | 1662 MachineRepresentation::kWord32); |
1620 if (lower()) { | 1663 if (lower()) { |
1621 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type); | 1664 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type); |
1622 } | 1665 } |
1623 return; | 1666 return; |
1624 } | 1667 } |
(...skipping 1836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3461 isolate(), graph()->zone(), callable.descriptor(), 0, flags, | 3504 isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
3462 Operator::kNoProperties); | 3505 Operator::kNoProperties); |
3463 to_number_operator_.set(common()->Call(desc)); | 3506 to_number_operator_.set(common()->Call(desc)); |
3464 } | 3507 } |
3465 return to_number_operator_.get(); | 3508 return to_number_operator_.get(); |
3466 } | 3509 } |
3467 | 3510 |
3468 } // namespace compiler | 3511 } // namespace compiler |
3469 } // namespace internal | 3512 } // namespace internal |
3470 } // namespace v8 | 3513 } // namespace v8 |
OLD | NEW |