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