blob: 8824a03dc974565f545aa57dedba7cfda19f60b3 [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
82static int GetParameterCountAfterLowering(
83 Signature<MachineRepresentation>* signature) {
84 return GetParameterIndexAfterLowering(
85 signature, static_cast<int>(signature->parameter_count()));
86}
87
88static int GetReturnCountAfterLowering(
89 Signature<MachineRepresentation>* signature) {
90 int result = static_cast<int>(signature->return_count());
91 for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
92 if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
93 result++;
94 }
95 }
96 return result;
97}
98
99void Int64Lowering::LowerNode(Node* node) {
100 switch (node->opcode()) {
101 case IrOpcode::kInt64Constant: {
102 int64_t value = OpParameter<int64_t>(node);
103 Node* low_node = graph()->NewNode(
104 common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
105 Node* high_node = graph()->NewNode(
106 common()->Int32Constant(static_cast<int32_t>(value >> 32)));
107 ReplaceNode(node, low_node, high_node);
108 break;
109 }
110 case IrOpcode::kLoad: {
111 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
112
113 if (load_rep.representation() == MachineRepresentation::kWord64) {
114 Node* base = node->InputAt(0);
115 Node* index = node->InputAt(1);
116 Node* index_high =
117 graph()->NewNode(machine()->Int32Add(), index,
118 graph()->NewNode(common()->Int32Constant(4)));
119
120 const Operator* load_op = machine()->Load(MachineType::Int32());
121 Node* high_node;
122 if (node->InputCount() > 2) {
123 Node* effect_high = node->InputAt(2);
124 Node* control_high = node->InputAt(3);
125 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
126 control_high);
127 // change the effect change from old_node --> old_effect to
128 // old_node --> high_node --> old_effect.
129 node->ReplaceInput(2, high_node);
130 } else {
131 high_node = graph()->NewNode(load_op, base, index_high);
132 }
133 NodeProperties::ChangeOp(node, load_op);
134 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100135 } else {
136 DefaultLowering(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100137 }
138 break;
139 }
140 case IrOpcode::kStore: {
141 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
142 if (store_rep.representation() == MachineRepresentation::kWord64) {
143 // We change the original store node to store the low word, and create
144 // a new store node to store the high word. The effect and control edges
145 // are copied from the original store to the new store node, the effect
146 // edge of the original store is redirected to the new store.
147 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
148
149 Node* base = node->InputAt(0);
150 Node* index = node->InputAt(1);
151 Node* index_high =
152 graph()->NewNode(machine()->Int32Add(), index,
153 graph()->NewNode(common()->Int32Constant(4)));
154
155 Node* value = node->InputAt(2);
156 DCHECK(HasReplacementLow(value));
157 DCHECK(HasReplacementHigh(value));
158
159 const Operator* store_op = machine()->Store(StoreRepresentation(
160 MachineRepresentation::kWord32, write_barrier_kind));
161
162 Node* high_node;
163 if (node->InputCount() > 3) {
164 Node* effect_high = node->InputAt(3);
165 Node* control_high = node->InputAt(4);
166 high_node = graph()->NewNode(store_op, base, index_high,
167 GetReplacementHigh(value), effect_high,
168 control_high);
169 node->ReplaceInput(3, high_node);
170
171 } else {
172 high_node = graph()->NewNode(store_op, base, index_high,
173 GetReplacementHigh(value));
174 }
175
176 node->ReplaceInput(2, GetReplacementLow(value));
177 NodeProperties::ChangeOp(node, store_op);
178 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100179 } else {
180 DefaultLowering(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 }
182 break;
183 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100184 case IrOpcode::kStart: {
185 int parameter_count = GetParameterCountAfterLowering(signature());
186 // Only exchange the node if the parameter count actually changed.
187 if (parameter_count != signature()->parameter_count()) {
188 int delta =
189 parameter_count - static_cast<int>(signature()->parameter_count());
190 int new_output_count = node->op()->ValueOutputCount() + delta;
191 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
192 }
193 break;
194 }
195 case IrOpcode::kParameter: {
196 DCHECK(node->InputCount() == 1);
197 // Only exchange the node if the parameter count actually changed. We do
198 // not even have to do the default lowering because the the start node,
199 // the only input of a parameter node, only changes if the parameter count
200 // changes.
201 if (GetParameterCountAfterLowering(signature()) !=
202 signature()->parameter_count()) {
203 int old_index = ParameterIndexOf(node->op());
204 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
205 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
206
207 Node* high_node = nullptr;
208 if (signature()->GetParam(old_index) ==
209 MachineRepresentation::kWord64) {
210 high_node = graph()->NewNode(common()->Parameter(new_index + 1),
211 graph()->start());
212 }
213 ReplaceNode(node, node, high_node);
214 }
215 break;
216 }
217 case IrOpcode::kReturn: {
218 DefaultLowering(node);
219 int new_return_count = GetReturnCountAfterLowering(signature());
220 if (signature()->return_count() != new_return_count) {
221 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
222 }
223 break;
224 }
225 case IrOpcode::kCall: {
226 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
227 if (DefaultLowering(node) ||
228 (descriptor->ReturnCount() == 1 &&
229 descriptor->GetReturnType(0) == MachineType::Int64())) {
230 // We have to adjust the call descriptor.
231 const Operator* op = common()->Call(
232 wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
233 NodeProperties::ChangeOp(node, op);
234 }
235 if (descriptor->ReturnCount() == 1 &&
236 descriptor->GetReturnType(0) == MachineType::Int64()) {
237 // We access the additional return values through projections.
238 Node* low_node = graph()->NewNode(common()->Projection(0), node);
239 Node* high_node = graph()->NewNode(common()->Projection(1), node);
240 ReplaceNode(node, low_node, high_node);
241 }
242 break;
243 }
Ben Murdochda12d292016-06-02 14:46:10 +0100244 case IrOpcode::kWord64And: {
245 DCHECK(node->InputCount() == 2);
246 Node* left = node->InputAt(0);
247 Node* right = node->InputAt(1);
248
249 Node* low_node =
250 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
251 GetReplacementLow(right));
252 Node* high_node =
253 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
254 GetReplacementHigh(right));
255 ReplaceNode(node, low_node, high_node);
256 break;
257 }
258 case IrOpcode::kTruncateInt64ToInt32: {
259 DCHECK(node->InputCount() == 1);
260 Node* input = node->InputAt(0);
261 ReplaceNode(node, GetReplacementLow(input), nullptr);
262 node->NullAllInputs();
263 break;
264 }
265 // todo(ahaas): I added a list of missing instructions here to make merging
266 // easier when I do them one by one.
267 // kExprI64Add:
268 case IrOpcode::kInt64Add: {
269 DCHECK(node->InputCount() == 2);
270
271 Node* right = node->InputAt(1);
272 node->ReplaceInput(1, GetReplacementLow(right));
273 node->AppendInput(zone(), GetReplacementHigh(right));
274
275 Node* left = node->InputAt(0);
276 node->ReplaceInput(0, GetReplacementLow(left));
277 node->InsertInput(zone(), 1, GetReplacementHigh(left));
278
279 NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
280 // We access the additional return values through projections.
281 Node* low_node = graph()->NewNode(common()->Projection(0), node);
282 Node* high_node = graph()->NewNode(common()->Projection(1), node);
283 ReplaceNode(node, low_node, high_node);
284 break;
285 }
286
287 // kExprI64Sub:
288 case IrOpcode::kInt64Sub: {
289 DCHECK(node->InputCount() == 2);
290
291 Node* right = node->InputAt(1);
292 node->ReplaceInput(1, GetReplacementLow(right));
293 node->AppendInput(zone(), GetReplacementHigh(right));
294
295 Node* left = node->InputAt(0);
296 node->ReplaceInput(0, GetReplacementLow(left));
297 node->InsertInput(zone(), 1, GetReplacementHigh(left));
298
299 NodeProperties::ChangeOp(node, machine()->Int32PairSub());
300 // We access the additional return values through projections.
301 Node* low_node = graph()->NewNode(common()->Projection(0), node);
302 Node* high_node = graph()->NewNode(common()->Projection(1), node);
303 ReplaceNode(node, low_node, high_node);
304 break;
305 }
306 // kExprI64Mul:
307 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 }
325 // kExprI64DivS:
326 // kExprI64DivU:
327 // kExprI64RemS:
328 // kExprI64RemU:
329 // kExprI64Ior:
330 case IrOpcode::kWord64Or: {
331 DCHECK(node->InputCount() == 2);
332 Node* left = node->InputAt(0);
333 Node* right = node->InputAt(1);
334
335 Node* low_node =
336 graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
337 GetReplacementLow(right));
338 Node* high_node =
339 graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
340 GetReplacementHigh(right));
341 ReplaceNode(node, low_node, high_node);
342 break;
343 }
344
345 // kExprI64Xor:
346 case IrOpcode::kWord64Xor: {
347 DCHECK(node->InputCount() == 2);
348 Node* left = node->InputAt(0);
349 Node* right = node->InputAt(1);
350
351 Node* low_node =
352 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
353 GetReplacementLow(right));
354 Node* high_node =
355 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
356 GetReplacementHigh(right));
357 ReplaceNode(node, low_node, high_node);
358 break;
359 }
360 // kExprI64Shl:
361 case IrOpcode::kWord64Shl: {
362 // TODO(turbofan): if the shift count >= 32, then we can set the low word
363 // of the output to 0 and just calculate the high word.
364 DCHECK(node->InputCount() == 2);
365 Node* shift = node->InputAt(1);
366 if (HasReplacementLow(shift)) {
367 // We do not have to care about the high word replacement, because
368 // the shift can only be between 0 and 63 anyways.
369 node->ReplaceInput(1, GetReplacementLow(shift));
370 }
371
372 Node* value = node->InputAt(0);
373 node->ReplaceInput(0, GetReplacementLow(value));
374 node->InsertInput(zone(), 1, GetReplacementHigh(value));
375
376 NodeProperties::ChangeOp(node, machine()->Word32PairShl());
377 // We access the additional return values through projections.
378 Node* low_node = graph()->NewNode(common()->Projection(0), node);
379 Node* high_node = graph()->NewNode(common()->Projection(1), node);
380 ReplaceNode(node, low_node, high_node);
381 break;
382 }
383 // kExprI64ShrU:
384 case IrOpcode::kWord64Shr: {
385 // TODO(turbofan): if the shift count >= 32, then we can set the low word
386 // of the output to 0 and just calculate the high word.
387 DCHECK(node->InputCount() == 2);
388 Node* shift = node->InputAt(1);
389 if (HasReplacementLow(shift)) {
390 // We do not have to care about the high word replacement, because
391 // the shift can only be between 0 and 63 anyways.
392 node->ReplaceInput(1, GetReplacementLow(shift));
393 }
394
395 Node* value = node->InputAt(0);
396 node->ReplaceInput(0, GetReplacementLow(value));
397 node->InsertInput(zone(), 1, GetReplacementHigh(value));
398
399 NodeProperties::ChangeOp(node, machine()->Word32PairShr());
400 // We access the additional return values through projections.
401 Node* low_node = graph()->NewNode(common()->Projection(0), node);
402 Node* high_node = graph()->NewNode(common()->Projection(1), node);
403 ReplaceNode(node, low_node, high_node);
404 break;
405 }
406 // kExprI64ShrS:
407 case IrOpcode::kWord64Sar: {
408 // TODO(turbofan): if the shift count >= 32, then we can set the low word
409 // of the output to 0 and just calculate the high word.
410 DCHECK(node->InputCount() == 2);
411 Node* shift = node->InputAt(1);
412 if (HasReplacementLow(shift)) {
413 // We do not have to care about the high word replacement, because
414 // the shift can only be between 0 and 63 anyways.
415 node->ReplaceInput(1, GetReplacementLow(shift));
416 }
417
418 Node* value = node->InputAt(0);
419 node->ReplaceInput(0, GetReplacementLow(value));
420 node->InsertInput(zone(), 1, GetReplacementHigh(value));
421
422 NodeProperties::ChangeOp(node, machine()->Word32PairSar());
423 // We access the additional return values through projections.
424 Node* low_node = graph()->NewNode(common()->Projection(0), node);
425 Node* high_node = graph()->NewNode(common()->Projection(1), node);
426 ReplaceNode(node, low_node, high_node);
427 break;
428 }
429 // kExprI64Eq:
430 case IrOpcode::kWord64Equal: {
431 DCHECK(node->InputCount() == 2);
432 Node* left = node->InputAt(0);
433 Node* right = node->InputAt(1);
434
435 // TODO(wasm): Use explicit comparisons and && here?
436 Node* replacement = graph()->NewNode(
437 machine()->Word32Equal(),
438 graph()->NewNode(
439 machine()->Word32Or(),
440 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
441 GetReplacementLow(right)),
442 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
443 GetReplacementHigh(right))),
444 graph()->NewNode(common()->Int32Constant(0)));
445
446 ReplaceNode(node, replacement, nullptr);
447 break;
448 }
449 // kExprI64LtS:
450 case IrOpcode::kInt64LessThan: {
451 LowerComparison(node, machine()->Int32LessThan(),
452 machine()->Uint32LessThan());
453 break;
454 }
455 case IrOpcode::kInt64LessThanOrEqual: {
456 LowerComparison(node, machine()->Int32LessThan(),
457 machine()->Uint32LessThanOrEqual());
458 break;
459 }
460 case IrOpcode::kUint64LessThan: {
461 LowerComparison(node, machine()->Uint32LessThan(),
462 machine()->Uint32LessThan());
463 break;
464 }
465 case IrOpcode::kUint64LessThanOrEqual: {
466 LowerComparison(node, machine()->Uint32LessThan(),
467 machine()->Uint32LessThanOrEqual());
468 break;
469 }
470
471 // kExprI64SConvertI32:
472 case IrOpcode::kChangeInt32ToInt64: {
473 DCHECK(node->InputCount() == 1);
474 Node* input = node->InputAt(0);
475 if (HasReplacementLow(input)) {
476 input = GetReplacementLow(input);
477 }
478 // We use SAR to preserve the sign in the high word.
479 ReplaceNode(
480 node, input,
481 graph()->NewNode(machine()->Word32Sar(), input,
482 graph()->NewNode(common()->Int32Constant(31))));
483 node->NullAllInputs();
484 break;
485 }
486 // kExprI64UConvertI32: {
487 case IrOpcode::kChangeUint32ToUint64: {
488 DCHECK(node->InputCount() == 1);
489 Node* input = node->InputAt(0);
490 if (HasReplacementLow(input)) {
491 input = GetReplacementLow(input);
492 }
493 ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
494 node->NullAllInputs();
495 break;
496 }
497 // kExprF64ReinterpretI64:
498 case IrOpcode::kBitcastInt64ToFloat64: {
499 DCHECK(node->InputCount() == 1);
500 Node* input = node->InputAt(0);
501 Node* stack_slot = graph()->NewNode(
502 machine()->StackSlot(MachineRepresentation::kWord64));
503
504 Node* store_high_word = graph()->NewNode(
505 machine()->Store(
506 StoreRepresentation(MachineRepresentation::kWord32,
507 WriteBarrierKind::kNoWriteBarrier)),
508 stack_slot, graph()->NewNode(common()->Int32Constant(4)),
509 GetReplacementHigh(input), graph()->start(), graph()->start());
510
511 Node* store_low_word = graph()->NewNode(
512 machine()->Store(
513 StoreRepresentation(MachineRepresentation::kWord32,
514 WriteBarrierKind::kNoWriteBarrier)),
515 stack_slot, graph()->NewNode(common()->Int32Constant(0)),
516 GetReplacementLow(input), store_high_word, graph()->start());
517
518 Node* load =
519 graph()->NewNode(machine()->Load(MachineType::Float64()), stack_slot,
520 graph()->NewNode(common()->Int32Constant(0)),
521 store_low_word, graph()->start());
522
523 ReplaceNode(node, load, nullptr);
524 break;
525 }
526 // kExprI64ReinterpretF64:
527 case IrOpcode::kBitcastFloat64ToInt64: {
528 DCHECK(node->InputCount() == 1);
529 Node* input = node->InputAt(0);
530 if (HasReplacementLow(input)) {
531 input = GetReplacementLow(input);
532 }
533 Node* stack_slot = graph()->NewNode(
534 machine()->StackSlot(MachineRepresentation::kWord64));
535 Node* store = graph()->NewNode(
536 machine()->Store(
537 StoreRepresentation(MachineRepresentation::kFloat64,
538 WriteBarrierKind::kNoWriteBarrier)),
539 stack_slot, graph()->NewNode(common()->Int32Constant(0)), input,
540 graph()->start(), graph()->start());
541
542 Node* high_node =
543 graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
544 graph()->NewNode(common()->Int32Constant(4)), store,
545 graph()->start());
546
547 Node* low_node =
548 graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
549 graph()->NewNode(common()->Int32Constant(0)), store,
550 graph()->start());
551 ReplaceNode(node, low_node, high_node);
552 break;
553 }
554 case IrOpcode::kWord64Ror: {
555 DCHECK(node->InputCount() == 2);
556 Node* input = node->InputAt(0);
557 Node* shift = HasReplacementLow(node->InputAt(1))
558 ? GetReplacementLow(node->InputAt(1))
559 : node->InputAt(1);
560 Int32Matcher m(shift);
561 if (m.HasValue()) {
562 // Precondition: 0 <= shift < 64.
563 int32_t shift_value = m.Value() & 0x3f;
564 if (shift_value == 0) {
565 ReplaceNode(node, GetReplacementLow(input),
566 GetReplacementHigh(input));
567 } else if (shift_value == 32) {
568 ReplaceNode(node, GetReplacementHigh(input),
569 GetReplacementLow(input));
570 } else {
571 Node* low_input;
572 Node* high_input;
573 if (shift_value < 32) {
574 low_input = GetReplacementLow(input);
575 high_input = GetReplacementHigh(input);
576 } else {
577 low_input = GetReplacementHigh(input);
578 high_input = GetReplacementLow(input);
579 }
580 int32_t masked_shift_value = shift_value & 0x1f;
581 Node* masked_shift =
582 graph()->NewNode(common()->Int32Constant(masked_shift_value));
583 Node* inv_shift = graph()->NewNode(
584 common()->Int32Constant(32 - masked_shift_value));
585
586 Node* low_node = graph()->NewNode(
587 machine()->Word32Or(),
588 graph()->NewNode(machine()->Word32Shr(), low_input, masked_shift),
589 graph()->NewNode(machine()->Word32Shl(), high_input, inv_shift));
590 Node* high_node = graph()->NewNode(
591 machine()->Word32Or(), graph()->NewNode(machine()->Word32Shr(),
592 high_input, masked_shift),
593 graph()->NewNode(machine()->Word32Shl(), low_input, inv_shift));
594 ReplaceNode(node, low_node, high_node);
595 }
596 } else {
597 Node* safe_shift = shift;
598 if (!machine()->Word32ShiftIsSafe()) {
599 safe_shift =
600 graph()->NewNode(machine()->Word32And(), shift,
601 graph()->NewNode(common()->Int32Constant(0x1f)));
602 }
603
604 // By creating this bit-mask with SAR and SHL we do not have to deal
605 // with shift == 0 as a special case.
606 Node* inv_mask = graph()->NewNode(
607 machine()->Word32Shl(),
608 graph()->NewNode(machine()->Word32Sar(),
609 graph()->NewNode(common()->Int32Constant(
610 std::numeric_limits<int32_t>::min())),
611 safe_shift),
612 graph()->NewNode(common()->Int32Constant(1)));
613
614 Node* bit_mask =
615 graph()->NewNode(machine()->Word32Xor(), inv_mask,
616 graph()->NewNode(common()->Int32Constant(-1)));
617
618 // We have to mask the shift value for this comparison. If
619 // !machine()->Word32ShiftIsSafe() then the masking should already be
620 // part of the graph.
621 Node* masked_shift6 = shift;
622 if (machine()->Word32ShiftIsSafe()) {
623 masked_shift6 =
624 graph()->NewNode(machine()->Word32And(), shift,
625 graph()->NewNode(common()->Int32Constant(0x3f)));
626 }
627
628 Diamond lt32(
629 graph(), common(),
630 graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
631 graph()->NewNode(common()->Int32Constant(32))));
632
633 // The low word and the high word can be swapped either at the input or
634 // at the output. We swap the inputs so that shift does not have to be
635 // kept for so long in a register.
636 Node* input_low =
637 lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
638 GetReplacementHigh(input));
639 Node* input_high =
640 lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
641 GetReplacementLow(input));
642
643 Node* rotate_low =
644 graph()->NewNode(machine()->Word32Ror(), input_low, safe_shift);
645 Node* rotate_high =
646 graph()->NewNode(machine()->Word32Ror(), input_high, safe_shift);
647
648 Node* low_node = graph()->NewNode(
649 machine()->Word32Or(),
650 graph()->NewNode(machine()->Word32And(), rotate_low, bit_mask),
651 graph()->NewNode(machine()->Word32And(), rotate_high, inv_mask));
652
653 Node* high_node = graph()->NewNode(
654 machine()->Word32Or(),
655 graph()->NewNode(machine()->Word32And(), rotate_high, bit_mask),
656 graph()->NewNode(machine()->Word32And(), rotate_low, inv_mask));
657
658 ReplaceNode(node, low_node, high_node);
659 }
660 break;
661 }
662 // kExprI64Clz:
663 case IrOpcode::kWord64Clz: {
664 DCHECK(node->InputCount() == 1);
665 Node* input = node->InputAt(0);
666 Diamond d(
667 graph(), common(),
668 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
669 graph()->NewNode(common()->Int32Constant(0))));
670
671 Node* low_node = d.Phi(
672 MachineRepresentation::kWord32,
673 graph()->NewNode(machine()->Int32Add(),
674 graph()->NewNode(machine()->Word32Clz(),
675 GetReplacementLow(input)),
676 graph()->NewNode(common()->Int32Constant(32))),
677 graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
678 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
679 break;
680 }
681 // kExprI64Ctz:
682 case IrOpcode::kWord64Ctz: {
683 DCHECK(node->InputCount() == 1);
684 DCHECK(machine()->Word32Ctz().IsSupported());
685 Node* input = node->InputAt(0);
686 Diamond d(
687 graph(), common(),
688 graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
689 graph()->NewNode(common()->Int32Constant(0))));
690 Node* low_node =
691 d.Phi(MachineRepresentation::kWord32,
692 graph()->NewNode(machine()->Int32Add(),
693 graph()->NewNode(machine()->Word32Ctz().op(),
694 GetReplacementHigh(input)),
695 graph()->NewNode(common()->Int32Constant(32))),
696 graph()->NewNode(machine()->Word32Ctz().op(),
697 GetReplacementLow(input)));
698 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
699 break;
700 }
701 // kExprI64Popcnt:
702 case IrOpcode::kWord64Popcnt: {
703 DCHECK(node->InputCount() == 1);
704 Node* input = node->InputAt(0);
705 // We assume that a Word64Popcnt node only has been created if
706 // Word32Popcnt is actually supported.
707 DCHECK(machine()->Word32Popcnt().IsSupported());
708 ReplaceNode(node, graph()->NewNode(
709 machine()->Int32Add(),
710 graph()->NewNode(machine()->Word32Popcnt().op(),
711 GetReplacementLow(input)),
712 graph()->NewNode(machine()->Word32Popcnt().op(),
713 GetReplacementHigh(input))),
714 graph()->NewNode(common()->Int32Constant(0)));
715 break;
716 }
717 case IrOpcode::kPhi: {
718 MachineRepresentation rep = PhiRepresentationOf(node->op());
719 if (rep == MachineRepresentation::kWord64) {
720 // The replacement nodes have already been created, we only have to
721 // replace placeholder nodes.
722 Node* low_node = GetReplacementLow(node);
723 Node* high_node = GetReplacementHigh(node);
724 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
725 low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
726 high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
727 }
728 } else {
729 DefaultLowering(node);
730 }
731 break;
732 }
733
Ben Murdoch097c5b22016-05-18 11:27:45 +0100734 default: { DefaultLowering(node); }
735 }
Ben Murdochda12d292016-06-02 14:46:10 +0100736} // NOLINT(readability/fn_size)
737
738void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
739 const Operator* low_word_op) {
740 DCHECK(node->InputCount() == 2);
741 Node* left = node->InputAt(0);
742 Node* right = node->InputAt(1);
743 Node* replacement = graph()->NewNode(
744 machine()->Word32Or(),
745 graph()->NewNode(high_word_op, GetReplacementHigh(left),
746 GetReplacementHigh(right)),
747 graph()->NewNode(
748 machine()->Word32And(),
749 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
750 GetReplacementHigh(right)),
751 graph()->NewNode(low_word_op, GetReplacementLow(left),
752 GetReplacementLow(right))));
753
754 ReplaceNode(node, replacement, nullptr);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100755}
756
757bool Int64Lowering::DefaultLowering(Node* node) {
758 bool something_changed = false;
759 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
760 Node* input = node->InputAt(i);
761 if (HasReplacementLow(input)) {
762 something_changed = true;
763 node->ReplaceInput(i, GetReplacementLow(input));
764 }
765 if (HasReplacementHigh(input)) {
766 something_changed = true;
767 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
768 }
769 }
770 return something_changed;
771}
772
773void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
774 // if new_low == nullptr, then also new_high == nullptr.
775 DCHECK(new_low != nullptr || new_high == nullptr);
776 replacements_[old->id()].low = new_low;
777 replacements_[old->id()].high = new_high;
778}
779
780bool Int64Lowering::HasReplacementLow(Node* node) {
781 return replacements_[node->id()].low != nullptr;
782}
783
784Node* Int64Lowering::GetReplacementLow(Node* node) {
785 Node* result = replacements_[node->id()].low;
786 DCHECK(result);
787 return result;
788}
789
790bool Int64Lowering::HasReplacementHigh(Node* node) {
791 return replacements_[node->id()].high != nullptr;
792}
793
794Node* Int64Lowering::GetReplacementHigh(Node* node) {
795 Node* result = replacements_[node->id()].high;
796 DCHECK(result);
797 return result;
798}
Ben Murdochda12d292016-06-02 14:46:10 +0100799
800void Int64Lowering::PreparePhiReplacement(Node* phi) {
801 MachineRepresentation rep = PhiRepresentationOf(phi->op());
802 if (rep == MachineRepresentation::kWord64) {
803 // We have to create the replacements for a phi node before we actually
804 // lower the phi to break potential cycles in the graph. The replacements of
805 // input nodes do not exist yet, so we use a placeholder node to pass the
806 // graph verifier.
807 int value_count = phi->op()->ValueInputCount();
808 Node** inputs_low = zone()->NewArray<Node*>(value_count + 1);
809 Node** inputs_high = zone()->NewArray<Node*>(value_count + 1);
810 for (int i = 0; i < value_count; i++) {
811 inputs_low[i] = placeholder_;
812 inputs_high[i] = placeholder_;
813 }
814 inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
815 inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
816 ReplaceNode(phi,
817 graph()->NewNode(
818 common()->Phi(MachineRepresentation::kWord32, value_count),
819 value_count + 1, inputs_low, false),
820 graph()->NewNode(
821 common()->Phi(MachineRepresentation::kWord32, value_count),
822 value_count + 1, inputs_high, false));
823 }
824}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100825} // namespace compiler
826} // namespace internal
827} // namespace v8