| 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/code-factory.h" | 5 #include "src/code-factory.h" |
| 6 #include "src/compiler/access-builder.h" | 6 #include "src/compiler/access-builder.h" |
| 7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
| 9 #include "src/compiler/linkage.h" | 9 #include "src/compiler/linkage.h" |
| 10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 // Relax the control uses of {node} by immediately replacing them with the | 33 // Relax the control uses of {node} by immediately replacing them with the |
| 34 // control input to {node}. | 34 // control input to {node}. |
| 35 // TODO(titzer): move into a GraphEditor? | 35 // TODO(titzer): move into a GraphEditor? |
| 36 static void RelaxControls(Node* node) { | 36 static void RelaxControls(Node* node) { |
| 37 NodeProperties::ReplaceWithValue(node, node, node); | 37 NodeProperties::ReplaceWithValue(node, node, node); |
| 38 } | 38 } |
| 39 | 39 |
| 40 | 40 |
| 41 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) | 41 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) |
| 42 : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) { | 42 : jsgraph_(jsgraph), simplified_(graph()->zone()) { |
| 43 zero_range_ = Type::Range(0.0, 0.0, graph()->zone()); | 43 zero_range_ = Type::Range(0.0, 0.0, graph()->zone()); |
| 44 one_range_ = Type::Range(1.0, 1.0, graph()->zone()); | 44 one_range_ = Type::Range(1.0, 1.0, graph()->zone()); |
| 45 zero_thirtyone_range_ = Type::Range(0.0, 31.0, graph()->zone()); | 45 zero_thirtyone_range_ = Type::Range(0.0, 31.0, graph()->zone()); |
| 46 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { | 46 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { |
| 47 double min = kMinInt / (1 << k); | 47 double min = kMinInt / (1 << k); |
| 48 double max = kMaxInt / (1 << k); | 48 double max = kMaxInt / (1 << k); |
| 49 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); | 49 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 | 52 |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 | 651 |
| 652 | 652 |
| 653 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { | 653 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
| 654 if (input->opcode() == IrOpcode::kJSToNumber) { | 654 if (input->opcode() == IrOpcode::kJSToNumber) { |
| 655 // Recursively try to reduce the input first. | 655 // Recursively try to reduce the input first. |
| 656 Reduction result = ReduceJSToNumber(input); | 656 Reduction result = ReduceJSToNumber(input); |
| 657 if (result.Changed()) return result; | 657 if (result.Changed()) return result; |
| 658 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) | 658 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) |
| 659 } | 659 } |
| 660 // Check if we have a cached conversion. | 660 // Check if we have a cached conversion. |
| 661 Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input); | |
| 662 if (conversion) return Replace(conversion); | |
| 663 Type* input_type = NodeProperties::GetBounds(input).upper; | 661 Type* input_type = NodeProperties::GetBounds(input).upper; |
| 664 if (input_type->Is(Type::Number())) { | 662 if (input_type->Is(Type::Number())) { |
| 665 // JSToNumber(x:number) => x | 663 // JSToNumber(x:number) => x |
| 666 return Changed(input); | 664 return Changed(input); |
| 667 } | 665 } |
| 668 if (input_type->Is(Type::Undefined())) { | 666 if (input_type->Is(Type::Undefined())) { |
| 669 // JSToNumber(undefined) => #NaN | 667 // JSToNumber(undefined) => #NaN |
| 670 return Replace(jsgraph()->NaNConstant()); | 668 return Replace(jsgraph()->NaNConstant()); |
| 671 } | 669 } |
| 672 if (input_type->Is(Type::Null())) { | 670 if (input_type->Is(Type::Null())) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 685 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { | 683 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
| 686 // Try to reduce the input first. | 684 // Try to reduce the input first. |
| 687 Node* const input = node->InputAt(0); | 685 Node* const input = node->InputAt(0); |
| 688 Reduction reduction = ReduceJSToNumberInput(input); | 686 Reduction reduction = ReduceJSToNumberInput(input); |
| 689 if (reduction.Changed()) { | 687 if (reduction.Changed()) { |
| 690 NodeProperties::ReplaceWithValue(node, reduction.replacement()); | 688 NodeProperties::ReplaceWithValue(node, reduction.replacement()); |
| 691 return reduction; | 689 return reduction; |
| 692 } | 690 } |
| 693 Type* const input_type = NodeProperties::GetBounds(input).upper; | 691 Type* const input_type = NodeProperties::GetBounds(input).upper; |
| 694 if (input_type->Is(Type::PlainPrimitive())) { | 692 if (input_type->Is(Type::PlainPrimitive())) { |
| 695 if (input->opcode() == IrOpcode::kPhi) { | |
| 696 // JSToNumber(phi(x1,...,xn,control):plain-primitive,context) | |
| 697 // => phi(JSToNumber(x1,no-context), | |
| 698 // ..., | |
| 699 // JSToNumber(xn,no-context),control) | |
| 700 int const input_count = input->InputCount() - 1; | |
| 701 Node* const control = input->InputAt(input_count); | |
| 702 DCHECK_LE(0, input_count); | |
| 703 DCHECK(NodeProperties::IsControl(control)); | |
| 704 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); | |
| 705 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | |
| 706 RelaxEffectsAndControls(node); | |
| 707 node->set_op(common()->Phi(kMachAnyTagged, input_count)); | |
| 708 for (int i = 0; i < input_count; ++i) { | |
| 709 // We must be very careful not to introduce cycles when pushing | |
| 710 // operations into phis. It is safe for {value}, since it appears | |
| 711 // as input to the phi that we are replacing, but it's not safe | |
| 712 // to simply reuse the context of the {node}. However, ToNumber() | |
| 713 // does not require a context anyways, so it's safe to discard it | |
| 714 // here and pass the dummy context. | |
| 715 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); | |
| 716 if (i < node->InputCount()) { | |
| 717 node->ReplaceInput(i, value); | |
| 718 } else { | |
| 719 node->AppendInput(graph()->zone(), value); | |
| 720 } | |
| 721 } | |
| 722 if (input_count < node->InputCount()) { | |
| 723 node->ReplaceInput(input_count, control); | |
| 724 } else { | |
| 725 node->AppendInput(graph()->zone(), control); | |
| 726 } | |
| 727 node->TrimInputCount(input_count + 1); | |
| 728 return Changed(node); | |
| 729 } | |
| 730 if (input->opcode() == IrOpcode::kSelect) { | |
| 731 // JSToNumber(select(c,x1,x2):plain-primitive,context) | |
| 732 // => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context)) | |
| 733 int const input_count = input->InputCount(); | |
| 734 BranchHint const input_hint = SelectParametersOf(input->op()).hint(); | |
| 735 DCHECK_EQ(3, input_count); | |
| 736 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); | |
| 737 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | |
| 738 RelaxEffectsAndControls(node); | |
| 739 node->set_op(common()->Select(kMachAnyTagged, input_hint)); | |
| 740 node->ReplaceInput(0, input->InputAt(0)); | |
| 741 for (int i = 1; i < input_count; ++i) { | |
| 742 // We must be very careful not to introduce cycles when pushing | |
| 743 // operations into selects. It is safe for {value}, since it appears | |
| 744 // as input to the select that we are replacing, but it's not safe | |
| 745 // to simply reuse the context of the {node}. However, ToNumber() | |
| 746 // does not require a context anyways, so it's safe to discard it | |
| 747 // here and pass the dummy context. | |
| 748 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); | |
| 749 node->ReplaceInput(i, value); | |
| 750 } | |
| 751 node->TrimInputCount(input_count); | |
| 752 return Changed(node); | |
| 753 } | |
| 754 // Remember this conversion. | |
| 755 InsertConversion(node); | |
| 756 if (NodeProperties::GetContextInput(node) != | 693 if (NodeProperties::GetContextInput(node) != |
| 757 jsgraph()->NoContextConstant() || | 694 jsgraph()->NoContextConstant() || |
| 758 NodeProperties::GetEffectInput(node) != graph()->start() || | 695 NodeProperties::GetEffectInput(node) != graph()->start() || |
| 759 NodeProperties::GetControlInput(node) != graph()->start()) { | 696 NodeProperties::GetControlInput(node) != graph()->start()) { |
| 760 // JSToNumber(x:plain-primitive,context,effect,control) | 697 // JSToNumber(x:plain-primitive,context,effect,control) |
| 761 // => JSToNumber(x,no-context,start,start) | 698 // => JSToNumber(x,no-context,start,start) |
| 762 RelaxEffectsAndControls(node); | 699 RelaxEffectsAndControls(node); |
| 763 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); | 700 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); |
| 764 NodeProperties::ReplaceControlInput(node, graph()->start()); | 701 NodeProperties::ReplaceControlInput(node, graph()->start()); |
| 765 NodeProperties::ReplaceEffectInput(node, graph()->start()); | 702 NodeProperties::ReplaceEffectInput(node, graph()->start()); |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 return NoChange(); | 1188 return NoChange(); |
| 1252 } | 1189 } |
| 1253 | 1190 |
| 1254 | 1191 |
| 1255 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) { | 1192 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) { |
| 1256 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); | 1193 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); |
| 1257 // Avoid inserting too many eager ToNumber() operations. | 1194 // Avoid inserting too many eager ToNumber() operations. |
| 1258 Reduction const reduction = ReduceJSToNumberInput(input); | 1195 Reduction const reduction = ReduceJSToNumberInput(input); |
| 1259 if (reduction.Changed()) return reduction.replacement(); | 1196 if (reduction.Changed()) return reduction.replacement(); |
| 1260 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. | 1197 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. |
| 1261 Node* const conversion = graph()->NewNode( | 1198 return graph()->NewNode( |
| 1262 javascript()->ToNumber(), input, jsgraph()->NoContextConstant(), | 1199 javascript()->ToNumber(), input, jsgraph()->NoContextConstant(), |
| 1263 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); | 1200 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); |
| 1264 InsertConversion(conversion); | |
| 1265 return conversion; | |
| 1266 } | 1201 } |
| 1267 | 1202 |
| 1268 | 1203 |
| 1269 template <IrOpcode::Value kOpcode> | |
| 1270 Node* JSTypedLowering::FindConversion(Node* input) { | |
| 1271 size_t const input_id = input->id(); | |
| 1272 if (input_id < conversions_.size()) { | |
| 1273 Node* const conversion = conversions_[input_id]; | |
| 1274 if (conversion && conversion->opcode() == kOpcode) { | |
| 1275 return conversion; | |
| 1276 } | |
| 1277 } | |
| 1278 return nullptr; | |
| 1279 } | |
| 1280 | |
| 1281 | |
| 1282 void JSTypedLowering::InsertConversion(Node* conversion) { | |
| 1283 DCHECK(conversion->opcode() == IrOpcode::kJSToNumber); | |
| 1284 size_t const input_id = conversion->InputAt(0)->id(); | |
| 1285 if (input_id >= conversions_.size()) { | |
| 1286 conversions_.resize(2 * input_id + 1); | |
| 1287 } | |
| 1288 conversions_[input_id] = conversion; | |
| 1289 } | |
| 1290 | |
| 1291 | |
| 1292 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { | 1204 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
| 1293 if (rhs == 0) return lhs; | 1205 if (rhs == 0) return lhs; |
| 1294 return graph()->NewNode(machine()->Word32Shl(), lhs, | 1206 return graph()->NewNode(machine()->Word32Shl(), lhs, |
| 1295 jsgraph()->Int32Constant(rhs)); | 1207 jsgraph()->Int32Constant(rhs)); |
| 1296 } | 1208 } |
| 1297 | 1209 |
| 1298 | 1210 |
| 1299 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } | 1211 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } |
| 1300 | 1212 |
| 1301 | 1213 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1312 } | 1224 } |
| 1313 | 1225 |
| 1314 | 1226 |
| 1315 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1227 MachineOperatorBuilder* JSTypedLowering::machine() const { |
| 1316 return jsgraph()->machine(); | 1228 return jsgraph()->machine(); |
| 1317 } | 1229 } |
| 1318 | 1230 |
| 1319 } // namespace compiler | 1231 } // namespace compiler |
| 1320 } // namespace internal | 1232 } // namespace internal |
| 1321 } // namespace v8 | 1233 } // namespace v8 |
| OLD | NEW |