2 // Copyright 2015 the V8 project authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
6 #include "src/compiler/js-intrinsic-lowering.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/node-properties.h"
17 JSIntrinsicLowering::JSIntrinsicLowering(JSGraph* jsgraph)
18 : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
21 Reduction JSIntrinsicLowering::Reduce(Node* node) {
22 if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
23 const Runtime::Function* const f =
24 Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
25 if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
26 switch (f->function_id) {
27 case Runtime::kInlineConstructDouble:
28 return ReduceConstructDouble(node);
29 case Runtime::kInlineDeoptimizeNow:
30 return ReduceDeoptimizeNow(node);
31 case Runtime::kInlineDoubleHi:
32 return ReduceDoubleHi(node);
33 case Runtime::kInlineDoubleLo:
34 return ReduceDoubleLo(node);
35 case Runtime::kInlineHeapObjectGetMap:
36 return ReduceHeapObjectGetMap(node);
37 case Runtime::kInlineIncrementStatsCounter:
38 return ReduceIncrementStatsCounter(node);
39 case Runtime::kInlineIsArray:
40 return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
41 case Runtime::kInlineIsFunction:
42 return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
43 case Runtime::kInlineIsNonNegativeSmi:
44 return ReduceIsNonNegativeSmi(node);
45 case Runtime::kInlineIsRegExp:
46 return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
47 case Runtime::kInlineIsSmi:
48 return ReduceIsSmi(node);
49 case Runtime::kInlineJSValueGetValue:
50 return ReduceJSValueGetValue(node);
51 case Runtime::kInlineMapGetInstanceType:
52 return ReduceMapGetInstanceType(node);
53 case Runtime::kInlineMathClz32:
54 return ReduceMathClz32(node);
55 case Runtime::kInlineMathFloor:
56 return ReduceMathFloor(node);
57 case Runtime::kInlineMathSqrt:
58 return ReduceMathSqrt(node);
59 case Runtime::kInlineOneByteSeqStringGetChar:
60 return ReduceSeqStringGetChar(node, String::ONE_BYTE_ENCODING);
61 case Runtime::kInlineOneByteSeqStringSetChar:
62 return ReduceSeqStringSetChar(node, String::ONE_BYTE_ENCODING);
63 case Runtime::kInlineStringGetLength:
64 return ReduceStringGetLength(node);
65 case Runtime::kInlineTwoByteSeqStringGetChar:
66 return ReduceSeqStringGetChar(node, String::TWO_BYTE_ENCODING);
67 case Runtime::kInlineTwoByteSeqStringSetChar:
68 return ReduceSeqStringSetChar(node, String::TWO_BYTE_ENCODING);
69 case Runtime::kInlineValueOf:
70 return ReduceValueOf(node);
78 Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
79 Node* high = NodeProperties::GetValueInput(node, 0);
80 Node* low = NodeProperties::GetValueInput(node, 1);
82 graph()->NewNode(machine()->Float64InsertHighWord32(),
83 graph()->NewNode(machine()->Float64InsertLowWord32(),
84 jsgraph()->Constant(0), low),
86 NodeProperties::ReplaceWithValue(node, value);
87 return Replace(value);
91 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
92 if (!FLAG_turbo_deoptimization) return NoChange();
94 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
95 DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
97 Node* effect = NodeProperties::GetEffectInput(node);
98 Node* control = NodeProperties::GetControlInput(node);
100 // We are making the continuation after the call dead. To
101 // model this, we generate if (true) statement with deopt
102 // in the true branch and continuation in the false branch.
104 graph()->NewNode(common()->Branch(), jsgraph()->TrueConstant(), control);
106 // False branch - the original continuation.
107 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
108 NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect,
111 // True branch: deopt.
112 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
114 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_true);
116 // Connect the deopt to the merge exiting the graph.
117 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
119 return Changed(deopt);
123 Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
124 return Change(node, machine()->Float64ExtractHighWord32());
128 Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
129 return Change(node, machine()->Float64ExtractLowWord32());
133 Reduction JSIntrinsicLowering::ReduceHeapObjectGetMap(Node* node) {
134 Node* value = NodeProperties::GetValueInput(node, 0);
135 Node* effect = NodeProperties::GetEffectInput(node);
136 Node* control = NodeProperties::GetControlInput(node);
137 return Change(node, simplified()->LoadField(AccessBuilder::ForMap()), value,
142 Reduction JSIntrinsicLowering::ReduceIncrementStatsCounter(Node* node) {
143 if (!FLAG_native_code_counters) return ChangeToUndefined(node);
144 HeapObjectMatcher<String> m(NodeProperties::GetValueInput(node, 0));
145 if (!m.HasValue() || !m.Value().handle()->IsString()) {
146 return ChangeToUndefined(node);
148 SmartArrayPointer<char> name = m.Value().handle()->ToCString();
149 StatsCounter counter(jsgraph()->isolate(), name.get());
150 if (!counter.Enabled()) return ChangeToUndefined(node);
152 Node* effect = NodeProperties::GetEffectInput(node);
153 Node* control = NodeProperties::GetControlInput(node);
154 FieldAccess access = AccessBuilder::ForStatsCounter();
155 Node* cnt = jsgraph()->ExternalConstant(ExternalReference(&counter));
157 graph()->NewNode(simplified()->LoadField(access), cnt, effect, control);
159 graph()->NewNode(machine()->Int32Add(), load, jsgraph()->OneConstant());
160 Node* store = graph()->NewNode(simplified()->StoreField(access), cnt, inc,
162 return ChangeToUndefined(node, store);
166 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
167 Node* node, InstanceType instance_type) {
168 // if (%_IsSmi(value)) {
171 // return %_GetInstanceType(%_GetMap(value)) == instance_type;
173 MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
175 Node* value = NodeProperties::GetValueInput(node, 0);
176 Node* effect = NodeProperties::GetEffectInput(node);
177 Node* control = NodeProperties::GetControlInput(node);
179 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
180 Node* branch = graph()->NewNode(common()->Branch(), check, control);
182 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
183 Node* etrue = effect;
184 Node* vtrue = jsgraph()->FalseConstant();
186 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
187 Node* efalse = graph()->NewNode(
188 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
189 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
192 Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
193 jsgraph()->Int32Constant(instance_type));
195 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
197 // Replace all effect uses of {node} with the {ephi}.
198 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
199 NodeProperties::ReplaceWithValue(node, node, ephi);
201 // Turn the {node} into a Phi.
202 return Change(node, common()->Phi(type, 2), vtrue, vfalse, merge);
206 Reduction JSIntrinsicLowering::ReduceIsNonNegativeSmi(Node* node) {
207 return Change(node, simplified()->ObjectIsNonNegativeSmi());
211 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
212 return Change(node, simplified()->ObjectIsSmi());
216 Reduction JSIntrinsicLowering::ReduceJSValueGetValue(Node* node) {
217 Node* value = NodeProperties::GetValueInput(node, 0);
218 Node* effect = NodeProperties::GetEffectInput(node);
219 Node* control = NodeProperties::GetControlInput(node);
220 return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
225 Reduction JSIntrinsicLowering::ReduceMapGetInstanceType(Node* node) {
226 Node* value = NodeProperties::GetValueInput(node, 0);
227 Node* effect = NodeProperties::GetEffectInput(node);
228 Node* control = NodeProperties::GetControlInput(node);
230 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
231 value, effect, control);
235 Reduction JSIntrinsicLowering::ReduceMathClz32(Node* node) {
236 return Change(node, machine()->Word32Clz());
240 Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
241 if (!machine()->HasFloat64RoundDown()) return NoChange();
242 return Change(node, machine()->Float64RoundDown());
246 Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
247 return Change(node, machine()->Float64Sqrt());
251 Reduction JSIntrinsicLowering::ReduceSeqStringGetChar(
252 Node* node, String::Encoding encoding) {
253 Node* effect = NodeProperties::GetEffectInput(node);
254 Node* control = NodeProperties::GetControlInput(node);
256 simplified()->LoadElement(AccessBuilder::ForSeqStringChar(encoding)));
257 node->ReplaceInput(2, effect);
258 node->ReplaceInput(3, control);
259 node->TrimInputCount(4);
260 NodeProperties::ReplaceWithValue(node, node, node);
261 return Changed(node);
265 Reduction JSIntrinsicLowering::ReduceSeqStringSetChar(
266 Node* node, String::Encoding encoding) {
267 // Note: The intrinsic has a strange argument order, so we need to reshuffle.
268 Node* index = NodeProperties::GetValueInput(node, 0);
269 Node* chr = NodeProperties::GetValueInput(node, 1);
270 Node* string = NodeProperties::GetValueInput(node, 2);
271 Node* effect = NodeProperties::GetEffectInput(node);
272 Node* control = NodeProperties::GetControlInput(node);
274 simplified()->StoreElement(AccessBuilder::ForSeqStringChar(encoding)));
275 node->ReplaceInput(0, string);
276 node->ReplaceInput(1, index);
277 node->ReplaceInput(2, chr);
278 node->ReplaceInput(3, effect);
279 node->ReplaceInput(4, control);
280 node->TrimInputCount(5);
281 NodeProperties::RemoveBounds(node);
282 NodeProperties::ReplaceWithValue(node, string, node);
283 return Changed(node);
287 Reduction JSIntrinsicLowering::ReduceStringGetLength(Node* node) {
288 Node* value = NodeProperties::GetValueInput(node, 0);
289 Node* effect = NodeProperties::GetEffectInput(node);
290 Node* control = NodeProperties::GetControlInput(node);
291 return Change(node, simplified()->LoadField(AccessBuilder::ForStringLength()),
292 value, effect, control);
296 Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
297 // if (%_IsSmi(value)) {
299 // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
300 // return %_GetValue(value);
304 const Operator* const merge_op = common()->Merge(2);
305 const Operator* const ephi_op = common()->EffectPhi(2);
306 const Operator* const phi_op = common()->Phi(kMachAnyTagged, 2);
308 Node* value = NodeProperties::GetValueInput(node, 0);
309 Node* effect = NodeProperties::GetEffectInput(node);
310 Node* control = NodeProperties::GetControlInput(node);
312 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
313 Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
315 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
316 Node* etrue0 = effect;
317 Node* vtrue0 = value;
319 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
323 Node* check1 = graph()->NewNode(
324 machine()->Word32Equal(),
326 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
327 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
328 value, effect, if_false0),
330 jsgraph()->Int32Constant(JS_VALUE_TYPE));
331 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
333 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
335 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
336 value, effect, if_true1);
337 Node* vtrue1 = etrue1;
339 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
340 Node* efalse1 = effect;
341 Node* vfalse1 = value;
343 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
344 efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
345 vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
348 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
350 // Replace all effect uses of {node} with the {ephi0}.
351 Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
352 NodeProperties::ReplaceWithValue(node, node, ephi0);
354 // Turn the {node} into a Phi.
355 return Change(node, phi_op, vtrue0, vfalse0, merge0);
359 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
360 // Replace all effect uses of {node} with the effect dependency.
361 NodeProperties::ReplaceWithValue(node, node);
362 // Remove the inputs corresponding to context, effect and control.
363 NodeProperties::RemoveNonValueInputs(node);
364 // Finally update the operator to the new one.
366 return Changed(node);
370 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
373 node->ReplaceInput(0, a);
374 node->ReplaceInput(1, b);
375 node->ReplaceInput(2, c);
376 node->TrimInputCount(3);
377 NodeProperties::ReplaceWithValue(node, node, node);
378 return Changed(node);
382 Reduction JSIntrinsicLowering::ChangeToUndefined(Node* node, Node* effect) {
383 NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(),
385 return Changed(node);
389 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
392 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
393 return jsgraph()->common();
397 MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
398 return jsgraph()->machine();
401 } // namespace compiler
402 } // namespace internal