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 |