a1e693585bf1eb7a60117d9eefbde470816e3a0c
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / js-intrinsic-lowering.cc
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/js-intrinsic-lowering.h"
6
7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/node-properties.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 JSIntrinsicLowering::JSIntrinsicLowering(JSGraph* jsgraph)
16     : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
17
18
19 Reduction JSIntrinsicLowering::Reduce(Node* node) {
20   if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
21   const Runtime::Function* const f =
22       Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
23   if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
24   switch (f->function_id) {
25     case Runtime::kInlineIsSmi:
26       return ReduceInlineIsSmi(node);
27     case Runtime::kInlineIsNonNegativeSmi:
28       return ReduceInlineIsNonNegativeSmi(node);
29     case Runtime::kInlineIsArray:
30       return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE);
31     case Runtime::kInlineIsFunction:
32       return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE);
33     case Runtime::kInlineIsRegExp:
34       return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE);
35     case Runtime::kInlineValueOf:
36       return ReduceInlineValueOf(node);
37     default:
38       break;
39   }
40   return NoChange();
41 }
42
43
44 Reduction JSIntrinsicLowering::ReduceInlineIsSmi(Node* node) {
45   return Change(node, simplified()->ObjectIsSmi());
46 }
47
48
49 Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) {
50   return Change(node, simplified()->ObjectIsNonNegativeSmi());
51 }
52
53
54 Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
55     Node* node, InstanceType instance_type) {
56   // if (%_IsSmi(value)) {
57   //   return false;
58   // } else {
59   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
60   // }
61   MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
62
63   Node* value = NodeProperties::GetValueInput(node, 0);
64   Node* effect = NodeProperties::GetEffectInput(node);
65   Node* control = NodeProperties::GetControlInput(node);
66
67   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
68   Node* branch = graph()->NewNode(common()->Branch(), check, control);
69
70   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
71   Node* etrue = effect;
72   Node* vtrue = jsgraph()->FalseConstant();
73
74   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
75   Node* efalse = graph()->NewNode(
76       simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
77       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
78                        effect, if_false),
79       effect, if_false);
80   Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
81                                   jsgraph()->Int32Constant(instance_type));
82
83   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
84
85   // Replace all effect uses of {node} with the {ephi}.
86   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
87   NodeProperties::ReplaceWithValue(node, node, ephi);
88
89   // Turn the {node} into a Phi.
90   return Change(node, common()->Phi(type, 2), vtrue, vfalse, merge);
91 }
92
93
94 Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
95   // if (%_IsSmi(value)) {
96   //   return value;
97   // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
98   //   return %_GetValue(value);
99   // } else {
100   //   return value;
101   // }
102   const Operator* const merge_op = common()->Merge(2);
103   const Operator* const ephi_op = common()->EffectPhi(2);
104   const Operator* const phi_op = common()->Phi(kMachAnyTagged, 2);
105
106   Node* value = NodeProperties::GetValueInput(node, 0);
107   Node* effect = NodeProperties::GetEffectInput(node);
108   Node* control = NodeProperties::GetControlInput(node);
109
110   Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
111   Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
112
113   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
114   Node* etrue0 = effect;
115   Node* vtrue0 = value;
116
117   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
118   Node* efalse0;
119   Node* vfalse0;
120   {
121     Node* check1 = graph()->NewNode(
122         machine()->Word32Equal(),
123         graph()->NewNode(
124             simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
125             graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
126                              value, effect, if_false0),
127             effect, if_false0),
128         jsgraph()->Int32Constant(JS_VALUE_TYPE));
129     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
130
131     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
132     Node* etrue1 =
133         graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
134                          value, effect, if_true1);
135     Node* vtrue1 = etrue1;
136
137     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
138     Node* efalse1 = effect;
139     Node* vfalse1 = value;
140
141     Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
142     efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
143     vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
144   }
145
146   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
147
148
149   // Replace all effect uses of {node} with the {ephi0}.
150   Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
151   NodeProperties::ReplaceWithValue(node, node, ephi0);
152
153   // Turn the {node} into a Phi.
154   return Change(node, phi_op, vtrue0, vfalse0, merge0);
155 }
156
157
158 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
159   // Remove the effects from the node and update its effect usages.
160   NodeProperties::ReplaceWithValue(node, node);
161   // Remove the inputs corresponding to context, effect and control.
162   NodeProperties::RemoveNonValueInputs(node);
163   // Finally update the operator to the new one.
164   node->set_op(op);
165   return Changed(node);
166 }
167
168
169 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
170                                       Node* b, Node* c) {
171   node->set_op(op);
172   node->ReplaceInput(0, a);
173   node->ReplaceInput(1, b);
174   node->ReplaceInput(2, c);
175   node->TrimInputCount(3);
176   return Changed(node);
177 }
178
179
180 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
181
182
183 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
184   return jsgraph()->common();
185 }
186
187
188 MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
189   return jsgraph()->machine();
190 }
191
192 }  // namespace compiler
193 }  // namespace internal
194 }  // namespace v8