v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
int64-lowering.cc
Go to the documentation of this file.
1// 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
6
13#include "src/compiler/node.h"
18// TODO(wasm): Remove this include.
21#include "src/zone/zone.h"
22
23#if V8_TARGET_ARCH_32_BIT
24
25namespace v8 {
26namespace internal {
27namespace compiler {
28
29Int64Lowering::Int64Lowering(TFGraph* graph, MachineOperatorBuilder* machine,
30 CommonOperatorBuilder* common,
31 SimplifiedOperatorBuilder* simplified, Zone* zone,
32 Signature<MachineRepresentation>* signature)
33 : graph_(graph),
34 machine_(machine),
35 common_(common),
36 simplified_(simplified),
37 zone_(zone),
38 signature_(signature),
39 state_(graph->NodeCount(), State::kUnvisited),
40 stack_(zone),
41 replacements_(nullptr),
42 placeholder_(graph->NewNode(common->Dead())) {
43 DCHECK_NOT_NULL(graph);
44 DCHECK_NOT_NULL(graph->end());
45 replacements_ = zone->AllocateArray<Replacement>(graph->NodeCount());
46 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
47}
48
49void Int64Lowering::LowerGraph() {
50 stack_.push_back({graph()->end(), 0});
51 state_[graph()->end()->id()] = State::kOnStack;
52
53 while (!stack_.empty()) {
54 NodeState& top = stack_.back();
55 if (top.input_index == top.node->InputCount()) {
56 // All inputs of top have already been lowered, now lower top.
57 Node* node = top.node;
58 stack_.pop_back();
59 state_[node->id()] = State::kVisited;
60 LowerNode(node);
61 } else {
62 // Push the next input onto the stack.
63 Node* input = top.node->InputAt(top.input_index++);
64 if (state_[input->id()] == State::kUnvisited) {
65 if (input->opcode() == IrOpcode::kPhi) {
66 // To break cycles with phi nodes we push phis on a separate stack so
67 // that they are processed after all other nodes.
68 PreparePhiReplacement(input);
69 stack_.push_front({input, 0});
70 } else if (input->opcode() == IrOpcode::kEffectPhi ||
71 input->opcode() == IrOpcode::kLoop) {
72 stack_.push_front({input, 0});
73 } else {
74 stack_.push_back({input, 0});
75 }
76 state_[input->id()] = State::kOnStack;
77 }
78 }
79 }
80}
81
82namespace {
83
84int GetReturnIndexAfterLowering(const CallDescriptor* call_descriptor,
85 int old_index) {
86 int result = old_index;
87 for (int i = 0; i < old_index; i++) {
88 if (call_descriptor->GetReturnType(i).representation() ==
89 MachineRepresentation::kWord64) {
90 result++;
91 }
92 }
93 return result;
94}
95
96int GetReturnCountAfterLowering(const CallDescriptor* call_descriptor) {
97 return GetReturnIndexAfterLowering(
98 call_descriptor, static_cast<int>(call_descriptor->ReturnCount()));
99}
100
101int GetParameterIndexAfterLowering(
102 Signature<MachineRepresentation>* signature, int old_index) {
103 int result = old_index;
104 // Be robust towards special indexes (>= param count).
105 int max_to_check =
106 std::min(old_index, static_cast<int>(signature->parameter_count()));
107 for (int i = 0; i < max_to_check; i++) {
108 if (signature->GetParam(i) == MachineRepresentation::kWord64) {
109 result++;
110 }
111 }
112 return result;
113}
114
115int GetReturnCountAfterLowering(Signature<MachineRepresentation>* signature) {
116 int result = static_cast<int>(signature->return_count());
117 for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
118 if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
119 result++;
120 }
121 }
122 return result;
123}
124
125} // namespace
126
127void Int64Lowering::LowerWord64AtomicBinop(Node* node, const Operator* op) {
128 DCHECK_EQ(5, node->InputCount());
129 LowerMemoryBaseAndIndex(node);
130 Node* value = node->InputAt(2);
131 node->ReplaceInput(2, GetReplacementLow(value));
132 node->InsertInput(zone(), 3, GetReplacementHigh(value));
133 NodeProperties::ChangeOp(node, op);
134 ReplaceNodeWithProjections(node);
135}
136
137void Int64Lowering::LowerWord64AtomicNarrowOp(Node* node, const Operator* op) {
138 DefaultLowering(node, true);
139 NodeProperties::ChangeOp(node, op);
140 ReplaceNode(node, node, graph()->NewNode(common()->Int32Constant(0)));
141}
142
143// static
144int Int64Lowering::GetParameterCountAfterLowering(
145 Signature<MachineRepresentation>* signature) {
146 // GetParameterIndexAfterLowering(parameter_count) returns the parameter count
147 // after lowering.
148 return GetParameterIndexAfterLowering(
149 signature, static_cast<int>(signature->parameter_count()));
150}
151
152void Int64Lowering::GetIndexNodes(Node* index, Node** index_low,
153 Node** index_high) {
154 // We want to transform constant indices into constant indices, because
155 // wasm-typer depends on them.
156 Int32Matcher m(index);
157 Node* index_second =
158 m.HasResolvedValue()
159 ? graph()->NewNode(common()->Int32Constant(m.ResolvedValue() + 4))
160 : graph()->NewNode(machine()->Int32Add(), index,
161 graph()->NewNode(common()->Int32Constant(4)));
162#if defined(V8_TARGET_LITTLE_ENDIAN)
163 *index_low = index;
164 *index_high = index_second;
165#elif defined(V8_TARGET_BIG_ENDIAN)
166 *index_low = index_second;
167 *index_high = index;
168#endif
169}
170
171void Int64Lowering::LowerLoadOperator(Node* node, MachineRepresentation rep,
172 const Operator* load_op) {
173 if (rep == MachineRepresentation::kWord64) {
174 LowerMemoryBaseAndIndex(node);
175 Node* base = node->InputAt(0);
176 Node* index = node->InputAt(1);
177 Node* index_low;
178 Node* index_high;
179 GetIndexNodes(index, &index_low, &index_high);
180 Node* high_node;
181 if (node->InputCount() > 2) {
182 Node* effect_high = node->InputAt(2);
183 Node* control_high = node->InputAt(3);
184 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
185 control_high);
186 // change the effect change from old_node --> old_effect to
187 // old_node --> high_node --> old_effect.
188 node->ReplaceInput(2, high_node);
189 } else {
190 high_node = graph()->NewNode(load_op, base, index_high);
191 }
192 node->ReplaceInput(1, index_low);
193 NodeProperties::ChangeOp(node, load_op);
194 ReplaceNode(node, node, high_node);
195 } else {
196 DefaultLowering(node);
197 }
198}
199
200void Int64Lowering::LowerStoreOperator(Node* node, MachineRepresentation rep,
201 const Operator* store_op) {
202 if (rep == MachineRepresentation::kWord64) {
203 // We change the original store node to store the low word, and create
204 // a new store node to store the high word. The effect and control edges
205 // are copied from the original store to the new store node, the effect
206 // edge of the original store is redirected to the new store.
207 LowerMemoryBaseAndIndex(node);
208 Node* base = node->InputAt(0);
209 Node* index = node->InputAt(1);
210 Node* index_low;
211 Node* index_high;
212 GetIndexNodes(index, &index_low, &index_high);
213 Node* value = node->InputAt(2);
214 DCHECK(HasReplacementLow(value));
215 DCHECK(HasReplacementHigh(value));
216
217 Node* high_node;
218 if (node->InputCount() > 3) {
219 Node* effect_high = node->InputAt(3);
220 Node* control_high = node->InputAt(4);
221 high_node = graph()->NewNode(store_op, base, index_high,
222 GetReplacementHigh(value), effect_high,
223 control_high);
224 node->ReplaceInput(3, high_node);
225
226 } else {
227 high_node = graph()->NewNode(store_op, base, index_high,
228 GetReplacementHigh(value));
229 }
230
231 node->ReplaceInput(1, index_low);
232 node->ReplaceInput(2, GetReplacementLow(value));
233 NodeProperties::ChangeOp(node, store_op);
234 ReplaceNode(node, node, high_node);
235 } else {
236 DefaultLowering(node, true);
237 }
238}
239
240void Int64Lowering::LowerNode(Node* node) {
241 switch (node->opcode()) {
242 case IrOpcode::kInt64Constant: {
243 int64_t value = OpParameter<int64_t>(node->op());
244 Node* low_node = graph()->NewNode(
245 common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
246 Node* high_node = graph()->NewNode(
247 common()->Int32Constant(static_cast<int32_t>(value >> 32)));
248 ReplaceNode(node, low_node, high_node);
249 break;
250 }
251 case IrOpcode::kLoad: {
254 LowerLoadOperator(node, rep, machine()->Load(MachineType::Int32()));
255 break;
256 }
257 case IrOpcode::kUnalignedLoad: {
260 LowerLoadOperator(node, rep,
261 machine()->UnalignedLoad(MachineType::Int32()));
262 break;
263 }
264 case IrOpcode::kLoadImmutable: {
267 LowerLoadOperator(node, rep,
268 machine()->LoadImmutable(MachineType::Int32()));
269 break;
270 }
271 case IrOpcode::kLoadFromObject: {
272 ObjectAccess access = ObjectAccessOf(node->op());
273 LowerLoadOperator(node, access.machine_type.representation(),
274 simplified()->LoadFromObject(ObjectAccess(
275 MachineType::Int32(), access.write_barrier_kind)));
276 break;
277 }
278 case IrOpcode::kLoadImmutableFromObject: {
279 ObjectAccess access = ObjectAccessOf(node->op());
280 LowerLoadOperator(node, access.machine_type.representation(),
281 simplified()->LoadImmutableFromObject(ObjectAccess(
282 MachineType::Int32(), access.write_barrier_kind)));
283 break;
284 }
285 case IrOpcode::kStore: {
286 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
287 LowerStoreOperator(
288 node, store_rep.representation(),
289 machine()->Store(StoreRepresentation(
290 MachineRepresentation::kWord32, store_rep.write_barrier_kind())));
291 break;
292 }
293 case IrOpcode::kUnalignedStore: {
296 LowerStoreOperator(
297 node, store_rep,
298 machine()->UnalignedStore(MachineRepresentation::kWord32));
299 break;
300 }
301 case IrOpcode::kStoreToObject: {
302 ObjectAccess access = ObjectAccessOf(node->op());
303 LowerStoreOperator(node, access.machine_type.representation(),
304 simplified()->StoreToObject(ObjectAccess(
305 MachineType::Int32(), access.write_barrier_kind)));
306 break;
307 }
308 case IrOpcode::kInitializeImmutableInObject: {
309 ObjectAccess access = ObjectAccessOf(node->op());
310 LowerStoreOperator(node, access.machine_type.representation(),
311 simplified()->InitializeImmutableInObject(ObjectAccess(
312 MachineType::Int32(), access.write_barrier_kind)));
313 break;
314 }
315 case IrOpcode::kStart: {
316 int parameter_count = GetParameterCountAfterLowering(signature());
317 // Only exchange the node if the parameter count actually changed.
318 if (parameter_count != static_cast<int>(signature()->parameter_count())) {
319 int delta =
320 parameter_count - static_cast<int>(signature()->parameter_count());
321 int new_output_count = node->op()->ValueOutputCount() + delta;
322 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
323 }
324 break;
325 }
326 case IrOpcode::kParameter: {
327 DCHECK_EQ(1, node->InputCount());
328 int param_count = static_cast<int>(signature()->parameter_count());
329 // Only exchange the node if the parameter count actually changed. We do
330 // not even have to do the default lowering because the the start node,
331 // the only input of a parameter node, only changes if the parameter count
332 // changes.
333 if (GetParameterCountAfterLowering(signature()) != param_count) {
334 int old_index = ParameterIndexOf(node->op());
335 // Adjust old_index to be compliant with the signature.
336 --old_index;
337 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
338 // Adjust new_index to consider the instance parameter.
339 ++new_index;
340 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
341
342 if (old_index < 0 || old_index >= param_count) {
343 // Special parameters (JS closure/context) don't have kWord64
344 // representation anyway.
345 break;
346 }
347
348 if (signature()->GetParam(old_index) ==
349 MachineRepresentation::kWord64) {
350 Node* high_node = graph()->NewNode(common()->Parameter(new_index + 1),
351 graph()->start());
352 ReplaceNode(node, node, high_node);
353 }
354 }
355 break;
356 }
357 case IrOpcode::kReturn: {
358 int input_count = node->InputCount();
359 DefaultLowering(node);
360 if (input_count != node->InputCount()) {
361 int new_return_count = GetReturnCountAfterLowering(signature());
362 if (static_cast<int>(signature()->return_count()) != new_return_count) {
363 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
364 }
365 }
366 break;
367 }
368 case IrOpcode::kTailCall: {
369 auto call_descriptor =
370 const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
371 bool returns_require_lowering =
372 GetReturnCountAfterLowering(call_descriptor) !=
373 static_cast<int>(call_descriptor->ReturnCount());
374 if (DefaultLowering(node) || returns_require_lowering) {
375 // Tail calls do not have return values, so adjusting the call
376 // descriptor is enough.
377 NodeProperties::ChangeOp(
378 node, common()->TailCall(LowerCallDescriptor(call_descriptor)));
379 }
380 break;
381 }
382 case IrOpcode::kCall: {
383 auto call_descriptor = CallDescriptorOf(node->op());
384
385 bool returns_require_lowering =
386 GetReturnCountAfterLowering(call_descriptor) !=
387 static_cast<int>(call_descriptor->ReturnCount());
388 if (DefaultLowering(node) || returns_require_lowering) {
389 // We have to adjust the call descriptor.
390 NodeProperties::ChangeOp(
391 node, common()->Call(LowerCallDescriptor(call_descriptor)));
392 }
393 if (returns_require_lowering) {
394 size_t return_arity = call_descriptor->ReturnCount();
395 if (return_arity == 1) {
396 // We access the additional return values through projections.
397 ReplaceNodeWithProjections(node);
398 } else {
399 ZoneVector<Node*> projections(return_arity, zone());
400 NodeProperties::CollectValueProjections(node, projections.data(),
401 return_arity);
402 for (size_t old_index = 0, new_index = 0; old_index < return_arity;
403 ++old_index, ++new_index) {
404 Node* use_node = projections[old_index];
405 DCHECK_EQ(ProjectionIndexOf(use_node->op()), old_index);
406 DCHECK_EQ(GetReturnIndexAfterLowering(call_descriptor,
407 static_cast<int>(old_index)),
408 static_cast<int>(new_index));
409 if (new_index != old_index) {
410 NodeProperties::ChangeOp(
411 use_node, common()->Projection(new_index));
412 }
413 if (call_descriptor->GetReturnType(old_index).representation() ==
414 MachineRepresentation::kWord64) {
415 Node* high_node = graph()->NewNode(
416 common()->Projection(new_index + 1), node, graph()->start());
417 ReplaceNode(use_node, use_node, high_node);
418 ++new_index;
419 }
420 }
421 }
422 }
423 break;
424 }
425 case IrOpcode::kWord64And: {
426 DCHECK_EQ(2, node->InputCount());
427 Node* left = node->InputAt(0);
428 Node* right = node->InputAt(1);
429
430 Node* low_node =
431 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
432 GetReplacementLow(right));
433 Node* high_node =
434 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
435 GetReplacementHigh(right));
436 ReplaceNode(node, low_node, high_node);
437 break;
438 }
439 case IrOpcode::kTruncateInt64ToInt32: {
440 DCHECK_EQ(1, node->InputCount());
441 Node* input = node->InputAt(0);
442 ReplaceNode(node, GetReplacementLow(input), nullptr);
443 node->NullAllInputs();
444 break;
445 }
446 case IrOpcode::kInt64Add: {
447 DCHECK_EQ(2, node->InputCount());
448
449 Node* right = node->InputAt(1);
450 node->ReplaceInput(1, GetReplacementLow(right));
451 node->AppendInput(zone(), GetReplacementHigh(right));
452
453 Node* left = node->InputAt(0);
454 node->ReplaceInput(0, GetReplacementLow(left));
455 node->InsertInput(zone(), 1, GetReplacementHigh(left));
456
457 NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
458 // We access the additional return values through projections.
459 ReplaceNodeWithProjections(node);
460 break;
461 }
462 case IrOpcode::kInt64Sub: {
463 DCHECK_EQ(2, node->InputCount());
464
465 Node* right = node->InputAt(1);
466 node->ReplaceInput(1, GetReplacementLow(right));
467 node->AppendInput(zone(), GetReplacementHigh(right));
468
469 Node* left = node->InputAt(0);
470 node->ReplaceInput(0, GetReplacementLow(left));
471 node->InsertInput(zone(), 1, GetReplacementHigh(left));
472
473 NodeProperties::ChangeOp(node, machine()->Int32PairSub());
474 // We access the additional return values through projections.
475 ReplaceNodeWithProjections(node);
476 break;
477 }
478 case IrOpcode::kInt64Mul: {
479 DCHECK_EQ(2, node->InputCount());
480
481 Node* right = node->InputAt(1);
482 node->ReplaceInput(1, GetReplacementLow(right));
483 node->AppendInput(zone(), GetReplacementHigh(right));
484
485 Node* left = node->InputAt(0);
486 node->ReplaceInput(0, GetReplacementLow(left));
487 node->InsertInput(zone(), 1, GetReplacementHigh(left));
488
489 NodeProperties::ChangeOp(node, machine()->Int32PairMul());
490 // We access the additional return values through projections.
491 ReplaceNodeWithProjections(node);
492 break;
493 }
494 case IrOpcode::kWord64Or: {
495 DCHECK_EQ(2, node->InputCount());
496 Node* left = node->InputAt(0);
497 Node* right = node->InputAt(1);
498
499 Node* low_node =
500 graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
501 GetReplacementLow(right));
502 Node* high_node =
503 graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
504 GetReplacementHigh(right));
505 ReplaceNode(node, low_node, high_node);
506 break;
507 }
508 case IrOpcode::kWord64Xor: {
509 DCHECK_EQ(2, node->InputCount());
510 Node* left = node->InputAt(0);
511 Node* right = node->InputAt(1);
512
513 Node* low_node =
514 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
515 GetReplacementLow(right));
516 Node* high_node =
517 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
518 GetReplacementHigh(right));
519 ReplaceNode(node, low_node, high_node);
520 break;
521 }
522 case IrOpcode::kWord64Shl: {
523 // TODO(turbofan): if the shift count >= 32, then we can set the low word
524 // of the output to 0 and just calculate the high word.
525 DCHECK_EQ(2, node->InputCount());
526 Node* shift = node->InputAt(1);
527 if (HasReplacementLow(shift)) {
528 // We do not have to care about the high word replacement, because
529 // the shift can only be between 0 and 63 anyways.
530 node->ReplaceInput(1, GetReplacementLow(shift));
531 }
532
533 Node* value = node->InputAt(0);
534 node->ReplaceInput(0, GetReplacementLow(value));
535 node->InsertInput(zone(), 1, GetReplacementHigh(value));
536
537 NodeProperties::ChangeOp(node, machine()->Word32PairShl());
538 // We access the additional return values through projections.
539 ReplaceNodeWithProjections(node);
540 break;
541 }
542 case IrOpcode::kWord64Shr: {
543 // TODO(turbofan): if the shift count >= 32, then we can set the low word
544 // of the output to 0 and just calculate the high word.
545 DCHECK_EQ(2, node->InputCount());
546 Node* shift = node->InputAt(1);
547 if (HasReplacementLow(shift)) {
548 // We do not have to care about the high word replacement, because
549 // the shift can only be between 0 and 63 anyways.
550 node->ReplaceInput(1, GetReplacementLow(shift));
551 }
552
553 Node* value = node->InputAt(0);
554 node->ReplaceInput(0, GetReplacementLow(value));
555 node->InsertInput(zone(), 1, GetReplacementHigh(value));
556
557 NodeProperties::ChangeOp(node, machine()->Word32PairShr());
558 // We access the additional return values through projections.
559 ReplaceNodeWithProjections(node);
560 break;
561 }
562 case IrOpcode::kWord64Sar: {
563 // TODO(turbofan): if the shift count >= 32, then we can set the low word
564 // of the output to 0 and just calculate the high word.
565 DCHECK_EQ(2, node->InputCount());
566 Node* shift = node->InputAt(1);
567 if (HasReplacementLow(shift)) {
568 // We do not have to care about the high word replacement, because
569 // the shift can only be between 0 and 63 anyways.
570 node->ReplaceInput(1, GetReplacementLow(shift));
571 }
572
573 Node* value = node->InputAt(0);
574 node->ReplaceInput(0, GetReplacementLow(value));
575 node->InsertInput(zone(), 1, GetReplacementHigh(value));
576
577 NodeProperties::ChangeOp(node, machine()->Word32PairSar());
578 // We access the additional return values through projections.
579 ReplaceNodeWithProjections(node);
580 break;
581 }
582 case IrOpcode::kWord64Equal: {
583 DCHECK_EQ(2, node->InputCount());
584 Node* left = node->InputAt(0);
585 Node* right = node->InputAt(1);
586
587 // TODO(wasm): Use explicit comparisons and && here?
588 Node* replacement = graph()->NewNode(
589 machine()->Word32Equal(),
590 graph()->NewNode(
591 machine()->Word32Or(),
592 graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
593 GetReplacementLow(right)),
594 graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
595 GetReplacementHigh(right))),
596 graph()->NewNode(common()->Int32Constant(0)));
597 ReplaceNode(node, replacement, nullptr);
598 break;
599 }
600 case IrOpcode::kInt64LessThan: {
601 LowerComparison(node, machine()->Int32LessThan(),
602 machine()->Uint32LessThan());
603 break;
604 }
605 case IrOpcode::kInt64LessThanOrEqual: {
606 LowerComparison(node, machine()->Int32LessThan(),
607 machine()->Uint32LessThanOrEqual());
608 break;
609 }
610 case IrOpcode::kUint64LessThan: {
611 LowerComparison(node, machine()->Uint32LessThan(),
612 machine()->Uint32LessThan());
613 break;
614 }
615 case IrOpcode::kUint64LessThanOrEqual: {
616 LowerComparison(node, machine()->Uint32LessThan(),
617 machine()->Uint32LessThanOrEqual());
618 break;
619 }
620 case IrOpcode::kSignExtendWord32ToInt64:
621 case IrOpcode::kChangeInt32ToInt64: {
622 DCHECK_EQ(1, node->InputCount());
623 Node* input = node->InputAt(0);
624 if (HasReplacementLow(input)) {
625 input = GetReplacementLow(input);
626 }
627 // We use SAR to preserve the sign in the high word.
628 Node* high_node =
629 graph()->NewNode(machine()->Word32Sar(), input,
630 graph()->NewNode(common()->Int32Constant(31)));
631 ReplaceNode(node, input, high_node);
632 node->NullAllInputs();
633 break;
634 }
635 case IrOpcode::kChangeUint32ToUint64: {
636 DCHECK_EQ(1, node->InputCount());
637 Node* input = node->InputAt(0);
638 if (HasReplacementLow(input)) {
639 input = GetReplacementLow(input);
640 }
641 ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
642 node->NullAllInputs();
643 break;
644 }
645 case IrOpcode::kBitcastInt64ToFloat64: {
646 DCHECK_EQ(1, node->InputCount());
647 Node* input = node->InputAt(0);
648
649 Node* high_half =
650 graph()->NewNode(machine()->Float64InsertHighWord32(),
651 graph()->NewNode(common()->Float64Constant(0.0)),
652 GetReplacementHigh(input));
653 Node* result = graph()->NewNode(machine()->Float64InsertLowWord32(),
654 high_half, GetReplacementLow(input));
655 ReplaceNode(node, result, nullptr);
656 break;
657 }
658 case IrOpcode::kBitcastFloat64ToInt64: {
659 DCHECK_EQ(1, node->InputCount());
660 Node* input = node->InputAt(0);
661 if (HasReplacementLow(input)) {
662 input = GetReplacementLow(input);
663 }
664
665 Node* low_node =
666 graph()->NewNode(machine()->Float64ExtractLowWord32(), input);
667 Node* high_node =
668 graph()->NewNode(machine()->Float64ExtractHighWord32(), input);
669 ReplaceNode(node, low_node, high_node);
670 break;
671 }
672 case IrOpcode::kWord64RolLowerable:
673 DCHECK(machine()->Word32Rol().IsSupported());
674 [[fallthrough]];
675 case IrOpcode::kWord64RorLowerable: {
676 DCHECK_EQ(3, node->InputCount());
677 Node* input = node->InputAt(0);
678 Node* shift = HasReplacementLow(node->InputAt(1))
679 ? GetReplacementLow(node->InputAt(1))
680 : node->InputAt(1);
681 Int32Matcher m(shift);
682 if (m.HasResolvedValue()) {
683 // Precondition: 0 <= shift < 64.
684 int32_t shift_value = m.ResolvedValue() & 0x3F;
685 if (shift_value == 0) {
686 ReplaceNode(node, GetReplacementLow(input),
687 GetReplacementHigh(input));
688 } else if (shift_value == 32) {
689 ReplaceNode(node, GetReplacementHigh(input),
690 GetReplacementLow(input));
691 } else {
692 Node* low_input;
693 Node* high_input;
694 if (shift_value < 32) {
695 low_input = GetReplacementLow(input);
696 high_input = GetReplacementHigh(input);
697 } else {
698 low_input = GetReplacementHigh(input);
699 high_input = GetReplacementLow(input);
700 }
701 int32_t masked_shift_value = shift_value & 0x1F;
702 Node* masked_shift =
703 graph()->NewNode(common()->Int32Constant(masked_shift_value));
704 Node* inv_shift = graph()->NewNode(
705 common()->Int32Constant(32 - masked_shift_value));
706
707 auto* op1 = machine()->Word32Shr();
708 auto* op2 = machine()->Word32Shl();
709 bool is_ror = node->opcode() == IrOpcode::kWord64RorLowerable;
710 if (!is_ror) std::swap(op1, op2);
711
712 Node* low_node =
713 graph()->NewNode(machine()->Word32Or(),
714 graph()->NewNode(op1, low_input, masked_shift),
715 graph()->NewNode(op2, high_input, inv_shift));
716 Node* high_node =
717 graph()->NewNode(machine()->Word32Or(),
718 graph()->NewNode(op1, high_input, masked_shift),
719 graph()->NewNode(op2, low_input, inv_shift));
720 ReplaceNode(node, low_node, high_node);
721 }
722 } else {
723 Node* safe_shift = shift;
724 if (!machine()->Word32ShiftIsSafe()) {
725 safe_shift =
726 graph()->NewNode(machine()->Word32And(), shift,
727 graph()->NewNode(common()->Int32Constant(0x1F)));
728 }
729
730 bool is_ror = node->opcode() == IrOpcode::kWord64RorLowerable;
731 Node* inv_mask =
732 is_ror ? graph()->NewNode(
733 machine()->Word32Xor(),
734 graph()->NewNode(
735 machine()->Word32Shr(),
736 graph()->NewNode(common()->Int32Constant(-1)),
737 safe_shift),
738 graph()->NewNode(common()->Int32Constant(-1)))
739 : graph()->NewNode(
740 machine()->Word32Shl(),
741 graph()->NewNode(common()->Int32Constant(-1)),
742 safe_shift);
743
744 Node* bit_mask =
745 graph()->NewNode(machine()->Word32Xor(), inv_mask,
746 graph()->NewNode(common()->Int32Constant(-1)));
747
748 // We have to mask the shift value for this comparison. If
749 // !machine()->Word32ShiftIsSafe() then the masking should already be
750 // part of the graph.
751 Node* masked_shift6 = shift;
752 if (machine()->Word32ShiftIsSafe()) {
753 masked_shift6 =
754 graph()->NewNode(machine()->Word32And(), shift,
755 graph()->NewNode(common()->Int32Constant(0x3F)));
756 }
757
758 Diamond lt32(
759 graph(), common(),
760 graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
761 graph()->NewNode(common()->Int32Constant(32))));
762 lt32.Chain(NodeProperties::GetControlInput(node));
763
764 // The low word and the high word can be swapped either at the input or
765 // at the output. We swap the inputs so that shift does not have to be
766 // kept for so long in a register.
767 Node* input_low =
768 lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
769 GetReplacementHigh(input));
770 Node* input_high =
771 lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
772 GetReplacementLow(input));
773
774 const Operator* oper =
775 is_ror ? machine()->Word32Ror() : machine()->Word32Rol().op();
776
777 Node* rotate_low = graph()->NewNode(oper, input_low, safe_shift);
778 Node* rotate_high = graph()->NewNode(oper, input_high, safe_shift);
779
780 auto* mask1 = bit_mask;
781 auto* mask2 = inv_mask;
782 if (!is_ror) std::swap(mask1, mask2);
783
784 Node* low_node = graph()->NewNode(
785 machine()->Word32Or(),
786 graph()->NewNode(machine()->Word32And(), rotate_low, mask1),
787 graph()->NewNode(machine()->Word32And(), rotate_high, mask2));
788 Node* high_node = graph()->NewNode(
789 machine()->Word32Or(),
790 graph()->NewNode(machine()->Word32And(), rotate_high, mask1),
791 graph()->NewNode(machine()->Word32And(), rotate_low, mask2));
792 ReplaceNode(node, low_node, high_node);
793 }
794 break;
795 }
796 case IrOpcode::kWord64ClzLowerable: {
797 DCHECK_EQ(2, node->InputCount());
798 Node* input = node->InputAt(0);
799 Diamond d(
800 graph(), common(),
801 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
802 graph()->NewNode(common()->Int32Constant(0))));
803 d.Chain(NodeProperties::GetControlInput(node));
804
805 Node* low_node = d.Phi(
806 MachineRepresentation::kWord32,
807 graph()->NewNode(machine()->Int32Add(),
808 graph()->NewNode(machine()->Word32Clz(),
809 GetReplacementLow(input)),
810 graph()->NewNode(common()->Int32Constant(32))),
811 graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
812 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
813 break;
814 }
815 case IrOpcode::kWord64CtzLowerable: {
816 DCHECK_EQ(2, node->InputCount());
817 DCHECK(machine()->Word32Ctz().IsSupported());
818 Node* input = node->InputAt(0);
819 Diamond d(
820 graph(), common(),
821 graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
822 graph()->NewNode(common()->Int32Constant(0))));
823 d.Chain(NodeProperties::GetControlInput(node));
824
825 Node* low_node =
826 d.Phi(MachineRepresentation::kWord32,
827 graph()->NewNode(machine()->Int32Add(),
828 graph()->NewNode(machine()->Word32Ctz().op(),
829 GetReplacementHigh(input)),
830 graph()->NewNode(common()->Int32Constant(32))),
831 graph()->NewNode(machine()->Word32Ctz().op(),
832 GetReplacementLow(input)));
833 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
834 break;
835 }
836 case IrOpcode::kWord64Ror:
837 case IrOpcode::kWord64Rol:
838 case IrOpcode::kWord64Ctz:
839 case IrOpcode::kWord64Clz:
840 FATAL("%s operator should not be used in 32-bit systems",
841 node->op()->mnemonic());
842 case IrOpcode::kWord64Popcnt: {
843 DCHECK_EQ(1, node->InputCount());
844 Node* input = node->InputAt(0);
845 // We assume that a Word64Popcnt node only has been created if
846 // Word32Popcnt is actually supported.
847 DCHECK(machine()->Word32Popcnt().IsSupported());
848 Node* low_node =
849 graph()->NewNode(machine()->Int32Add(),
850 graph()->NewNode(machine()->Word32Popcnt().op(),
851 GetReplacementLow(input)),
852 graph()->NewNode(machine()->Word32Popcnt().op(),
853 GetReplacementHigh(input)));
854 ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
855 break;
856 }
857 case IrOpcode::kPhi: {
859 if (rep == MachineRepresentation::kWord64) {
860 // The replacement nodes have already been created, we only have to
861 // replace placeholder nodes.
862 Node* low_node = GetReplacementLow(node);
863 Node* high_node = GetReplacementHigh(node);
864 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
865 low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
866 high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
867 }
868 } else {
869 DefaultLowering(node);
870 }
871 break;
872 }
873 case IrOpcode::kLoopExitValue: {
875 if (rep == MachineRepresentation::kWord64) {
876 Node* low_node = graph()->NewNode(
877 common()->LoopExitValue(MachineRepresentation::kWord32),
878 GetReplacementLow(node->InputAt(0)), node->InputAt(1));
879 Node* high_node = graph()->NewNode(
880 common()->LoopExitValue(MachineRepresentation::kWord32),
881 GetReplacementHigh(node->InputAt(0)), node->InputAt(1));
882 ReplaceNode(node, low_node, high_node);
883 } else {
884 DefaultLowering(node);
885 }
886 break;
887 }
888 case IrOpcode::kWord64ReverseBytes: {
889 Node* input = node->InputAt(0);
890 Node* low_node = graph()->NewNode(machine()->Word32ReverseBytes(),
891 GetReplacementHigh(input));
892 Node* high_node = graph()->NewNode(machine()->Word32ReverseBytes(),
893 GetReplacementLow(input));
894 ReplaceNode(node, low_node, high_node);
895 break;
896 }
897 case IrOpcode::kSignExtendWord8ToInt64: {
898 DCHECK_EQ(1, node->InputCount());
899 Node* input = node->InputAt(0);
900 if (HasReplacementLow(input)) {
901 input = GetReplacementLow(input);
902 }
903 // Sign extend low node to Int32
904 Node* low_node =
905 graph()->NewNode(machine()->SignExtendWord8ToInt32(), input);
906 // We use SAR to preserve the sign in the high word.
907 Node* high_node =
908 graph()->NewNode(machine()->Word32Sar(), low_node,
909 graph()->NewNode(common()->Int32Constant(31)));
910 ReplaceNode(node, low_node, high_node);
911 node->NullAllInputs();
912 break;
913 }
914 case IrOpcode::kSignExtendWord16ToInt64: {
915 DCHECK_EQ(1, node->InputCount());
916 Node* input = node->InputAt(0);
917 if (HasReplacementLow(input)) {
918 input = GetReplacementLow(input);
919 }
920 // Sign extend low node to Int32
921 Node* low_node =
922 graph()->NewNode(machine()->SignExtendWord16ToInt32(), input);
923 // We use SAR to preserve the sign in the high word.
924 Node* high_node =
925 graph()->NewNode(machine()->Word32Sar(), low_node,
926 graph()->NewNode(common()->Int32Constant(31)));
927 ReplaceNode(node, low_node, high_node);
928 node->NullAllInputs();
929 break;
930 }
931 case IrOpcode::kWord64AtomicLoad: {
932 DCHECK_EQ(4, node->InputCount());
933 AtomicLoadParameters params = AtomicLoadParametersOf(node->op());
934 DefaultLowering(node, true);
935 if (params.representation() == MachineType::Uint64()) {
936 NodeProperties::ChangeOp(
937 node, machine()->Word32AtomicPairLoad(params.order()));
938 ReplaceNodeWithProjections(node);
939 } else {
940 NodeProperties::ChangeOp(node, machine()->Word32AtomicLoad(params));
941 ReplaceNode(node, node, graph()->NewNode(common()->Int32Constant(0)));
942 }
943 break;
944 }
945 case IrOpcode::kWord64AtomicStore: {
946 DCHECK_EQ(5, node->InputCount());
947 AtomicStoreParameters params = AtomicStoreParametersOf(node->op());
948 if (params.representation() == MachineRepresentation::kWord64) {
949 LowerMemoryBaseAndIndex(node);
950 Node* value = node->InputAt(2);
951 node->ReplaceInput(2, GetReplacementLow(value));
952 node->InsertInput(zone(), 3, GetReplacementHigh(value));
953 NodeProperties::ChangeOp(
954 node, machine()->Word32AtomicPairStore(params.order()));
955 } else {
956 DefaultLowering(node, true);
957 NodeProperties::ChangeOp(node, machine()->Word32AtomicStore(params));
958 }
959 break;
960 }
961#define ATOMIC_CASE(name) \
962 case IrOpcode::kWord64Atomic##name: { \
963 MachineType type = AtomicOpType(node->op()); \
964 if (type == MachineType::Uint64()) { \
965 LowerWord64AtomicBinop(node, machine()->Word32AtomicPair##name()); \
966 } else { \
967 LowerWord64AtomicNarrowOp(node, machine()->Word32Atomic##name(type)); \
968 } \
969 break; \
970 }
971 ATOMIC_CASE(Add)
972 ATOMIC_CASE(Sub)
973 ATOMIC_CASE(And)
974 ATOMIC_CASE(Or)
975 ATOMIC_CASE(Xor)
976 ATOMIC_CASE(Exchange)
977#undef ATOMIC_CASE
978 case IrOpcode::kWord64AtomicCompareExchange: {
979 MachineType type = AtomicOpType(node->op());
980 if (type == MachineType::Uint64()) {
981 LowerMemoryBaseAndIndex(node);
982 Node* old_value = node->InputAt(2);
983 Node* new_value = node->InputAt(3);
984 node->ReplaceInput(2, GetReplacementLow(old_value));
985 node->ReplaceInput(3, GetReplacementHigh(old_value));
986 node->InsertInput(zone(), 4, GetReplacementLow(new_value));
987 node->InsertInput(zone(), 5, GetReplacementHigh(new_value));
988 NodeProperties::ChangeOp(node,
989 machine()->Word32AtomicPairCompareExchange());
990 ReplaceNodeWithProjections(node);
991 } else {
992 DCHECK(type == MachineType::Uint32() || type == MachineType::Uint16() ||
993 type == MachineType::Uint8());
994 DefaultLowering(node, true);
995 NodeProperties::ChangeOp(node,
996 machine()->Word32AtomicCompareExchange(type));
997 ReplaceNode(node, node, graph()->NewNode(common()->Int32Constant(0)));
998 }
999 break;
1000 }
1001 case IrOpcode::kI64x2Splat: {
1002 DCHECK_EQ(1, node->InputCount());
1003 Node* input = node->InputAt(0);
1004 node->ReplaceInput(0, GetReplacementLow(input));
1005 node->AppendInput(zone(), GetReplacementHigh(input));
1006 NodeProperties::ChangeOp(node, machine()->I64x2SplatI32Pair());
1007 break;
1008 }
1009 case IrOpcode::kI64x2ExtractLane: {
1010 DCHECK_EQ(1, node->InputCount());
1011 Node* input = node->InputAt(0);
1012 int32_t lane = OpParameter<int32_t>(node->op());
1013 Node* low_node =
1014 graph()->NewNode(machine()->I32x4ExtractLane(lane * 2), input);
1015 Node* high_node =
1016 graph()->NewNode(machine()->I32x4ExtractLane(lane * 2 + 1), input);
1017 ReplaceNode(node, low_node, high_node);
1018 break;
1019 }
1020 case IrOpcode::kI64x2ReplaceLane: {
1021 DCHECK_EQ(2, node->InputCount());
1022 int32_t lane = OpParameter<int32_t>(node->op());
1023 Node* input = node->InputAt(1);
1024 node->ReplaceInput(1, GetReplacementLow(input));
1025 node->AppendInput(zone(), GetReplacementHigh(input));
1026 NodeProperties::ChangeOp(node, machine()->I64x2ReplaceLaneI32Pair(lane));
1027 break;
1028 }
1029
1030 default: { DefaultLowering(node); }
1031 }
1032}
1033
1034void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
1035 const Operator* low_word_op) {
1036 DCHECK_EQ(2, node->InputCount());
1037 Node* left = node->InputAt(0);
1038 Node* right = node->InputAt(1);
1039 Node* replacement = graph()->NewNode(
1040 machine()->Word32Or(),
1041 graph()->NewNode(high_word_op, GetReplacementHigh(left),
1042 GetReplacementHigh(right)),
1043 graph()->NewNode(
1044 machine()->Word32And(),
1045 graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
1046 GetReplacementHigh(right)),
1047 graph()->NewNode(low_word_op, GetReplacementLow(left),
1048 GetReplacementLow(right))));
1049 ReplaceNode(node, replacement, nullptr);
1050}
1051
1052bool Int64Lowering::DefaultLowering(Node* node, bool low_word_only) {
1053 bool something_changed = false;
1054 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
1055 Node* input = node->InputAt(i);
1056 if (HasReplacementLow(input)) {
1057 something_changed = true;
1058 node->ReplaceInput(i, GetReplacementLow(input));
1059 }
1060 if (!low_word_only && HasReplacementHigh(input)) {
1061 something_changed = true;
1062 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
1063 }
1064 }
1065 return something_changed;
1066}
1067
1068const CallDescriptor* Int64Lowering::LowerCallDescriptor(
1069 const CallDescriptor* call_descriptor) {
1070 CallDescriptor* maybe_special_replacement =
1071 wasm::GetWasmEngine()->call_descriptors()->GetLoweredCallDescriptor(
1072 call_descriptor);
1073 if (maybe_special_replacement) return maybe_special_replacement;
1074 return GetI32WasmCallDescriptor(zone(), call_descriptor);
1075}
1076
1077void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
1078 // if new_low == nullptr, then also new_high == nullptr.
1079 DCHECK(new_low != nullptr || new_high == nullptr);
1080 replacements_[old->id()].low = new_low;
1081 replacements_[old->id()].high = new_high;
1082}
1083
1084bool Int64Lowering::HasReplacementLow(Node* node) {
1085 return replacements_[node->id()].low != nullptr;
1086}
1087
1088Node* Int64Lowering::GetReplacementLow(Node* node) {
1089 Node* result = replacements_[node->id()].low;
1090 DCHECK(result);
1091 return result;
1092}
1093
1094bool Int64Lowering::HasReplacementHigh(Node* node) {
1095 return replacements_[node->id()].high != nullptr;
1096}
1097
1098Node* Int64Lowering::GetReplacementHigh(Node* node) {
1099 Node* result = replacements_[node->id()].high;
1100 DCHECK(result);
1101 return result;
1102}
1103
1104void Int64Lowering::PreparePhiReplacement(Node* phi) {
1106 if (rep == MachineRepresentation::kWord64) {
1107 // We have to create the replacements for a phi node before we actually
1108 // lower the phi to break potential cycles in the graph. The replacements of
1109 // input nodes do not exist yet, so we use a placeholder node to pass the
1110 // graph verifier.
1111 int value_count = phi->op()->ValueInputCount();
1112 Node** inputs_low = zone()->AllocateArray<Node*>(value_count + 1);
1113 Node** inputs_high = zone()->AllocateArray<Node*>(value_count + 1);
1114 for (int i = 0; i < value_count; i++) {
1115 inputs_low[i] = placeholder_;
1116 inputs_high[i] = placeholder_;
1117 }
1118 inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
1119 inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
1120 ReplaceNode(phi,
1121 graph()->NewNode(
1122 common()->Phi(MachineRepresentation::kWord32, value_count),
1123 value_count + 1, inputs_low, false),
1124 graph()->NewNode(
1125 common()->Phi(MachineRepresentation::kWord32, value_count),
1126 value_count + 1, inputs_high, false));
1127 }
1128}
1129
1130void Int64Lowering::ReplaceNodeWithProjections(Node* node) {
1131 DCHECK(node != nullptr);
1132 Node* low_node =
1133 graph()->NewNode(common()->Projection(0), node, graph()->start());
1134 Node* high_node =
1135 graph()->NewNode(common()->Projection(1), node, graph()->start());
1136 ReplaceNode(node, low_node, high_node);
1137}
1138
1139void Int64Lowering::LowerMemoryBaseAndIndex(Node* node) {
1140 DCHECK(node != nullptr);
1141 // Low word only replacements for memory operands for 32-bit address space.
1142 Node* base = node->InputAt(0);
1143 Node* index = node->InputAt(1);
1144 if (HasReplacementLow(base)) {
1145 node->ReplaceInput(0, GetReplacementLow(base));
1146 }
1147 if (HasReplacementLow(index)) {
1148 node->ReplaceInput(1, GetReplacementLow(index));
1149 }
1150}
1151
1152} // namespace compiler
1153} // namespace internal
1154} // namespace v8
1155
1156#endif // V8_TARGET_ARCH_32_BIT
TFGraph * graph
friend Zone
Definition asm-types.cc:195
int16_t parameter_count
Definition builtins.cc:67
constexpr MachineRepresentation representation() const
Int64Lowering(TFGraph *graph, MachineOperatorBuilder *machine, CommonOperatorBuilder *common, SimplifiedOperatorBuilder *simplified_, Zone *zone, Signature< MachineRepresentation > *signature)
Zone * zone_
int start
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
OptionalOpIndex index
ZoneVector< RpoNumber > & result
int m
Definition mul-fft.cc:294
int int32_t
Definition unicode.cc:40
size_t ProjectionIndexOf(const Operator *const op)
AtomicStoreParameters const & AtomicStoreParametersOf(Operator const *op)
StoreRepresentation const & StoreRepresentationOf(Operator const *op)
CallDescriptor const * CallDescriptorOf(const Operator *const op)
AtomicLoadParameters AtomicLoadParametersOf(Operator const *op)
int ParameterIndexOf(const Operator *const op)
const ObjectAccess & ObjectAccessOf(const Operator *op)
MachineType AtomicOpType(InstructionSelectorT *selector, OpIndex node)
IntMatcher< int32_t, IrOpcode::kInt32Constant > Int32Matcher
LoadRepresentation LoadRepresentationOf(Operator const *op)
MachineRepresentation UnalignedStoreRepresentation
UnalignedStoreRepresentation const & UnalignedStoreRepresentationOf(Operator const *op)
MachineRepresentation LoopExitValueRepresentationOf(const Operator *const op)
MachineRepresentation PhiRepresentationOf(const Operator *const op)
void Store(LiftoffAssembler *assm, LiftoffRegister src, MemOperand dst, ValueKind kind)
i::Address Load(i::Address address)
Definition unwinder.cc:19
#define FATAL(...)
Definition logging.h:47
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
TFGraph * graph_