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