blob: 830a0de607af27e0d0ee06ab056f2742089d4d39 [file] [log] [blame]
Ben Murdoch097c5b22016-05-18 11:27:45 +01001// 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
3// found in the LICENSE file.
4
5#include "src/compiler/int64-lowering.h"
6#include "src/compiler/common-operator.h"
Ben Murdochda12d292016-06-02 14:46:10 +01007#include "src/compiler/diamond.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +01008#include "src/compiler/graph.h"
9#include "src/compiler/linkage.h"
10#include "src/compiler/machine-operator.h"
Ben Murdochda12d292016-06-02 14:46:10 +010011#include "src/compiler/node-matchers.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/compiler/node-properties.h"
13
14#include "src/compiler/node.h"
15#include "src/wasm/wasm-module.h"
16#include "src/zone.h"
17
18namespace v8 {
19namespace internal {
20namespace compiler {
21
22Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
23 CommonOperatorBuilder* common, Zone* zone,
24 Signature<MachineRepresentation>* signature)
25 : zone_(zone),
26 graph_(graph),
27 machine_(machine),
28 common_(common),
Ben Murdochda12d292016-06-02 14:46:10 +010029 state_(graph, 3),
Ben Murdoch097c5b22016-05-18 11:27:45 +010030 stack_(zone),
Ben Murdochda12d292016-06-02 14:46:10 +010031 replacements_(nullptr),
32 signature_(signature),
33 placeholder_(graph->NewNode(common->Parameter(-2, "placeholder"),
34 graph->start())) {
35 replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
Ben Murdoch097c5b22016-05-18 11:27:45 +010036 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
37}
38
39void Int64Lowering::LowerGraph() {
Ben Murdochda12d292016-06-02 14:46:10 +010040 if (!machine()->Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010041 return;
42 }
Ben Murdochda12d292016-06-02 14:46:10 +010043 stack_.push_back({graph()->end(), 0});
Ben Murdoch097c5b22016-05-18 11:27:45 +010044 state_.Set(graph()->end(), State::kOnStack);
45
46 while (!stack_.empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +010047 NodeState& top = stack_.back();
48 if (top.input_index == top.node->InputCount()) {
49 // All inputs of top have already been lowered, now lower top.
50 stack_.pop_back();
51 state_.Set(top.node, State::kVisited);
52 LowerNode(top.node);
Ben Murdoch097c5b22016-05-18 11:27:45 +010053 } else {
Ben Murdochda12d292016-06-02 14:46:10 +010054 // Push the next input onto the stack.
55 Node* input = top.node->InputAt(top.input_index++);
56 if (state_.Get(input) == State::kUnvisited) {
57 if (input->opcode() == IrOpcode::kPhi) {
58 // To break cycles with phi nodes we push phis on a separate stack so
59 // that they are processed after all other nodes.
60 PreparePhiReplacement(input);
61 stack_.push_front({input, 0});
62 } else {
63 stack_.push_back({input, 0});
Ben Murdoch097c5b22016-05-18 11:27:45 +010064 }
Ben Murdochda12d292016-06-02 14:46:10 +010065 state_.Set(input, State::kOnStack);
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010067 }
68 }
69}
70
71static int GetParameterIndexAfterLowering(
72 Signature<MachineRepresentation>* signature, int old_index) {
73 int result = old_index;
74 for (int i = 0; i < old_index; i++) {
75 if (signature->GetParam(i) == MachineRepresentation::kWord64) {
76 result++;
77 }
78 }
79 return result;
80}
81
Ben Murdochc5610432016-08-08 18:44:38 +010082int Int64Lowering::GetParameterCountAfterLowering(
Ben Murdoch097c5b22016-05-18 11:27:45 +010083 Signature<MachineRepresentation>* signature) {
Ben Murdochc5610432016-08-08 18:44:38 +010084 // GetParameterIndexAfterLowering(parameter_count) returns the parameter count
85 // after lowering.
Ben Murdoch097c5b22016-05-18 11:27:45 +010086 return GetParameterIndexAfterLowering(
87 signature, static_cast<int>(signature->parameter_count()));
88}
89
90static int GetReturnCountAfterLowering(
91 Signature<MachineRepresentation>* signature) {
92 int result = static_cast<int>(signature->return_count());
93 for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
94 if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
95 result++;
96 }
97 }
98 return result;
99}
100
101void Int64Lowering::LowerNode(Node* node) {
102 switch (node->opcode()) {
103 case IrOpcode::kInt64Constant: {
104 int64_t value = OpParameter<int64_t>(node);
105 Node* low_node = graph()->NewNode(
106 common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
107 Node* high_node = graph()->NewNode(
108 common()->Int32Constant(static_cast<int32_t>(value >> 32)));
109 ReplaceNode(node, low_node, high_node);
110 break;
111 }
112 case IrOpcode::kLoad: {
113 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
114
115 if (load_rep.representation() == MachineRepresentation::kWord64) {
116 Node* base = node->InputAt(0);
117 Node* index = node->InputAt(1);
118 Node* index_high =
119 graph()->NewNode(machine()->Int32Add(), index,
120 graph()->NewNode(common()->Int32Constant(4)));
121
122 const Operator* load_op = machine()->Load(MachineType::Int32());
123 Node* high_node;
124 if (node->InputCount() > 2) {
125 Node* effect_high = node->InputAt(2);
126 Node* control_high = node->InputAt(3);
127 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
128 control_high);
129 // change the effect change from old_node --> old_effect to
130 // old_node --> high_node --> old_effect.
131 node->ReplaceInput(2, high_node);
132 } else {
133 high_node = graph()->NewNode(load_op, base, index_high);
134 }
135 NodeProperties::ChangeOp(node, load_op);
136 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100137 } else {
138 DefaultLowering(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100139 }
140 break;
141 }
142 case IrOpcode::kStore: {
143 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
144 if (store_rep.representation() == MachineRepresentation::kWord64) {
145 // We change the original store node to store the low word, and create
146 // a new store node to store the high word. The effect and control edges
147 // are copied from the original store to the new store node, the effect
148 // edge of the original store is redirected to the new store.
149 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
150
151 Node* base = node->InputAt(0);
152 Node* index = node->InputAt(1);
153 Node* index_high =
154 graph()->NewNode(machine()->Int32Add(), index,
155 graph()->NewNode(common()->Int32Constant(4)));
156
157 Node* value = node->InputAt(2);
158 DCHECK(HasReplacementLow(value));
159 DCHECK(HasReplacementHigh(value));
160
161 const Operator* store_op = machine()->Store(StoreRepresentation(
162 MachineRepresentation::kWord32, write_barrier_kind));
163
164 Node* high_node;
165 if (node->InputCount() > 3) {
166 Node* effect_high = node->InputAt(3);
167 Node* control_high = node->InputAt(4);
168 high_node = graph()->NewNode(store_op, base, index_high,
169 GetReplacementHigh(value), effect_high,
170 control_high);
171 node->ReplaceInput(3, high_node);
172
173 } else {
174 high_node = graph()->NewNode(store_op, base, index_high,
175 GetReplacementHigh(value));
176 }
177
178 node->ReplaceInput(2, GetReplacementLow(value));
179 NodeProperties::ChangeOp(node, store_op);
180 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100181 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100182 if (HasReplacementLow(node->InputAt(2))) {
183 node->ReplaceInput(2, GetReplacementLow(node->InputAt(2)));
184 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100185 }
186 break;
187 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 case IrOpcode::kStart: {
189 int parameter_count = GetParameterCountAfterLowering(signature());
190 // Only exchange the node if the parameter count actually changed.
191 if (parameter_count != signature()->parameter_count()) {
192 int delta =
193 parameter_count - static_cast<int>(signature()->parameter_count());
194 int new_output_count = node->op()->ValueOutputCount() + delta;
195 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
196 }
197 break;
198 }
199 case IrOpcode::kParameter: {
200 DCHECK(node->InputCount() == 1);
201 // Only exchange the node if the parameter count actually changed. We do
202 // not even have to do the default lowering because the the start node,
203 // the only input of a parameter node, only changes if the parameter count
204 // changes.
205 if (GetParameterCountAfterLowering(signature()) !=
206 signature()->parameter_count()) {
207 int old_index = ParameterIndexOf(node->op());
208 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
209 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
210
211 Node* high_node = nullptr;
212 if (signature()->GetParam(old_index) ==
213 MachineRepresentation::kWord64) {
214 high_node = graph()->NewNode(common()->Parameter(new_index + 1),
215 graph()->start());
216 }
217 ReplaceNode(node, node, high_node);
218 }
219 break;
220 }
221 case IrOpcode::kReturn: {
222 DefaultLowering(node);
223 int new_return_count = GetReturnCountAfterLowering(signature());
224 if (signature()->return_count() != new_return_count) {
225 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
226 }
227 break;
228 }
229 case IrOpcode::kCall: {
Ben Murdochc5610432016-08-08 18:44:38 +0100230 // TODO(turbofan): Make WASM code const-correct wrt. CallDescriptor.
231 CallDescriptor* descriptor =
232 const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100233 if (DefaultLowering(node) ||
234 (descriptor->ReturnCount() == 1 &&
235 descriptor->GetReturnType(0) == MachineType::Int64())) {
236 // We have to adjust the call descriptor.
237 const Operator* op = common()->Call(
238 wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
239 NodeProperties::ChangeOp(node, op);
240 }
241 if (descriptor->ReturnCount() == 1 &&
242 descriptor->GetReturnType(0) == MachineType::Int64()) {
243 // We access the additional return values through projections.
244 Node* low_node = graph()->NewNode(common()->Projection(0), node);
245 Node* high_node = graph()->NewNode(common()->Projection(1), node);
246 ReplaceNode(node, low_node, high_node);
247 }
248 break;
249 }
Ben Murdochda12d292016-06-02 14:46:10 +0100250 case IrOpcode::kWord64And: {
251 DCHECK(node->InputCount() == 2);
252 Node* left = node->InputAt(0);
253 Node* right = node->InputAt(1);
254
255 Node* low_node =
256 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
257 GetReplacementLow(right));
258 Node* high_node =
259 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
260 GetReplacementHigh(right));
261 ReplaceNode(node, low_node, high_node);
262 break;
263 }
264 case IrOpcode::kTruncateInt64ToInt32: {
265 DCHECK(node->InputCount() == 1);
266 Node* input = node->InputAt(0);
267 ReplaceNode(node, GetReplacementLow(input), nullptr);
268 node->NullAllInputs();
269 break;
270 }
Ben Murdochda12d292016-06-02 14:46:10 +0100271 case IrOpcode::kInt64Add: {
272 DCHECK(node->InputCount() == 2);
273
274 Node* right = node->InputAt(1);
275 node->ReplaceInput(1, GetReplacementLow(right));
276 node->AppendInput(zone(), GetReplacementHigh(right));
277
278 Node* left = node->InputAt(0);
279 node->ReplaceInput(0, GetReplacementLow(left));
280 node->InsertInput(zone(), 1, GetReplacementHigh(left));
281
282 NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
283 // We access the additional return values through projections.
284 Node* low_node = graph()->NewNode(common()->Projection(0), node);
285 Node* high_node = graph()->NewNode(common()->Projection(1), node);
286 ReplaceNode(node, low_node, high_node);
287 break;
288 }
Ben Murdochda12d292016-06-02 14:46:10 +0100289 case IrOpcode::kInt64Sub: {
290 DCHECK(node->InputCount() == 2);
291
292 Node* right = node->InputAt(1);
293 node->ReplaceInput(1, GetReplacementLow(right));
294 node->AppendInput(zone(), GetReplacementHigh(right));
295
296 Node* left = node->InputAt(0);
297 node->ReplaceInput(0, GetReplacementLow(left));
298 node->InsertInput(zone(), 1, GetReplacementHigh(left));
299
300 NodeProperties::ChangeOp(node, machine()->Int32PairSub());
301 // We access the additional return values through projections.
302 Node* low_node = graph()->NewNode(common()->Projection(0), node);
303 Node* high_node = graph()->NewNode(common()->Projection(1), node);
304 ReplaceNode(node, low_node, high_node);
305 break;
306 }
Ben Murdochda12d292016-06-02 14:46:10 +0100307 case IrOpcode::kInt64Mul: {
308 DCHECK(node->InputCount() == 2);
309
310 Node* right = node->InputAt(1);
311 node->ReplaceInput(1, GetReplacementLow(right));
312 node->AppendInput(zone(), GetReplacementHigh(right));
313
314 Node* left = node->InputAt(0);
315 node->ReplaceInput(0, GetReplacementLow(left));
316 node->InsertInput(zone(), 1, GetReplacementHigh(left));
317
318 NodeProperties::ChangeOp(node, machine()->Int32PairMul());
319 // We access the additional return values through projections.
320 Node* low_node = graph()->NewNode(common()->Projection(0), node);
321 Node* high_node = graph()->NewNode(common()->Projection(1), node);
322 ReplaceNode(node, low_node, high_node);
323 break;
324 }
Ben Murdochda12d292016-06-02 14:46:10 +0100325 case IrOpcode::kWord64Or: {
326 DCHECK(node->InputCount() == 2);
327 Node* left = node->InputAt(0);
328 Node* right = node->InputAt(1);
329
330 Node* low_node =
331 graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
332 GetReplacementLow(right));
333 Node* high_node =
334 graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
335 GetReplacementHigh(right));
336 ReplaceNode(node, low_node, high_node);
337 break;
338 }
Ben Murdochda12d292016-06-02 14:46:10 +0100339 case IrOpcode::kWord64Xor: {
340 DCHECK(node->InputCount() == 2);
341 Node* left = node->InputAt(0);
342 Node* right = node->InputAt(1);
343
344 Node* low_node =
345 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
346 GetReplacementLow(right));
347 Node* high_node =
348 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
349 GetReplacementHigh(right));
350 ReplaceNode(node, low_node, high_node);
351 break;
352 }
Ben Murdochda12d292016-06-02 14:46:10 +0100353 case IrOpcode::kWord64Shl: {
354 // TODO(turbofan): if the shift count >= 32, then we can set the low word
355 // of the output to 0 and just calculate the high word.
356 DCHECK(node->InputCount() == 2);
357 Node* shift = node->InputAt(1);
358 if (HasReplacementLow(shift)) {
359 // We do not have to care about the high word replacement, because
360 // the shift can only be between 0 and 63 anyways.
361 node->ReplaceInput(1, GetReplacementLow(shift));
362 }
363
364 Node* value = node->InputAt(0);
365 node->ReplaceInput(0, GetReplacementLow(value));
366 node->InsertInput(zone(), 1, GetReplacementHigh(value));
367
368 NodeProperties::ChangeOp(node, machine()->Word32PairShl());
369 // We access the additional return values through projections.
370 Node* low_node = graph()->NewNode(common()->Projection(0), node);
371 Node* high_node = graph()->NewNode(common()->Projection(1), node);
372 ReplaceNode(node, low_node, high_node);
373 break;
374 }
Ben Murdochda12d292016-06-02 14:46:10 +0100375 case IrOpcode::kWord64Shr: {
376 // TODO(turbofan): if the shift count >= 32, then we can set the low word
377 // of the output to 0 and just calculate the high word.
378 DCHECK(node->InputCount() == 2);
379 Node* shift = node->InputAt(1);
380 if (HasReplacementLow(shift)) {
381 // We do not have to care about the high word replacement, because
382 // the shift can only be between 0 and 63 anyways.
383 node->ReplaceInput(1, GetReplacementLow(shift));
384 }
385
386 Node* value = node->InputAt(0);
387 node->ReplaceInput(0, GetReplacementLow(value));
388 node->InsertInput(zone(), 1, GetReplacementHigh(value));
389
390 NodeProperties::ChangeOp(node, machine()->Word32PairShr());
391 // We access the additional return values through projections.
392 Node* low_node = graph()->NewNode(common()->Projection(0), node);
393 Node* high_node = graph()->NewNode(common()->Projection(1), node);
394 ReplaceNode(node, low_node, high_node);
395 break;
396 }
Ben Murdochda12d292016-06-02 14:46:10 +0100397 case IrOpcode::kWord64Sar: {
398 // TODO(turbofan): if the shift count >= 32, then we can set the low word
399 // of the output to 0 and just calculate the high word.
400 DCHECK(node->InputCount() == 2);
401 Node* shift = node->InputAt(1);
402 if (HasReplacementLow(shift)) {
403 // We do not have to care about the high word replacement, because
404 // the shift can only be between 0 and 63 anyways.
405 node->ReplaceInput(1, GetReplacementLow(shift));
406 }
407
408 Node* value = node->InputAt(0);
409 node->ReplaceInput(0, GetReplacementLow(value));
410 node->InsertInput(zone(), 1, GetReplacementHigh(value));
411
412 NodeProperties::ChangeOp(node, machine()->Word32PairSar());
413 // We access the additional return values through projections.
414 Node* low_node = graph()->NewNode(common()->Projection(0), node);
415 Node* high_node = graph()->NewNode(common()->Projection(1), node);
416 ReplaceNode(node, low_node, high_node);
417 break;
418 }
Ben Murdochda12d292016-06-02 14:46:10 +0100419 case IrOpcode::kWord64Equal: {
420 DCHECK(node->InputCount() == 2);
421 Node* left = node->InputAt(0);
422 Node* right = node->InputAt(1);
423
424 // TODO(wasm): Use explicit comparisons and && here?
425 Node* replacement = graph()->NewNode(
426 machine()->Word32Equal(),
427 graph()->NewNode(
428 machine()->Word32Or(),
429 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
430 GetReplacementLow(right)),
431 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
432 GetReplacementHigh(right))),
433 graph()->NewNode(common()->Int32Constant(0)));
434
435 ReplaceNode(node, replacement, nullptr);
436 break;
437 }
Ben Murdochda12d292016-06-02 14:46:10 +0100438 case IrOpcode::kInt64LessThan: {
439 LowerComparison(node, machine()->Int32LessThan(),
440 machine()->Uint32LessThan());
441 break;
442 }
443 case IrOpcode::kInt64LessThanOrEqual: {
444 LowerComparison(node, machine()->Int32LessThan(),
445 machine()->Uint32LessThanOrEqual());
446 break;
447 }
448 case IrOpcode::kUint64LessThan: {
449 LowerComparison(node, machine()->Uint32LessThan(),
450 machine()->Uint32LessThan());
451 break;
452 }
453 case IrOpcode::kUint64LessThanOrEqual: {
454 LowerComparison(node, machine()->Uint32LessThan(),
455 machine()->Uint32LessThanOrEqual());
456 break;
457 }
Ben Murdochda12d292016-06-02 14:46:10 +0100458 case IrOpcode::kChangeInt32ToInt64: {
459 DCHECK(node->InputCount() == 1);
460 Node* input = node->InputAt(0);
461 if (HasReplacementLow(input)) {
462 input = GetReplacementLow(input);
463 }
464 // We use SAR to preserve the sign in the high word.
465 ReplaceNode(
466 node, input,
467 graph()->NewNode(machine()->Word32Sar(), input,
468 graph()->NewNode(common()->Int32Constant(31))));
469 node->NullAllInputs();
470 break;
471 }
Ben Murdochda12d292016-06-02 14:46:10 +0100472 case IrOpcode::kChangeUint32ToUint64: {
473 DCHECK(node->InputCount() == 1);
474 Node* input = node->InputAt(0);
475 if (HasReplacementLow(input)) {
476 input = GetReplacementLow(input);
477 }
478 ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
479 node->NullAllInputs();
480 break;
481 }
Ben Murdochda12d292016-06-02 14:46:10 +0100482 case IrOpcode::kBitcastInt64ToFloat64: {
483 DCHECK(node->InputCount() == 1);
484 Node* input = node->InputAt(0);
485 Node* stack_slot = graph()->NewNode(
486 machine()->StackSlot(MachineRepresentation::kWord64));
487
488 Node* store_high_word = graph()->NewNode(
489 machine()->Store(
490 StoreRepresentation(MachineRepresentation::kWord32,
491 WriteBarrierKind::kNoWriteBarrier)),
492 stack_slot, graph()->NewNode(common()->Int32Constant(4)),
493 GetReplacementHigh(input), graph()->start(), graph()->start());
494
495 Node* store_low_word = graph()->NewNode(
496 machine()->Store(
497 StoreRepresentation(MachineRepresentation::kWord32,
498 WriteBarrierKind::kNoWriteBarrier)),
499 stack_slot, graph()->NewNode(common()->Int32Constant(0)),
500 GetReplacementLow(input), store_high_word, graph()->start());
501
502 Node* load =
503 graph()->NewNode(machine()->Load(MachineType::Float64()), stack_slot,
504 graph()->NewNode(common()->Int32Constant(0)),
505 store_low_word, graph()->start());
506
507 ReplaceNode(node, load, nullptr);
508 break;
509 }
Ben Murdochda12d292016-06-02 14:46:10 +0100510 case IrOpcode::kBitcastFloat64ToInt64: {
511 DCHECK(node->InputCount() == 1);
512 Node* input = node->InputAt(0);
513 if (HasReplacementLow(input)) {
514 input = GetReplacementLow(input);
515 }
516 Node* stack_slot = graph()->NewNode(
517 machine()->StackSlot(MachineRepresentation::kWord64));
518 Node* store = graph()->NewNode(
519 machine()->Store(
520 StoreRepresentation(MachineRepresentation::kFloat64,
521 WriteBarrierKind::kNoWriteBarrier)),
522 stack_slot, graph()->NewNode(common()->Int32Constant(0)), input,
523 graph()->start(), graph()->start());
524
525 Node* high_node =
526 graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
527 graph()->NewNode(common()->Int32Constant(4)), store,
528 graph()->start());
529
530 Node* low_node =
531 graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
532 graph()->NewNode(common()->Int32Constant(0)), store,
533 graph()->start());
534 ReplaceNode(node, low_node, high_node);
535 break;
536 }
537 case IrOpcode::kWord64Ror: {
538 DCHECK(node->InputCount() == 2);
539 Node* input = node->InputAt(0);
540 Node* shift = HasReplacementLow(node->InputAt(1))
541 ? GetReplacementLow(node->InputAt(1))
542 : node->InputAt(1);
543 Int32Matcher m(shift);
544 if (m.HasValue()) {
545 // Precondition: 0 <= shift < 64.
546 int32_t shift_value = m.Value() & 0x3f;
547 if (shift_value == 0) {
548 ReplaceNode(node, GetReplacementLow(input),
549 GetReplacementHigh(input));
550 } else if (shift_value == 32) {
551 ReplaceNode(node, GetReplacementHigh(input),
552 GetReplacementLow(input));
553 } else {
554 Node* low_input;
555 Node* high_input;
556 if (shift_value < 32) {
557 low_input = GetReplacementLow(input);
558 high_input = GetReplacementHigh(input);
559 } else {
560 low_input = GetReplacementHigh(input);
561 high_input = GetReplacementLow(input);
562 }
563 int32_t masked_shift_value = shift_value & 0x1f;
564 Node* masked_shift =
565 graph()->NewNode(common()->Int32Constant(masked_shift_value));
566 Node* inv_shift = graph()->NewNode(
567 common()->Int32Constant(32 - masked_shift_value));
568
569 Node* low_node = graph()->NewNode(
570 machine()->Word32Or(),
571 graph()->NewNode(machine()->Word32Shr(), low_input, masked_shift),
572 graph()->NewNode(machine()->Word32Shl(), high_input, inv_shift));
573 Node* high_node = graph()->NewNode(
574 machine()->Word32Or(), graph()->NewNode(machine()->Word32Shr(),
575 high_input, masked_shift),
576 graph()->NewNode(machine()->Word32Shl(), low_input, inv_shift));
577 ReplaceNode(node, low_node, high_node);
578 }
579 } else {
580 Node* safe_shift = shift;
581 if (!machine()->Word32ShiftIsSafe()) {
582 safe_shift =
583 graph()->NewNode(machine()->Word32And(), shift,
584 graph()->NewNode(common()->Int32Constant(0x1f)));
585 }
586
587 // By creating this bit-mask with SAR and SHL we do not have to deal
588 // with shift == 0 as a special case.
589 Node* inv_mask = graph()->NewNode(
590 machine()->Word32Shl(),
591 graph()->NewNode(machine()->Word32Sar(),
592 graph()->NewNode(common()->Int32Constant(
593 std::numeric_limits<int32_t>::min())),
594 safe_shift),
595 graph()->NewNode(common()->Int32Constant(1)));
596
597 Node* bit_mask =
598 graph()->NewNode(machine()->Word32Xor(), inv_mask,
599 graph()->NewNode(common()->Int32Constant(-1)));
600
601 // We have to mask the shift value for this comparison. If
602 // !machine()->Word32ShiftIsSafe() then the masking should already be
603 // part of the graph.
604 Node* masked_shift6 = shift;
605 if (machine()->Word32ShiftIsSafe()) {
606 masked_shift6 =
607 graph()->NewNode(machine()->Word32And(), shift,
608 graph()->NewNode(common()->Int32Constant(0x3f)));
609 }
610
611 Diamond lt32(
612 graph(), common(),
613 graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
614 graph()->NewNode(common()->Int32Constant(32))));
615
616 // The low word and the high word can be swapped either at the input or
617 // at the output. We swap the inputs so that shift does not have to be
618 // kept for so long in a register.
619 Node* input_low =
620 lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
621 GetReplacementHigh(input));
622 Node* input_high =
623 lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
624 GetReplacementLow(input));
625
626 Node* rotate_low =
627 graph()->NewNode(machine()->Word32Ror(), input_low, safe_shift);
628 Node* rotate_high =
629 graph()->NewNode(machine()->Word32Ror(), input_high, safe_shift);
630
631 Node* low_node = graph()->NewNode(
632 machine()->Word32Or(),
633 graph()->NewNode(machine()->Word32And(), rotate_low, bit_mask),
634 graph()->NewNode(machine()->Word32And(), rotate_high, inv_mask));
635
636 Node* high_node = graph()->NewNode(
637 machine()->Word32Or(),
638 graph()->NewNode(machine()->Word32And(), rotate_high, bit_mask),
639 graph()->NewNode(machine()->Word32And(), rotate_low, inv_mask));
640
641 ReplaceNode(node, low_node, high_node);
642 }
643 break;
644 }
Ben Murdochda12d292016-06-02 14:46:10 +0100645 case IrOpcode::kWord64Clz: {
646 DCHECK(node->InputCount() == 1);
647 Node* input = node->InputAt(0);
648 Diamond d(
649 graph(), common(),
650 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
651 graph()->NewNode(common()->Int32Constant(0))));
652
653 Node* low_node = d.Phi(
654 MachineRepresentation::kWord32,
655 graph()->NewNode(machine()->Int32Add(),
656 graph()->NewNode(machine()->Word32Clz(),
657 GetReplacementLow(input)),
658 graph()->NewNode(common()->Int32Constant(32))),
659 graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
660 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
661 break;
662 }
Ben Murdochda12d292016-06-02 14:46:10 +0100663 case IrOpcode::kWord64Ctz: {
664 DCHECK(node->InputCount() == 1);
665 DCHECK(machine()->Word32Ctz().IsSupported());
666 Node* input = node->InputAt(0);
667 Diamond d(
668 graph(), common(),
669 graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
670 graph()->NewNode(common()->Int32Constant(0))));
671 Node* low_node =
672 d.Phi(MachineRepresentation::kWord32,
673 graph()->NewNode(machine()->Int32Add(),
674 graph()->NewNode(machine()->Word32Ctz().op(),
675 GetReplacementHigh(input)),
676 graph()->NewNode(common()->Int32Constant(32))),
677 graph()->NewNode(machine()->Word32Ctz().op(),
678 GetReplacementLow(input)));
679 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
680 break;
681 }
Ben Murdochda12d292016-06-02 14:46:10 +0100682 case IrOpcode::kWord64Popcnt: {
683 DCHECK(node->InputCount() == 1);
684 Node* input = node->InputAt(0);
685 // We assume that a Word64Popcnt node only has been created if
686 // Word32Popcnt is actually supported.
687 DCHECK(machine()->Word32Popcnt().IsSupported());
688 ReplaceNode(node, graph()->NewNode(
689 machine()->Int32Add(),
690 graph()->NewNode(machine()->Word32Popcnt().op(),
691 GetReplacementLow(input)),
692 graph()->NewNode(machine()->Word32Popcnt().op(),
693 GetReplacementHigh(input))),
694 graph()->NewNode(common()->Int32Constant(0)));
695 break;
696 }
697 case IrOpcode::kPhi: {
698 MachineRepresentation rep = PhiRepresentationOf(node->op());
699 if (rep == MachineRepresentation::kWord64) {
700 // The replacement nodes have already been created, we only have to
701 // replace placeholder nodes.
702 Node* low_node = GetReplacementLow(node);
703 Node* high_node = GetReplacementHigh(node);
704 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
705 low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
706 high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
707 }
708 } else {
709 DefaultLowering(node);
710 }
711 break;
712 }
713
Ben Murdoch097c5b22016-05-18 11:27:45 +0100714 default: { DefaultLowering(node); }
715 }
Ben Murdochda12d292016-06-02 14:46:10 +0100716} // NOLINT(readability/fn_size)
717
718void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
719 const Operator* low_word_op) {
720 DCHECK(node->InputCount() == 2);
721 Node* left = node->InputAt(0);
722 Node* right = node->InputAt(1);
723 Node* replacement = graph()->NewNode(
724 machine()->Word32Or(),
725 graph()->NewNode(high_word_op, GetReplacementHigh(left),
726 GetReplacementHigh(right)),
727 graph()->NewNode(
728 machine()->Word32And(),
729 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
730 GetReplacementHigh(right)),
731 graph()->NewNode(low_word_op, GetReplacementLow(left),
732 GetReplacementLow(right))));
733
734 ReplaceNode(node, replacement, nullptr);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100735}
736
737bool Int64Lowering::DefaultLowering(Node* node) {
738 bool something_changed = false;
739 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
740 Node* input = node->InputAt(i);
741 if (HasReplacementLow(input)) {
742 something_changed = true;
743 node->ReplaceInput(i, GetReplacementLow(input));
744 }
745 if (HasReplacementHigh(input)) {
746 something_changed = true;
747 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
748 }
749 }
750 return something_changed;
751}
752
753void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
754 // if new_low == nullptr, then also new_high == nullptr.
755 DCHECK(new_low != nullptr || new_high == nullptr);
756 replacements_[old->id()].low = new_low;
757 replacements_[old->id()].high = new_high;
758}
759
760bool Int64Lowering::HasReplacementLow(Node* node) {
761 return replacements_[node->id()].low != nullptr;
762}
763
764Node* Int64Lowering::GetReplacementLow(Node* node) {
765 Node* result = replacements_[node->id()].low;
766 DCHECK(result);
767 return result;
768}
769
770bool Int64Lowering::HasReplacementHigh(Node* node) {
771 return replacements_[node->id()].high != nullptr;
772}
773
774Node* Int64Lowering::GetReplacementHigh(Node* node) {
775 Node* result = replacements_[node->id()].high;
776 DCHECK(result);
777 return result;
778}
Ben Murdochda12d292016-06-02 14:46:10 +0100779
780void Int64Lowering::PreparePhiReplacement(Node* phi) {
781 MachineRepresentation rep = PhiRepresentationOf(phi->op());
782 if (rep == MachineRepresentation::kWord64) {
783 // We have to create the replacements for a phi node before we actually
784 // lower the phi to break potential cycles in the graph. The replacements of
785 // input nodes do not exist yet, so we use a placeholder node to pass the
786 // graph verifier.
787 int value_count = phi->op()->ValueInputCount();
788 Node** inputs_low = zone()->NewArray<Node*>(value_count + 1);
789 Node** inputs_high = zone()->NewArray<Node*>(value_count + 1);
790 for (int i = 0; i < value_count; i++) {
791 inputs_low[i] = placeholder_;
792 inputs_high[i] = placeholder_;
793 }
794 inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
795 inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
796 ReplaceNode(phi,
797 graph()->NewNode(
798 common()->Phi(MachineRepresentation::kWord32, value_count),
799 value_count + 1, inputs_low, false),
800 graph()->NewNode(
801 common()->Phi(MachineRepresentation::kWord32, value_count),
802 value_count + 1, inputs_high, false));
803 }
804}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100805} // namespace compiler
806} // namespace internal
807} // namespace v8