blob: 737947aad0b31a5f834936487bb8436bb55a7988 [file] [log] [blame]
Ben Murdoch109988c2016-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 Murdoch3b9bc312016-06-02 14:46:10 +01007#include "src/compiler/diamond.h"
Ben Murdoch109988c2016-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 Murdoch3b9bc312016-06-02 14:46:10 +010011#include "src/compiler/node-matchers.h"
Ben Murdoch109988c2016-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 Murdoch3b9bc312016-06-02 14:46:10 +010029 state_(graph, 3),
Ben Murdoch109988c2016-05-18 11:27:45 +010030 stack_(zone),
Ben Murdoch3b9bc312016-06-02 14:46:10 +010031 replacements_(nullptr),
32 signature_(signature),
33 placeholder_(graph->NewNode(common->Parameter(-2, "placeholder"),
34 graph->start())) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +010035 DCHECK_NOT_NULL(graph);
36 DCHECK_NOT_NULL(graph->end());
Ben Murdoch3b9bc312016-06-02 14:46:10 +010037 replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
Ben Murdoch109988c2016-05-18 11:27:45 +010038 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
39}
40
41void Int64Lowering::LowerGraph() {
Ben Murdoch3b9bc312016-06-02 14:46:10 +010042 if (!machine()->Is32()) {
Ben Murdoch109988c2016-05-18 11:27:45 +010043 return;
44 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +010045 stack_.push_back({graph()->end(), 0});
Ben Murdoch109988c2016-05-18 11:27:45 +010046 state_.Set(graph()->end(), State::kOnStack);
47
48 while (!stack_.empty()) {
Ben Murdoch3b9bc312016-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 Murdoch109988c2016-05-18 11:27:45 +010055 } else {
Ben Murdoch3b9bc312016-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 Murdoch109988c2016-05-18 11:27:45 +010066 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +010067 state_.Set(input, State::kOnStack);
Ben Murdoch109988c2016-05-18 11:27:45 +010068 }
Ben Murdoch109988c2016-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 Murdochbcf72ee2016-08-08 18:44:38 +010084int Int64Lowering::GetParameterCountAfterLowering(
Ben Murdoch109988c2016-05-18 11:27:45 +010085 Signature<MachineRepresentation>* signature) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +010086 // GetParameterIndexAfterLowering(parameter_count) returns the parameter count
87 // after lowering.
Ben Murdoch109988c2016-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 Murdoch13e2dad2016-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 Murdoch109988c2016-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 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000135 case IrOpcode::kLoad:
136 case IrOpcode::kUnalignedLoad: {
137 MachineRepresentation rep;
138 if (node->opcode() == IrOpcode::kLoad) {
139 rep = LoadRepresentationOf(node->op()).representation();
140 } else {
141 DCHECK(node->opcode() == IrOpcode::kUnalignedLoad);
142 rep = UnalignedLoadRepresentationOf(node->op()).representation();
143 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100144
Ben Murdochf91f0612016-11-29 16:50:11 +0000145 if (rep == MachineRepresentation::kWord64) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100146 Node* base = node->InputAt(0);
147 Node* index = node->InputAt(1);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100148 Node* index_low;
149 Node* index_high;
150 GetIndexNodes(index, index_low, index_high);
Ben Murdochf91f0612016-11-29 16:50:11 +0000151 const Operator* load_op;
152
153 if (node->opcode() == IrOpcode::kLoad) {
154 load_op = machine()->Load(MachineType::Int32());
155 } else {
156 DCHECK(node->opcode() == IrOpcode::kUnalignedLoad);
157 load_op = machine()->UnalignedLoad(MachineType::Int32());
158 }
159
Ben Murdoch109988c2016-05-18 11:27:45 +0100160 Node* high_node;
161 if (node->InputCount() > 2) {
162 Node* effect_high = node->InputAt(2);
163 Node* control_high = node->InputAt(3);
164 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
165 control_high);
166 // change the effect change from old_node --> old_effect to
167 // old_node --> high_node --> old_effect.
168 node->ReplaceInput(2, high_node);
169 } else {
170 high_node = graph()->NewNode(load_op, base, index_high);
171 }
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100172 node->ReplaceInput(1, index_low);
Ben Murdoch109988c2016-05-18 11:27:45 +0100173 NodeProperties::ChangeOp(node, load_op);
174 ReplaceNode(node, node, high_node);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100175 } else {
176 DefaultLowering(node);
Ben Murdoch109988c2016-05-18 11:27:45 +0100177 }
178 break;
179 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000180 case IrOpcode::kStore:
181 case IrOpcode::kUnalignedStore: {
182 MachineRepresentation rep;
183 if (node->opcode() == IrOpcode::kStore) {
184 rep = StoreRepresentationOf(node->op()).representation();
185 } else {
186 DCHECK(node->opcode() == IrOpcode::kUnalignedStore);
187 rep = UnalignedStoreRepresentationOf(node->op());
188 }
189
190 if (rep == MachineRepresentation::kWord64) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100191 // We change the original store node to store the low word, and create
192 // a new store node to store the high word. The effect and control edges
193 // are copied from the original store to the new store node, the effect
194 // edge of the original store is redirected to the new store.
Ben Murdoch109988c2016-05-18 11:27:45 +0100195 Node* base = node->InputAt(0);
196 Node* index = node->InputAt(1);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100197 Node* index_low;
198 Node* index_high;
199 GetIndexNodes(index, index_low, index_high);
Ben Murdoch109988c2016-05-18 11:27:45 +0100200 Node* value = node->InputAt(2);
201 DCHECK(HasReplacementLow(value));
202 DCHECK(HasReplacementHigh(value));
203
Ben Murdochf91f0612016-11-29 16:50:11 +0000204 const Operator* store_op;
205 if (node->opcode() == IrOpcode::kStore) {
206 WriteBarrierKind write_barrier_kind =
207 StoreRepresentationOf(node->op()).write_barrier_kind();
208 store_op = machine()->Store(StoreRepresentation(
209 MachineRepresentation::kWord32, write_barrier_kind));
210 } else {
211 DCHECK(node->opcode() == IrOpcode::kUnalignedStore);
212 store_op = machine()->UnalignedStore(MachineRepresentation::kWord32);
213 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100214
215 Node* high_node;
216 if (node->InputCount() > 3) {
217 Node* effect_high = node->InputAt(3);
218 Node* control_high = node->InputAt(4);
219 high_node = graph()->NewNode(store_op, base, index_high,
220 GetReplacementHigh(value), effect_high,
221 control_high);
222 node->ReplaceInput(3, high_node);
223
224 } else {
225 high_node = graph()->NewNode(store_op, base, index_high,
226 GetReplacementHigh(value));
227 }
228
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100229 node->ReplaceInput(1, index_low);
Ben Murdoch109988c2016-05-18 11:27:45 +0100230 node->ReplaceInput(2, GetReplacementLow(value));
231 NodeProperties::ChangeOp(node, store_op);
232 ReplaceNode(node, node, high_node);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100233 } else {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100234 if (HasReplacementLow(node->InputAt(2))) {
235 node->ReplaceInput(2, GetReplacementLow(node->InputAt(2)));
236 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100237 }
238 break;
239 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100240 case IrOpcode::kStart: {
241 int parameter_count = GetParameterCountAfterLowering(signature());
242 // Only exchange the node if the parameter count actually changed.
243 if (parameter_count != signature()->parameter_count()) {
244 int delta =
245 parameter_count - static_cast<int>(signature()->parameter_count());
246 int new_output_count = node->op()->ValueOutputCount() + delta;
247 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
248 }
249 break;
250 }
251 case IrOpcode::kParameter: {
252 DCHECK(node->InputCount() == 1);
253 // Only exchange the node if the parameter count actually changed. We do
254 // not even have to do the default lowering because the the start node,
255 // the only input of a parameter node, only changes if the parameter count
256 // changes.
257 if (GetParameterCountAfterLowering(signature()) !=
258 signature()->parameter_count()) {
259 int old_index = ParameterIndexOf(node->op());
260 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
261 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
262
263 Node* high_node = nullptr;
264 if (signature()->GetParam(old_index) ==
265 MachineRepresentation::kWord64) {
266 high_node = graph()->NewNode(common()->Parameter(new_index + 1),
267 graph()->start());
268 }
269 ReplaceNode(node, node, high_node);
270 }
271 break;
272 }
273 case IrOpcode::kReturn: {
274 DefaultLowering(node);
275 int new_return_count = GetReturnCountAfterLowering(signature());
276 if (signature()->return_count() != new_return_count) {
277 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
278 }
279 break;
280 }
281 case IrOpcode::kCall: {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100282 // TODO(turbofan): Make WASM code const-correct wrt. CallDescriptor.
283 CallDescriptor* descriptor =
284 const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
Ben Murdoch109988c2016-05-18 11:27:45 +0100285 if (DefaultLowering(node) ||
286 (descriptor->ReturnCount() == 1 &&
287 descriptor->GetReturnType(0) == MachineType::Int64())) {
288 // We have to adjust the call descriptor.
289 const Operator* op = common()->Call(
290 wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
291 NodeProperties::ChangeOp(node, op);
292 }
293 if (descriptor->ReturnCount() == 1 &&
294 descriptor->GetReturnType(0) == MachineType::Int64()) {
295 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100296 Node* low_node =
297 graph()->NewNode(common()->Projection(0), node, graph()->start());
298 Node* high_node =
299 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch109988c2016-05-18 11:27:45 +0100300 ReplaceNode(node, low_node, high_node);
301 }
302 break;
303 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100304 case IrOpcode::kWord64And: {
305 DCHECK(node->InputCount() == 2);
306 Node* left = node->InputAt(0);
307 Node* right = node->InputAt(1);
308
309 Node* low_node =
310 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
311 GetReplacementLow(right));
312 Node* high_node =
313 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
314 GetReplacementHigh(right));
315 ReplaceNode(node, low_node, high_node);
316 break;
317 }
318 case IrOpcode::kTruncateInt64ToInt32: {
319 DCHECK(node->InputCount() == 1);
320 Node* input = node->InputAt(0);
321 ReplaceNode(node, GetReplacementLow(input), nullptr);
322 node->NullAllInputs();
323 break;
324 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100325 case IrOpcode::kInt64Add: {
326 DCHECK(node->InputCount() == 2);
327
328 Node* right = node->InputAt(1);
329 node->ReplaceInput(1, GetReplacementLow(right));
330 node->AppendInput(zone(), GetReplacementHigh(right));
331
332 Node* left = node->InputAt(0);
333 node->ReplaceInput(0, GetReplacementLow(left));
334 node->InsertInput(zone(), 1, GetReplacementHigh(left));
335
336 NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
337 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100338 Node* low_node =
339 graph()->NewNode(common()->Projection(0), node, graph()->start());
340 Node* high_node =
341 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100342 ReplaceNode(node, low_node, high_node);
343 break;
344 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100345 case IrOpcode::kInt64Sub: {
346 DCHECK(node->InputCount() == 2);
347
348 Node* right = node->InputAt(1);
349 node->ReplaceInput(1, GetReplacementLow(right));
350 node->AppendInput(zone(), GetReplacementHigh(right));
351
352 Node* left = node->InputAt(0);
353 node->ReplaceInput(0, GetReplacementLow(left));
354 node->InsertInput(zone(), 1, GetReplacementHigh(left));
355
356 NodeProperties::ChangeOp(node, machine()->Int32PairSub());
357 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100358 Node* low_node =
359 graph()->NewNode(common()->Projection(0), node, graph()->start());
360 Node* high_node =
361 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100362 ReplaceNode(node, low_node, high_node);
363 break;
364 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100365 case IrOpcode::kInt64Mul: {
366 DCHECK(node->InputCount() == 2);
367
368 Node* right = node->InputAt(1);
369 node->ReplaceInput(1, GetReplacementLow(right));
370 node->AppendInput(zone(), GetReplacementHigh(right));
371
372 Node* left = node->InputAt(0);
373 node->ReplaceInput(0, GetReplacementLow(left));
374 node->InsertInput(zone(), 1, GetReplacementHigh(left));
375
376 NodeProperties::ChangeOp(node, machine()->Int32PairMul());
377 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100378 Node* low_node =
379 graph()->NewNode(common()->Projection(0), node, graph()->start());
380 Node* high_node =
381 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100382 ReplaceNode(node, low_node, high_node);
383 break;
384 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100385 case IrOpcode::kWord64Or: {
386 DCHECK(node->InputCount() == 2);
387 Node* left = node->InputAt(0);
388 Node* right = node->InputAt(1);
389
390 Node* low_node =
391 graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
392 GetReplacementLow(right));
393 Node* high_node =
394 graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
395 GetReplacementHigh(right));
396 ReplaceNode(node, low_node, high_node);
397 break;
398 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100399 case IrOpcode::kWord64Xor: {
400 DCHECK(node->InputCount() == 2);
401 Node* left = node->InputAt(0);
402 Node* right = node->InputAt(1);
403
404 Node* low_node =
405 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
406 GetReplacementLow(right));
407 Node* high_node =
408 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
409 GetReplacementHigh(right));
410 ReplaceNode(node, low_node, high_node);
411 break;
412 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100413 case IrOpcode::kWord64Shl: {
414 // TODO(turbofan): if the shift count >= 32, then we can set the low word
415 // of the output to 0 and just calculate the high word.
416 DCHECK(node->InputCount() == 2);
417 Node* shift = node->InputAt(1);
418 if (HasReplacementLow(shift)) {
419 // We do not have to care about the high word replacement, because
420 // the shift can only be between 0 and 63 anyways.
421 node->ReplaceInput(1, GetReplacementLow(shift));
422 }
423
424 Node* value = node->InputAt(0);
425 node->ReplaceInput(0, GetReplacementLow(value));
426 node->InsertInput(zone(), 1, GetReplacementHigh(value));
427
428 NodeProperties::ChangeOp(node, machine()->Word32PairShl());
429 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100430 Node* low_node =
431 graph()->NewNode(common()->Projection(0), node, graph()->start());
432 Node* high_node =
433 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100434 ReplaceNode(node, low_node, high_node);
435 break;
436 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100437 case IrOpcode::kWord64Shr: {
438 // TODO(turbofan): if the shift count >= 32, then we can set the low word
439 // of the output to 0 and just calculate the high word.
440 DCHECK(node->InputCount() == 2);
441 Node* shift = node->InputAt(1);
442 if (HasReplacementLow(shift)) {
443 // We do not have to care about the high word replacement, because
444 // the shift can only be between 0 and 63 anyways.
445 node->ReplaceInput(1, GetReplacementLow(shift));
446 }
447
448 Node* value = node->InputAt(0);
449 node->ReplaceInput(0, GetReplacementLow(value));
450 node->InsertInput(zone(), 1, GetReplacementHigh(value));
451
452 NodeProperties::ChangeOp(node, machine()->Word32PairShr());
453 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100454 Node* low_node =
455 graph()->NewNode(common()->Projection(0), node, graph()->start());
456 Node* high_node =
457 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100458 ReplaceNode(node, low_node, high_node);
459 break;
460 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100461 case IrOpcode::kWord64Sar: {
462 // TODO(turbofan): if the shift count >= 32, then we can set the low word
463 // of the output to 0 and just calculate the high word.
464 DCHECK(node->InputCount() == 2);
465 Node* shift = node->InputAt(1);
466 if (HasReplacementLow(shift)) {
467 // We do not have to care about the high word replacement, because
468 // the shift can only be between 0 and 63 anyways.
469 node->ReplaceInput(1, GetReplacementLow(shift));
470 }
471
472 Node* value = node->InputAt(0);
473 node->ReplaceInput(0, GetReplacementLow(value));
474 node->InsertInput(zone(), 1, GetReplacementHigh(value));
475
476 NodeProperties::ChangeOp(node, machine()->Word32PairSar());
477 // We access the additional return values through projections.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100478 Node* low_node =
479 graph()->NewNode(common()->Projection(0), node, graph()->start());
480 Node* high_node =
481 graph()->NewNode(common()->Projection(1), node, graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100482 ReplaceNode(node, low_node, high_node);
483 break;
484 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100485 case IrOpcode::kWord64Equal: {
486 DCHECK(node->InputCount() == 2);
487 Node* left = node->InputAt(0);
488 Node* right = node->InputAt(1);
489
490 // TODO(wasm): Use explicit comparisons and && here?
491 Node* replacement = graph()->NewNode(
492 machine()->Word32Equal(),
493 graph()->NewNode(
494 machine()->Word32Or(),
495 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
496 GetReplacementLow(right)),
497 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
498 GetReplacementHigh(right))),
499 graph()->NewNode(common()->Int32Constant(0)));
500
501 ReplaceNode(node, replacement, nullptr);
502 break;
503 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100504 case IrOpcode::kInt64LessThan: {
505 LowerComparison(node, machine()->Int32LessThan(),
506 machine()->Uint32LessThan());
507 break;
508 }
509 case IrOpcode::kInt64LessThanOrEqual: {
510 LowerComparison(node, machine()->Int32LessThan(),
511 machine()->Uint32LessThanOrEqual());
512 break;
513 }
514 case IrOpcode::kUint64LessThan: {
515 LowerComparison(node, machine()->Uint32LessThan(),
516 machine()->Uint32LessThan());
517 break;
518 }
519 case IrOpcode::kUint64LessThanOrEqual: {
520 LowerComparison(node, machine()->Uint32LessThan(),
521 machine()->Uint32LessThanOrEqual());
522 break;
523 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100524 case IrOpcode::kChangeInt32ToInt64: {
525 DCHECK(node->InputCount() == 1);
526 Node* input = node->InputAt(0);
527 if (HasReplacementLow(input)) {
528 input = GetReplacementLow(input);
529 }
530 // We use SAR to preserve the sign in the high word.
531 ReplaceNode(
532 node, input,
533 graph()->NewNode(machine()->Word32Sar(), input,
534 graph()->NewNode(common()->Int32Constant(31))));
535 node->NullAllInputs();
536 break;
537 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100538 case IrOpcode::kChangeUint32ToUint64: {
539 DCHECK(node->InputCount() == 1);
540 Node* input = node->InputAt(0);
541 if (HasReplacementLow(input)) {
542 input = GetReplacementLow(input);
543 }
544 ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
545 node->NullAllInputs();
546 break;
547 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100548 case IrOpcode::kBitcastInt64ToFloat64: {
549 DCHECK(node->InputCount() == 1);
550 Node* input = node->InputAt(0);
551 Node* stack_slot = graph()->NewNode(
552 machine()->StackSlot(MachineRepresentation::kWord64));
553
554 Node* store_high_word = graph()->NewNode(
555 machine()->Store(
556 StoreRepresentation(MachineRepresentation::kWord32,
557 WriteBarrierKind::kNoWriteBarrier)),
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100558 stack_slot,
559 graph()->NewNode(common()->Int32Constant(kHigherWordOffset)),
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100560 GetReplacementHigh(input), graph()->start(), graph()->start());
561
562 Node* store_low_word = graph()->NewNode(
563 machine()->Store(
564 StoreRepresentation(MachineRepresentation::kWord32,
565 WriteBarrierKind::kNoWriteBarrier)),
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100566 stack_slot,
567 graph()->NewNode(common()->Int32Constant(kLowerWordOffset)),
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100568 GetReplacementLow(input), store_high_word, graph()->start());
569
570 Node* load =
571 graph()->NewNode(machine()->Load(MachineType::Float64()), stack_slot,
572 graph()->NewNode(common()->Int32Constant(0)),
573 store_low_word, graph()->start());
574
575 ReplaceNode(node, load, nullptr);
576 break;
577 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100578 case IrOpcode::kBitcastFloat64ToInt64: {
579 DCHECK(node->InputCount() == 1);
580 Node* input = node->InputAt(0);
581 if (HasReplacementLow(input)) {
582 input = GetReplacementLow(input);
583 }
584 Node* stack_slot = graph()->NewNode(
585 machine()->StackSlot(MachineRepresentation::kWord64));
586 Node* store = graph()->NewNode(
587 machine()->Store(
588 StoreRepresentation(MachineRepresentation::kFloat64,
589 WriteBarrierKind::kNoWriteBarrier)),
590 stack_slot, graph()->NewNode(common()->Int32Constant(0)), input,
591 graph()->start(), graph()->start());
592
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100593 Node* high_node = graph()->NewNode(
594 machine()->Load(MachineType::Int32()), stack_slot,
595 graph()->NewNode(common()->Int32Constant(kHigherWordOffset)), store,
596 graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100597
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100598 Node* low_node = graph()->NewNode(
599 machine()->Load(MachineType::Int32()), stack_slot,
600 graph()->NewNode(common()->Int32Constant(kLowerWordOffset)), store,
601 graph()->start());
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100602 ReplaceNode(node, low_node, high_node);
603 break;
604 }
605 case IrOpcode::kWord64Ror: {
606 DCHECK(node->InputCount() == 2);
607 Node* input = node->InputAt(0);
608 Node* shift = HasReplacementLow(node->InputAt(1))
609 ? GetReplacementLow(node->InputAt(1))
610 : node->InputAt(1);
611 Int32Matcher m(shift);
612 if (m.HasValue()) {
613 // Precondition: 0 <= shift < 64.
614 int32_t shift_value = m.Value() & 0x3f;
615 if (shift_value == 0) {
616 ReplaceNode(node, GetReplacementLow(input),
617 GetReplacementHigh(input));
618 } else if (shift_value == 32) {
619 ReplaceNode(node, GetReplacementHigh(input),
620 GetReplacementLow(input));
621 } else {
622 Node* low_input;
623 Node* high_input;
624 if (shift_value < 32) {
625 low_input = GetReplacementLow(input);
626 high_input = GetReplacementHigh(input);
627 } else {
628 low_input = GetReplacementHigh(input);
629 high_input = GetReplacementLow(input);
630 }
631 int32_t masked_shift_value = shift_value & 0x1f;
632 Node* masked_shift =
633 graph()->NewNode(common()->Int32Constant(masked_shift_value));
634 Node* inv_shift = graph()->NewNode(
635 common()->Int32Constant(32 - masked_shift_value));
636
637 Node* low_node = graph()->NewNode(
638 machine()->Word32Or(),
639 graph()->NewNode(machine()->Word32Shr(), low_input, masked_shift),
640 graph()->NewNode(machine()->Word32Shl(), high_input, inv_shift));
641 Node* high_node = graph()->NewNode(
642 machine()->Word32Or(), graph()->NewNode(machine()->Word32Shr(),
643 high_input, masked_shift),
644 graph()->NewNode(machine()->Word32Shl(), low_input, inv_shift));
645 ReplaceNode(node, low_node, high_node);
646 }
647 } else {
648 Node* safe_shift = shift;
649 if (!machine()->Word32ShiftIsSafe()) {
650 safe_shift =
651 graph()->NewNode(machine()->Word32And(), shift,
652 graph()->NewNode(common()->Int32Constant(0x1f)));
653 }
654
655 // By creating this bit-mask with SAR and SHL we do not have to deal
656 // with shift == 0 as a special case.
657 Node* inv_mask = graph()->NewNode(
658 machine()->Word32Shl(),
659 graph()->NewNode(machine()->Word32Sar(),
660 graph()->NewNode(common()->Int32Constant(
661 std::numeric_limits<int32_t>::min())),
662 safe_shift),
663 graph()->NewNode(common()->Int32Constant(1)));
664
665 Node* bit_mask =
666 graph()->NewNode(machine()->Word32Xor(), inv_mask,
667 graph()->NewNode(common()->Int32Constant(-1)));
668
669 // We have to mask the shift value for this comparison. If
670 // !machine()->Word32ShiftIsSafe() then the masking should already be
671 // part of the graph.
672 Node* masked_shift6 = shift;
673 if (machine()->Word32ShiftIsSafe()) {
674 masked_shift6 =
675 graph()->NewNode(machine()->Word32And(), shift,
676 graph()->NewNode(common()->Int32Constant(0x3f)));
677 }
678
679 Diamond lt32(
680 graph(), common(),
681 graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
682 graph()->NewNode(common()->Int32Constant(32))));
683
684 // The low word and the high word can be swapped either at the input or
685 // at the output. We swap the inputs so that shift does not have to be
686 // kept for so long in a register.
687 Node* input_low =
688 lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
689 GetReplacementHigh(input));
690 Node* input_high =
691 lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
692 GetReplacementLow(input));
693
694 Node* rotate_low =
695 graph()->NewNode(machine()->Word32Ror(), input_low, safe_shift);
696 Node* rotate_high =
697 graph()->NewNode(machine()->Word32Ror(), input_high, safe_shift);
698
699 Node* low_node = graph()->NewNode(
700 machine()->Word32Or(),
701 graph()->NewNode(machine()->Word32And(), rotate_low, bit_mask),
702 graph()->NewNode(machine()->Word32And(), rotate_high, inv_mask));
703
704 Node* high_node = graph()->NewNode(
705 machine()->Word32Or(),
706 graph()->NewNode(machine()->Word32And(), rotate_high, bit_mask),
707 graph()->NewNode(machine()->Word32And(), rotate_low, inv_mask));
708
709 ReplaceNode(node, low_node, high_node);
710 }
711 break;
712 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100713 case IrOpcode::kWord64Clz: {
714 DCHECK(node->InputCount() == 1);
715 Node* input = node->InputAt(0);
716 Diamond d(
717 graph(), common(),
718 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
719 graph()->NewNode(common()->Int32Constant(0))));
720
721 Node* low_node = d.Phi(
722 MachineRepresentation::kWord32,
723 graph()->NewNode(machine()->Int32Add(),
724 graph()->NewNode(machine()->Word32Clz(),
725 GetReplacementLow(input)),
726 graph()->NewNode(common()->Int32Constant(32))),
727 graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
728 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
729 break;
730 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100731 case IrOpcode::kWord64Ctz: {
732 DCHECK(node->InputCount() == 1);
733 DCHECK(machine()->Word32Ctz().IsSupported());
734 Node* input = node->InputAt(0);
735 Diamond d(
736 graph(), common(),
737 graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
738 graph()->NewNode(common()->Int32Constant(0))));
739 Node* low_node =
740 d.Phi(MachineRepresentation::kWord32,
741 graph()->NewNode(machine()->Int32Add(),
742 graph()->NewNode(machine()->Word32Ctz().op(),
743 GetReplacementHigh(input)),
744 graph()->NewNode(common()->Int32Constant(32))),
745 graph()->NewNode(machine()->Word32Ctz().op(),
746 GetReplacementLow(input)));
747 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
748 break;
749 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100750 case IrOpcode::kWord64Popcnt: {
751 DCHECK(node->InputCount() == 1);
752 Node* input = node->InputAt(0);
753 // We assume that a Word64Popcnt node only has been created if
754 // Word32Popcnt is actually supported.
755 DCHECK(machine()->Word32Popcnt().IsSupported());
756 ReplaceNode(node, graph()->NewNode(
757 machine()->Int32Add(),
758 graph()->NewNode(machine()->Word32Popcnt().op(),
759 GetReplacementLow(input)),
760 graph()->NewNode(machine()->Word32Popcnt().op(),
761 GetReplacementHigh(input))),
762 graph()->NewNode(common()->Int32Constant(0)));
763 break;
764 }
765 case IrOpcode::kPhi: {
766 MachineRepresentation rep = PhiRepresentationOf(node->op());
767 if (rep == MachineRepresentation::kWord64) {
768 // The replacement nodes have already been created, we only have to
769 // replace placeholder nodes.
770 Node* low_node = GetReplacementLow(node);
771 Node* high_node = GetReplacementHigh(node);
772 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
773 low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
774 high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
775 }
776 } else {
777 DefaultLowering(node);
778 }
779 break;
780 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000781 case IrOpcode::kWord64ReverseBytes: {
782 Node* input = node->InputAt(0);
783 ReplaceNode(node, graph()->NewNode(machine()->Word32ReverseBytes().op(),
784 GetReplacementHigh(input)),
785 graph()->NewNode(machine()->Word32ReverseBytes().op(),
786 GetReplacementLow(input)));
787 break;
788 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100789
Ben Murdoch109988c2016-05-18 11:27:45 +0100790 default: { DefaultLowering(node); }
791 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100792} // NOLINT(readability/fn_size)
793
794void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
795 const Operator* low_word_op) {
796 DCHECK(node->InputCount() == 2);
797 Node* left = node->InputAt(0);
798 Node* right = node->InputAt(1);
799 Node* replacement = graph()->NewNode(
800 machine()->Word32Or(),
801 graph()->NewNode(high_word_op, GetReplacementHigh(left),
802 GetReplacementHigh(right)),
803 graph()->NewNode(
804 machine()->Word32And(),
805 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
806 GetReplacementHigh(right)),
807 graph()->NewNode(low_word_op, GetReplacementLow(left),
808 GetReplacementLow(right))));
809
810 ReplaceNode(node, replacement, nullptr);
Ben Murdoch109988c2016-05-18 11:27:45 +0100811}
812
813bool Int64Lowering::DefaultLowering(Node* node) {
814 bool something_changed = false;
815 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
816 Node* input = node->InputAt(i);
817 if (HasReplacementLow(input)) {
818 something_changed = true;
819 node->ReplaceInput(i, GetReplacementLow(input));
820 }
821 if (HasReplacementHigh(input)) {
822 something_changed = true;
823 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
824 }
825 }
826 return something_changed;
827}
828
829void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
830 // if new_low == nullptr, then also new_high == nullptr.
831 DCHECK(new_low != nullptr || new_high == nullptr);
832 replacements_[old->id()].low = new_low;
833 replacements_[old->id()].high = new_high;
834}
835
836bool Int64Lowering::HasReplacementLow(Node* node) {
837 return replacements_[node->id()].low != nullptr;
838}
839
840Node* Int64Lowering::GetReplacementLow(Node* node) {
841 Node* result = replacements_[node->id()].low;
842 DCHECK(result);
843 return result;
844}
845
846bool Int64Lowering::HasReplacementHigh(Node* node) {
847 return replacements_[node->id()].high != nullptr;
848}
849
850Node* Int64Lowering::GetReplacementHigh(Node* node) {
851 Node* result = replacements_[node->id()].high;
852 DCHECK(result);
853 return result;
854}
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100855
856void Int64Lowering::PreparePhiReplacement(Node* phi) {
857 MachineRepresentation rep = PhiRepresentationOf(phi->op());
858 if (rep == MachineRepresentation::kWord64) {
859 // We have to create the replacements for a phi node before we actually
860 // lower the phi to break potential cycles in the graph. The replacements of
861 // input nodes do not exist yet, so we use a placeholder node to pass the
862 // graph verifier.
863 int value_count = phi->op()->ValueInputCount();
864 Node** inputs_low = zone()->NewArray<Node*>(value_count + 1);
865 Node** inputs_high = zone()->NewArray<Node*>(value_count + 1);
866 for (int i = 0; i < value_count; i++) {
867 inputs_low[i] = placeholder_;
868 inputs_high[i] = placeholder_;
869 }
870 inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
871 inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
872 ReplaceNode(phi,
873 graph()->NewNode(
874 common()->Phi(MachineRepresentation::kWord32, value_count),
875 value_count + 1, inputs_low, false),
876 graph()->NewNode(
877 common()->Phi(MachineRepresentation::kWord32, value_count),
878 value_count + 1, inputs_high, false));
879 }
880}
Ben Murdoch109988c2016-05-18 11:27:45 +0100881} // namespace compiler
882} // namespace internal
883} // namespace v8