blob: 68d37723ef7ee1bd5722d866ce0adca0a64e19cb [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())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +010035 DCHECK_NOT_NULL(graph);
36 DCHECK_NOT_NULL(graph->end());
Ben Murdochda12d292016-06-02 14:46:10 +010037 replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
Ben Murdoch097c5b22016-05-18 11:27:45 +010038 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
39}
40
41void Int64Lowering::LowerGraph() {
Ben Murdochda12d292016-06-02 14:46:10 +010042 if (!machine()->Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010043 return;
44 }
Ben Murdochda12d292016-06-02 14:46:10 +010045 stack_.push_back({graph()->end(), 0});
Ben Murdoch097c5b22016-05-18 11:27:45 +010046 state_.Set(graph()->end(), State::kOnStack);
47
48 while (!stack_.empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +010049 NodeState& top = stack_.back();
50 if (top.input_index == top.node->InputCount()) {
51 // All inputs of top have already been lowered, now lower top.
52 stack_.pop_back();
53 state_.Set(top.node, State::kVisited);
54 LowerNode(top.node);
Ben Murdoch097c5b22016-05-18 11:27:45 +010055 } else {
Ben Murdochda12d292016-06-02 14:46:10 +010056 // Push the next input onto the stack.
57 Node* input = top.node->InputAt(top.input_index++);
58 if (state_.Get(input) == State::kUnvisited) {
59 if (input->opcode() == IrOpcode::kPhi) {
60 // To break cycles with phi nodes we push phis on a separate stack so
61 // that they are processed after all other nodes.
62 PreparePhiReplacement(input);
63 stack_.push_front({input, 0});
64 } else {
65 stack_.push_back({input, 0});
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 }
Ben Murdochda12d292016-06-02 14:46:10 +010067 state_.Set(input, State::kOnStack);
Ben Murdoch097c5b22016-05-18 11:27:45 +010068 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010069 }
70 }
71}
72
73static int GetParameterIndexAfterLowering(
74 Signature<MachineRepresentation>* signature, int old_index) {
75 int result = old_index;
76 for (int i = 0; i < old_index; i++) {
77 if (signature->GetParam(i) == MachineRepresentation::kWord64) {
78 result++;
79 }
80 }
81 return result;
82}
83
Ben Murdochc5610432016-08-08 18:44:38 +010084int Int64Lowering::GetParameterCountAfterLowering(
Ben Murdoch097c5b22016-05-18 11:27:45 +010085 Signature<MachineRepresentation>* signature) {
Ben Murdochc5610432016-08-08 18:44:38 +010086 // GetParameterIndexAfterLowering(parameter_count) returns the parameter count
87 // after lowering.
Ben Murdoch097c5b22016-05-18 11:27:45 +010088 return GetParameterIndexAfterLowering(
89 signature, static_cast<int>(signature->parameter_count()));
90}
91
92static int GetReturnCountAfterLowering(
93 Signature<MachineRepresentation>* signature) {
94 int result = static_cast<int>(signature->return_count());
95 for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
96 if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
97 result++;
98 }
99 }
100 return result;
101}
102
Ben Murdoch61f157c2016-09-16 13:49:30 +0100103void Int64Lowering::GetIndexNodes(Node* index, Node*& index_low,
104 Node*& index_high) {
105#if defined(V8_TARGET_LITTLE_ENDIAN)
106 index_low = index;
107 index_high = graph()->NewNode(machine()->Int32Add(), index,
108 graph()->NewNode(common()->Int32Constant(4)));
109#elif defined(V8_TARGET_BIG_ENDIAN)
110 index_low = graph()->NewNode(machine()->Int32Add(), index,
111 graph()->NewNode(common()->Int32Constant(4)));
112 index_high = index;
113#endif
114}
115
116#if defined(V8_TARGET_LITTLE_ENDIAN)
117const int Int64Lowering::kLowerWordOffset = 0;
118const int Int64Lowering::kHigherWordOffset = 4;
119#elif defined(V8_TARGET_BIG_ENDIAN)
120const int Int64Lowering::kLowerWordOffset = 4;
121const int Int64Lowering::kHigherWordOffset = 0;
122#endif
123
Ben Murdoch097c5b22016-05-18 11:27:45 +0100124void Int64Lowering::LowerNode(Node* node) {
125 switch (node->opcode()) {
126 case IrOpcode::kInt64Constant: {
127 int64_t value = OpParameter<int64_t>(node);
128 Node* low_node = graph()->NewNode(
129 common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
130 Node* high_node = graph()->NewNode(
131 common()->Int32Constant(static_cast<int32_t>(value >> 32)));
132 ReplaceNode(node, low_node, high_node);
133 break;
134 }
135 case IrOpcode::kLoad: {
136 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
137
138 if (load_rep.representation() == MachineRepresentation::kWord64) {
139 Node* base = node->InputAt(0);
140 Node* index = node->InputAt(1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100141 Node* index_low;
142 Node* index_high;
143 GetIndexNodes(index, index_low, index_high);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100144 const Operator* load_op = machine()->Load(MachineType::Int32());
145 Node* high_node;
146 if (node->InputCount() > 2) {
147 Node* effect_high = node->InputAt(2);
148 Node* control_high = node->InputAt(3);
149 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
150 control_high);
151 // change the effect change from old_node --> old_effect to
152 // old_node --> high_node --> old_effect.
153 node->ReplaceInput(2, high_node);
154 } else {
155 high_node = graph()->NewNode(load_op, base, index_high);
156 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157 node->ReplaceInput(1, index_low);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 NodeProperties::ChangeOp(node, load_op);
159 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100160 } else {
161 DefaultLowering(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 }
163 break;
164 }
165 case IrOpcode::kStore: {
166 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
167 if (store_rep.representation() == MachineRepresentation::kWord64) {
168 // We change the original store node to store the low word, and create
169 // a new store node to store the high word. The effect and control edges
170 // are copied from the original store to the new store node, the effect
171 // edge of the original store is redirected to the new store.
172 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
173
174 Node* base = node->InputAt(0);
175 Node* index = node->InputAt(1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100176 Node* index_low;
177 Node* index_high;
178 GetIndexNodes(index, index_low, index_high);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100179 Node* value = node->InputAt(2);
180 DCHECK(HasReplacementLow(value));
181 DCHECK(HasReplacementHigh(value));
182
183 const Operator* store_op = machine()->Store(StoreRepresentation(
184 MachineRepresentation::kWord32, write_barrier_kind));
185
186 Node* high_node;
187 if (node->InputCount() > 3) {
188 Node* effect_high = node->InputAt(3);
189 Node* control_high = node->InputAt(4);
190 high_node = graph()->NewNode(store_op, base, index_high,
191 GetReplacementHigh(value), effect_high,
192 control_high);
193 node->ReplaceInput(3, high_node);
194
195 } else {
196 high_node = graph()->NewNode(store_op, base, index_high,
197 GetReplacementHigh(value));
198 }
199
Ben Murdoch61f157c2016-09-16 13:49:30 +0100200 node->ReplaceInput(1, index_low);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100201 node->ReplaceInput(2, GetReplacementLow(value));
202 NodeProperties::ChangeOp(node, store_op);
203 ReplaceNode(node, node, high_node);
Ben Murdochda12d292016-06-02 14:46:10 +0100204 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100205 if (HasReplacementLow(node->InputAt(2))) {
206 node->ReplaceInput(2, GetReplacementLow(node->InputAt(2)));
207 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100208 }
209 break;
210 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 case IrOpcode::kStart: {
212 int parameter_count = GetParameterCountAfterLowering(signature());
213 // Only exchange the node if the parameter count actually changed.
214 if (parameter_count != signature()->parameter_count()) {
215 int delta =
216 parameter_count - static_cast<int>(signature()->parameter_count());
217 int new_output_count = node->op()->ValueOutputCount() + delta;
218 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
219 }
220 break;
221 }
222 case IrOpcode::kParameter: {
223 DCHECK(node->InputCount() == 1);
224 // Only exchange the node if the parameter count actually changed. We do
225 // not even have to do the default lowering because the the start node,
226 // the only input of a parameter node, only changes if the parameter count
227 // changes.
228 if (GetParameterCountAfterLowering(signature()) !=
229 signature()->parameter_count()) {
230 int old_index = ParameterIndexOf(node->op());
231 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
232 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
233
234 Node* high_node = nullptr;
235 if (signature()->GetParam(old_index) ==
236 MachineRepresentation::kWord64) {
237 high_node = graph()->NewNode(common()->Parameter(new_index + 1),
238 graph()->start());
239 }
240 ReplaceNode(node, node, high_node);
241 }
242 break;
243 }
244 case IrOpcode::kReturn: {
245 DefaultLowering(node);
246 int new_return_count = GetReturnCountAfterLowering(signature());
247 if (signature()->return_count() != new_return_count) {
248 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
249 }
250 break;
251 }
252 case IrOpcode::kCall: {
Ben Murdochc5610432016-08-08 18:44:38 +0100253 // TODO(turbofan): Make WASM code const-correct wrt. CallDescriptor.
254 CallDescriptor* descriptor =
255 const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100256 if (DefaultLowering(node) ||
257 (descriptor->ReturnCount() == 1 &&
258 descriptor->GetReturnType(0) == MachineType::Int64())) {
259 // We have to adjust the call descriptor.
260 const Operator* op = common()->Call(
261 wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
262 NodeProperties::ChangeOp(node, op);
263 }
264 if (descriptor->ReturnCount() == 1 &&
265 descriptor->GetReturnType(0) == MachineType::Int64()) {
266 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100267 Node* low_node =
268 graph()->NewNode(common()->Projection(0), node, graph()->start());
269 Node* high_node =
270 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 ReplaceNode(node, low_node, high_node);
272 }
273 break;
274 }
Ben Murdochda12d292016-06-02 14:46:10 +0100275 case IrOpcode::kWord64And: {
276 DCHECK(node->InputCount() == 2);
277 Node* left = node->InputAt(0);
278 Node* right = node->InputAt(1);
279
280 Node* low_node =
281 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
282 GetReplacementLow(right));
283 Node* high_node =
284 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
285 GetReplacementHigh(right));
286 ReplaceNode(node, low_node, high_node);
287 break;
288 }
289 case IrOpcode::kTruncateInt64ToInt32: {
290 DCHECK(node->InputCount() == 1);
291 Node* input = node->InputAt(0);
292 ReplaceNode(node, GetReplacementLow(input), nullptr);
293 node->NullAllInputs();
294 break;
295 }
Ben Murdochda12d292016-06-02 14:46:10 +0100296 case IrOpcode::kInt64Add: {
297 DCHECK(node->InputCount() == 2);
298
299 Node* right = node->InputAt(1);
300 node->ReplaceInput(1, GetReplacementLow(right));
301 node->AppendInput(zone(), GetReplacementHigh(right));
302
303 Node* left = node->InputAt(0);
304 node->ReplaceInput(0, GetReplacementLow(left));
305 node->InsertInput(zone(), 1, GetReplacementHigh(left));
306
307 NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
308 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100309 Node* low_node =
310 graph()->NewNode(common()->Projection(0), node, graph()->start());
311 Node* high_node =
312 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100313 ReplaceNode(node, low_node, high_node);
314 break;
315 }
Ben Murdochda12d292016-06-02 14:46:10 +0100316 case IrOpcode::kInt64Sub: {
317 DCHECK(node->InputCount() == 2);
318
319 Node* right = node->InputAt(1);
320 node->ReplaceInput(1, GetReplacementLow(right));
321 node->AppendInput(zone(), GetReplacementHigh(right));
322
323 Node* left = node->InputAt(0);
324 node->ReplaceInput(0, GetReplacementLow(left));
325 node->InsertInput(zone(), 1, GetReplacementHigh(left));
326
327 NodeProperties::ChangeOp(node, machine()->Int32PairSub());
328 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100329 Node* low_node =
330 graph()->NewNode(common()->Projection(0), node, graph()->start());
331 Node* high_node =
332 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100333 ReplaceNode(node, low_node, high_node);
334 break;
335 }
Ben Murdochda12d292016-06-02 14:46:10 +0100336 case IrOpcode::kInt64Mul: {
337 DCHECK(node->InputCount() == 2);
338
339 Node* right = node->InputAt(1);
340 node->ReplaceInput(1, GetReplacementLow(right));
341 node->AppendInput(zone(), GetReplacementHigh(right));
342
343 Node* left = node->InputAt(0);
344 node->ReplaceInput(0, GetReplacementLow(left));
345 node->InsertInput(zone(), 1, GetReplacementHigh(left));
346
347 NodeProperties::ChangeOp(node, machine()->Int32PairMul());
348 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100349 Node* low_node =
350 graph()->NewNode(common()->Projection(0), node, graph()->start());
351 Node* high_node =
352 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100353 ReplaceNode(node, low_node, high_node);
354 break;
355 }
Ben Murdochda12d292016-06-02 14:46:10 +0100356 case IrOpcode::kWord64Or: {
357 DCHECK(node->InputCount() == 2);
358 Node* left = node->InputAt(0);
359 Node* right = node->InputAt(1);
360
361 Node* low_node =
362 graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
363 GetReplacementLow(right));
364 Node* high_node =
365 graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
366 GetReplacementHigh(right));
367 ReplaceNode(node, low_node, high_node);
368 break;
369 }
Ben Murdochda12d292016-06-02 14:46:10 +0100370 case IrOpcode::kWord64Xor: {
371 DCHECK(node->InputCount() == 2);
372 Node* left = node->InputAt(0);
373 Node* right = node->InputAt(1);
374
375 Node* low_node =
376 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
377 GetReplacementLow(right));
378 Node* high_node =
379 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
380 GetReplacementHigh(right));
381 ReplaceNode(node, low_node, high_node);
382 break;
383 }
Ben Murdochda12d292016-06-02 14:46:10 +0100384 case IrOpcode::kWord64Shl: {
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()->Word32PairShl());
400 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100401 Node* low_node =
402 graph()->NewNode(common()->Projection(0), node, graph()->start());
403 Node* high_node =
404 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100405 ReplaceNode(node, low_node, high_node);
406 break;
407 }
Ben Murdochda12d292016-06-02 14:46:10 +0100408 case IrOpcode::kWord64Shr: {
409 // TODO(turbofan): if the shift count >= 32, then we can set the low word
410 // of the output to 0 and just calculate the high word.
411 DCHECK(node->InputCount() == 2);
412 Node* shift = node->InputAt(1);
413 if (HasReplacementLow(shift)) {
414 // We do not have to care about the high word replacement, because
415 // the shift can only be between 0 and 63 anyways.
416 node->ReplaceInput(1, GetReplacementLow(shift));
417 }
418
419 Node* value = node->InputAt(0);
420 node->ReplaceInput(0, GetReplacementLow(value));
421 node->InsertInput(zone(), 1, GetReplacementHigh(value));
422
423 NodeProperties::ChangeOp(node, machine()->Word32PairShr());
424 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100425 Node* low_node =
426 graph()->NewNode(common()->Projection(0), node, graph()->start());
427 Node* high_node =
428 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100429 ReplaceNode(node, low_node, high_node);
430 break;
431 }
Ben Murdochda12d292016-06-02 14:46:10 +0100432 case IrOpcode::kWord64Sar: {
433 // TODO(turbofan): if the shift count >= 32, then we can set the low word
434 // of the output to 0 and just calculate the high word.
435 DCHECK(node->InputCount() == 2);
436 Node* shift = node->InputAt(1);
437 if (HasReplacementLow(shift)) {
438 // We do not have to care about the high word replacement, because
439 // the shift can only be between 0 and 63 anyways.
440 node->ReplaceInput(1, GetReplacementLow(shift));
441 }
442
443 Node* value = node->InputAt(0);
444 node->ReplaceInput(0, GetReplacementLow(value));
445 node->InsertInput(zone(), 1, GetReplacementHigh(value));
446
447 NodeProperties::ChangeOp(node, machine()->Word32PairSar());
448 // We access the additional return values through projections.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100449 Node* low_node =
450 graph()->NewNode(common()->Projection(0), node, graph()->start());
451 Node* high_node =
452 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100453 ReplaceNode(node, low_node, high_node);
454 break;
455 }
Ben Murdochda12d292016-06-02 14:46:10 +0100456 case IrOpcode::kWord64Equal: {
457 DCHECK(node->InputCount() == 2);
458 Node* left = node->InputAt(0);
459 Node* right = node->InputAt(1);
460
461 // TODO(wasm): Use explicit comparisons and && here?
462 Node* replacement = graph()->NewNode(
463 machine()->Word32Equal(),
464 graph()->NewNode(
465 machine()->Word32Or(),
466 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
467 GetReplacementLow(right)),
468 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
469 GetReplacementHigh(right))),
470 graph()->NewNode(common()->Int32Constant(0)));
471
472 ReplaceNode(node, replacement, nullptr);
473 break;
474 }
Ben Murdochda12d292016-06-02 14:46:10 +0100475 case IrOpcode::kInt64LessThan: {
476 LowerComparison(node, machine()->Int32LessThan(),
477 machine()->Uint32LessThan());
478 break;
479 }
480 case IrOpcode::kInt64LessThanOrEqual: {
481 LowerComparison(node, machine()->Int32LessThan(),
482 machine()->Uint32LessThanOrEqual());
483 break;
484 }
485 case IrOpcode::kUint64LessThan: {
486 LowerComparison(node, machine()->Uint32LessThan(),
487 machine()->Uint32LessThan());
488 break;
489 }
490 case IrOpcode::kUint64LessThanOrEqual: {
491 LowerComparison(node, machine()->Uint32LessThan(),
492 machine()->Uint32LessThanOrEqual());
493 break;
494 }
Ben Murdochda12d292016-06-02 14:46:10 +0100495 case IrOpcode::kChangeInt32ToInt64: {
496 DCHECK(node->InputCount() == 1);
497 Node* input = node->InputAt(0);
498 if (HasReplacementLow(input)) {
499 input = GetReplacementLow(input);
500 }
501 // We use SAR to preserve the sign in the high word.
502 ReplaceNode(
503 node, input,
504 graph()->NewNode(machine()->Word32Sar(), input,
505 graph()->NewNode(common()->Int32Constant(31))));
506 node->NullAllInputs();
507 break;
508 }
Ben Murdochda12d292016-06-02 14:46:10 +0100509 case IrOpcode::kChangeUint32ToUint64: {
510 DCHECK(node->InputCount() == 1);
511 Node* input = node->InputAt(0);
512 if (HasReplacementLow(input)) {
513 input = GetReplacementLow(input);
514 }
515 ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
516 node->NullAllInputs();
517 break;
518 }
Ben Murdochda12d292016-06-02 14:46:10 +0100519 case IrOpcode::kBitcastInt64ToFloat64: {
520 DCHECK(node->InputCount() == 1);
521 Node* input = node->InputAt(0);
522 Node* stack_slot = graph()->NewNode(
523 machine()->StackSlot(MachineRepresentation::kWord64));
524
525 Node* store_high_word = graph()->NewNode(
526 machine()->Store(
527 StoreRepresentation(MachineRepresentation::kWord32,
528 WriteBarrierKind::kNoWriteBarrier)),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100529 stack_slot,
530 graph()->NewNode(common()->Int32Constant(kHigherWordOffset)),
Ben Murdochda12d292016-06-02 14:46:10 +0100531 GetReplacementHigh(input), graph()->start(), graph()->start());
532
533 Node* store_low_word = graph()->NewNode(
534 machine()->Store(
535 StoreRepresentation(MachineRepresentation::kWord32,
536 WriteBarrierKind::kNoWriteBarrier)),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100537 stack_slot,
538 graph()->NewNode(common()->Int32Constant(kLowerWordOffset)),
Ben Murdochda12d292016-06-02 14:46:10 +0100539 GetReplacementLow(input), store_high_word, graph()->start());
540
541 Node* load =
542 graph()->NewNode(machine()->Load(MachineType::Float64()), stack_slot,
543 graph()->NewNode(common()->Int32Constant(0)),
544 store_low_word, graph()->start());
545
546 ReplaceNode(node, load, nullptr);
547 break;
548 }
Ben Murdochda12d292016-06-02 14:46:10 +0100549 case IrOpcode::kBitcastFloat64ToInt64: {
550 DCHECK(node->InputCount() == 1);
551 Node* input = node->InputAt(0);
552 if (HasReplacementLow(input)) {
553 input = GetReplacementLow(input);
554 }
555 Node* stack_slot = graph()->NewNode(
556 machine()->StackSlot(MachineRepresentation::kWord64));
557 Node* store = graph()->NewNode(
558 machine()->Store(
559 StoreRepresentation(MachineRepresentation::kFloat64,
560 WriteBarrierKind::kNoWriteBarrier)),
561 stack_slot, graph()->NewNode(common()->Int32Constant(0)), input,
562 graph()->start(), graph()->start());
563
Ben Murdoch61f157c2016-09-16 13:49:30 +0100564 Node* high_node = graph()->NewNode(
565 machine()->Load(MachineType::Int32()), stack_slot,
566 graph()->NewNode(common()->Int32Constant(kHigherWordOffset)), store,
567 graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100568
Ben Murdoch61f157c2016-09-16 13:49:30 +0100569 Node* low_node = graph()->NewNode(
570 machine()->Load(MachineType::Int32()), stack_slot,
571 graph()->NewNode(common()->Int32Constant(kLowerWordOffset)), store,
572 graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +0100573 ReplaceNode(node, low_node, high_node);
574 break;
575 }
576 case IrOpcode::kWord64Ror: {
577 DCHECK(node->InputCount() == 2);
578 Node* input = node->InputAt(0);
579 Node* shift = HasReplacementLow(node->InputAt(1))
580 ? GetReplacementLow(node->InputAt(1))
581 : node->InputAt(1);
582 Int32Matcher m(shift);
583 if (m.HasValue()) {
584 // Precondition: 0 <= shift < 64.
585 int32_t shift_value = m.Value() & 0x3f;
586 if (shift_value == 0) {
587 ReplaceNode(node, GetReplacementLow(input),
588 GetReplacementHigh(input));
589 } else if (shift_value == 32) {
590 ReplaceNode(node, GetReplacementHigh(input),
591 GetReplacementLow(input));
592 } else {
593 Node* low_input;
594 Node* high_input;
595 if (shift_value < 32) {
596 low_input = GetReplacementLow(input);
597 high_input = GetReplacementHigh(input);
598 } else {
599 low_input = GetReplacementHigh(input);
600 high_input = GetReplacementLow(input);
601 }
602 int32_t masked_shift_value = shift_value & 0x1f;
603 Node* masked_shift =
604 graph()->NewNode(common()->Int32Constant(masked_shift_value));
605 Node* inv_shift = graph()->NewNode(
606 common()->Int32Constant(32 - masked_shift_value));
607
608 Node* low_node = graph()->NewNode(
609 machine()->Word32Or(),
610 graph()->NewNode(machine()->Word32Shr(), low_input, masked_shift),
611 graph()->NewNode(machine()->Word32Shl(), high_input, inv_shift));
612 Node* high_node = graph()->NewNode(
613 machine()->Word32Or(), graph()->NewNode(machine()->Word32Shr(),
614 high_input, masked_shift),
615 graph()->NewNode(machine()->Word32Shl(), low_input, inv_shift));
616 ReplaceNode(node, low_node, high_node);
617 }
618 } else {
619 Node* safe_shift = shift;
620 if (!machine()->Word32ShiftIsSafe()) {
621 safe_shift =
622 graph()->NewNode(machine()->Word32And(), shift,
623 graph()->NewNode(common()->Int32Constant(0x1f)));
624 }
625
626 // By creating this bit-mask with SAR and SHL we do not have to deal
627 // with shift == 0 as a special case.
628 Node* inv_mask = graph()->NewNode(
629 machine()->Word32Shl(),
630 graph()->NewNode(machine()->Word32Sar(),
631 graph()->NewNode(common()->Int32Constant(
632 std::numeric_limits<int32_t>::min())),
633 safe_shift),
634 graph()->NewNode(common()->Int32Constant(1)));
635
636 Node* bit_mask =
637 graph()->NewNode(machine()->Word32Xor(), inv_mask,
638 graph()->NewNode(common()->Int32Constant(-1)));
639
640 // We have to mask the shift value for this comparison. If
641 // !machine()->Word32ShiftIsSafe() then the masking should already be
642 // part of the graph.
643 Node* masked_shift6 = shift;
644 if (machine()->Word32ShiftIsSafe()) {
645 masked_shift6 =
646 graph()->NewNode(machine()->Word32And(), shift,
647 graph()->NewNode(common()->Int32Constant(0x3f)));
648 }
649
650 Diamond lt32(
651 graph(), common(),
652 graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
653 graph()->NewNode(common()->Int32Constant(32))));
654
655 // The low word and the high word can be swapped either at the input or
656 // at the output. We swap the inputs so that shift does not have to be
657 // kept for so long in a register.
658 Node* input_low =
659 lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
660 GetReplacementHigh(input));
661 Node* input_high =
662 lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
663 GetReplacementLow(input));
664
665 Node* rotate_low =
666 graph()->NewNode(machine()->Word32Ror(), input_low, safe_shift);
667 Node* rotate_high =
668 graph()->NewNode(machine()->Word32Ror(), input_high, safe_shift);
669
670 Node* low_node = graph()->NewNode(
671 machine()->Word32Or(),
672 graph()->NewNode(machine()->Word32And(), rotate_low, bit_mask),
673 graph()->NewNode(machine()->Word32And(), rotate_high, inv_mask));
674
675 Node* high_node = graph()->NewNode(
676 machine()->Word32Or(),
677 graph()->NewNode(machine()->Word32And(), rotate_high, bit_mask),
678 graph()->NewNode(machine()->Word32And(), rotate_low, inv_mask));
679
680 ReplaceNode(node, low_node, high_node);
681 }
682 break;
683 }
Ben Murdochda12d292016-06-02 14:46:10 +0100684 case IrOpcode::kWord64Clz: {
685 DCHECK(node->InputCount() == 1);
686 Node* input = node->InputAt(0);
687 Diamond d(
688 graph(), common(),
689 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
690 graph()->NewNode(common()->Int32Constant(0))));
691
692 Node* low_node = d.Phi(
693 MachineRepresentation::kWord32,
694 graph()->NewNode(machine()->Int32Add(),
695 graph()->NewNode(machine()->Word32Clz(),
696 GetReplacementLow(input)),
697 graph()->NewNode(common()->Int32Constant(32))),
698 graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
699 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
700 break;
701 }
Ben Murdochda12d292016-06-02 14:46:10 +0100702 case IrOpcode::kWord64Ctz: {
703 DCHECK(node->InputCount() == 1);
704 DCHECK(machine()->Word32Ctz().IsSupported());
705 Node* input = node->InputAt(0);
706 Diamond d(
707 graph(), common(),
708 graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
709 graph()->NewNode(common()->Int32Constant(0))));
710 Node* low_node =
711 d.Phi(MachineRepresentation::kWord32,
712 graph()->NewNode(machine()->Int32Add(),
713 graph()->NewNode(machine()->Word32Ctz().op(),
714 GetReplacementHigh(input)),
715 graph()->NewNode(common()->Int32Constant(32))),
716 graph()->NewNode(machine()->Word32Ctz().op(),
717 GetReplacementLow(input)));
718 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
719 break;
720 }
Ben Murdochda12d292016-06-02 14:46:10 +0100721 case IrOpcode::kWord64Popcnt: {
722 DCHECK(node->InputCount() == 1);
723 Node* input = node->InputAt(0);
724 // We assume that a Word64Popcnt node only has been created if
725 // Word32Popcnt is actually supported.
726 DCHECK(machine()->Word32Popcnt().IsSupported());
727 ReplaceNode(node, graph()->NewNode(
728 machine()->Int32Add(),
729 graph()->NewNode(machine()->Word32Popcnt().op(),
730 GetReplacementLow(input)),
731 graph()->NewNode(machine()->Word32Popcnt().op(),
732 GetReplacementHigh(input))),
733 graph()->NewNode(common()->Int32Constant(0)));
734 break;
735 }
736 case IrOpcode::kPhi: {
737 MachineRepresentation rep = PhiRepresentationOf(node->op());
738 if (rep == MachineRepresentation::kWord64) {
739 // The replacement nodes have already been created, we only have to
740 // replace placeholder nodes.
741 Node* low_node = GetReplacementLow(node);
742 Node* high_node = GetReplacementHigh(node);
743 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
744 low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
745 high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
746 }
747 } else {
748 DefaultLowering(node);
749 }
750 break;
751 }
752
Ben Murdoch097c5b22016-05-18 11:27:45 +0100753 default: { DefaultLowering(node); }
754 }
Ben Murdochda12d292016-06-02 14:46:10 +0100755} // NOLINT(readability/fn_size)
756
757void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
758 const Operator* low_word_op) {
759 DCHECK(node->InputCount() == 2);
760 Node* left = node->InputAt(0);
761 Node* right = node->InputAt(1);
762 Node* replacement = graph()->NewNode(
763 machine()->Word32Or(),
764 graph()->NewNode(high_word_op, GetReplacementHigh(left),
765 GetReplacementHigh(right)),
766 graph()->NewNode(
767 machine()->Word32And(),
768 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
769 GetReplacementHigh(right)),
770 graph()->NewNode(low_word_op, GetReplacementLow(left),
771 GetReplacementLow(right))));
772
773 ReplaceNode(node, replacement, nullptr);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100774}
775
776bool Int64Lowering::DefaultLowering(Node* node) {
777 bool something_changed = false;
778 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
779 Node* input = node->InputAt(i);
780 if (HasReplacementLow(input)) {
781 something_changed = true;
782 node->ReplaceInput(i, GetReplacementLow(input));
783 }
784 if (HasReplacementHigh(input)) {
785 something_changed = true;
786 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
787 }
788 }
789 return something_changed;
790}
791
792void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
793 // if new_low == nullptr, then also new_high == nullptr.
794 DCHECK(new_low != nullptr || new_high == nullptr);
795 replacements_[old->id()].low = new_low;
796 replacements_[old->id()].high = new_high;
797}
798
799bool Int64Lowering::HasReplacementLow(Node* node) {
800 return replacements_[node->id()].low != nullptr;
801}
802
803Node* Int64Lowering::GetReplacementLow(Node* node) {
804 Node* result = replacements_[node->id()].low;
805 DCHECK(result);
806 return result;
807}
808
809bool Int64Lowering::HasReplacementHigh(Node* node) {
810 return replacements_[node->id()].high != nullptr;
811}
812
813Node* Int64Lowering::GetReplacementHigh(Node* node) {
814 Node* result = replacements_[node->id()].high;
815 DCHECK(result);
816 return result;
817}
Ben Murdochda12d292016-06-02 14:46:10 +0100818
819void Int64Lowering::PreparePhiReplacement(Node* phi) {
820 MachineRepresentation rep = PhiRepresentationOf(phi->op());
821 if (rep == MachineRepresentation::kWord64) {
822 // We have to create the replacements for a phi node before we actually
823 // lower the phi to break potential cycles in the graph. The replacements of
824 // input nodes do not exist yet, so we use a placeholder node to pass the
825 // graph verifier.
826 int value_count = phi->op()->ValueInputCount();
827 Node** inputs_low = zone()->NewArray<Node*>(value_count + 1);
828 Node** inputs_high = zone()->NewArray<Node*>(value_count + 1);
829 for (int i = 0; i < value_count; i++) {
830 inputs_low[i] = placeholder_;
831 inputs_high[i] = placeholder_;
832 }
833 inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
834 inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
835 ReplaceNode(phi,
836 graph()->NewNode(
837 common()->Phi(MachineRepresentation::kWord32, value_count),
838 value_count + 1, inputs_low, false),
839 graph()->NewNode(
840 common()->Phi(MachineRepresentation::kWord32, value_count),
841 value_count + 1, inputs_high, false));
842 }
843}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100844} // namespace compiler
845} // namespace internal
846} // namespace v8