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/base/adapters.h" 6#include "src/compiler/instruction-selector-impl.h" 7#include "src/compiler/node-matchers.h" 8#include "src/compiler/node-properties.h" 9#include "src/ppc/frames-ppc.h" 10 11namespace v8 { 12namespace internal { 13namespace compiler { 14 15enum ImmediateMode { 16 kInt16Imm, 17 kInt16Imm_Unsigned, 18 kInt16Imm_Negate, 19 kInt16Imm_4ByteAligned, 20 kShift32Imm, 21 kShift64Imm, 22 kNoImmediate 23}; 24 25 26// Adds PPC-specific methods for generating operands. 27class PPCOperandGenerator final : public OperandGenerator { 28 public: 29 explicit PPCOperandGenerator(InstructionSelector* selector) 30 : OperandGenerator(selector) {} 31 32 InstructionOperand UseOperand(Node* node, ImmediateMode mode) { 33 if (CanBeImmediate(node, mode)) { 34 return UseImmediate(node); 35 } 36 return UseRegister(node); 37 } 38 39 bool CanBeImmediate(Node* node, ImmediateMode mode) { 40 int64_t value; 41 if (node->opcode() == IrOpcode::kInt32Constant) 42 value = OpParameter<int32_t>(node); 43 else if (node->opcode() == IrOpcode::kInt64Constant) 44 value = OpParameter<int64_t>(node); 45 else 46 return false; 47 return CanBeImmediate(value, mode); 48 } 49 50 bool CanBeImmediate(int64_t value, ImmediateMode mode) { 51 switch (mode) { 52 case kInt16Imm: 53 return is_int16(value); 54 case kInt16Imm_Unsigned: 55 return is_uint16(value); 56 case kInt16Imm_Negate: 57 return is_int16(-value); 58 case kInt16Imm_4ByteAligned: 59 return is_int16(value) && !(value & 3); 60 case kShift32Imm: 61 return 0 <= value && value < 32; 62 case kShift64Imm: 63 return 0 <= value && value < 64; 64 case kNoImmediate: 65 return false; 66 } 67 return false; 68 } 69}; 70 71 72namespace { 73 74void VisitRR(InstructionSelector* selector, InstructionCode opcode, 75 Node* node) { 76 PPCOperandGenerator g(selector); 77 selector->Emit(opcode, g.DefineAsRegister(node), 78 g.UseRegister(node->InputAt(0))); 79} 80 81void VisitRRR(InstructionSelector* selector, InstructionCode opcode, 82 Node* node) { 83 PPCOperandGenerator g(selector); 84 selector->Emit(opcode, g.DefineAsRegister(node), 85 g.UseRegister(node->InputAt(0)), 86 g.UseRegister(node->InputAt(1))); 87} 88 89void VisitRRO(InstructionSelector* selector, InstructionCode opcode, Node* node, 90 ImmediateMode operand_mode) { 91 PPCOperandGenerator g(selector); 92 selector->Emit(opcode, g.DefineAsRegister(node), 93 g.UseRegister(node->InputAt(0)), 94 g.UseOperand(node->InputAt(1), operand_mode)); 95} 96 97 98#if V8_TARGET_ARCH_PPC64 99void VisitTryTruncateDouble(InstructionSelector* selector, 100 InstructionCode opcode, Node* node) { 101 PPCOperandGenerator g(selector); 102 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))}; 103 InstructionOperand outputs[2]; 104 size_t output_count = 0; 105 outputs[output_count++] = g.DefineAsRegister(node); 106 107 Node* success_output = NodeProperties::FindProjection(node, 1); 108 if (success_output) { 109 outputs[output_count++] = g.DefineAsRegister(success_output); 110 } 111 112 selector->Emit(opcode, output_count, outputs, 1, inputs); 113} 114#endif 115 116 117// Shared routine for multiple binary operations. 118template <typename Matcher> 119void VisitBinop(InstructionSelector* selector, Node* node, 120 InstructionCode opcode, ImmediateMode operand_mode, 121 FlagsContinuation* cont) { 122 PPCOperandGenerator g(selector); 123 Matcher m(node); 124 InstructionOperand inputs[4]; 125 size_t input_count = 0; 126 InstructionOperand outputs[2]; 127 size_t output_count = 0; 128 129 inputs[input_count++] = g.UseRegister(m.left().node()); 130 inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode); 131 132 if (cont->IsBranch()) { 133 inputs[input_count++] = g.Label(cont->true_block()); 134 inputs[input_count++] = g.Label(cont->false_block()); 135 } 136 137 if (cont->IsDeoptimize()) { 138 // If we can deoptimize as a result of the binop, we need to make sure that 139 // the deopt inputs are not overwritten by the binop result. One way 140 // to achieve that is to declare the output register as same-as-first. 141 outputs[output_count++] = g.DefineSameAsFirst(node); 142 } else { 143 outputs[output_count++] = g.DefineAsRegister(node); 144 } 145 if (cont->IsSet()) { 146 outputs[output_count++] = g.DefineAsRegister(cont->result()); 147 } 148 149 DCHECK_NE(0u, input_count); 150 DCHECK_NE(0u, output_count); 151 DCHECK_GE(arraysize(inputs), input_count); 152 DCHECK_GE(arraysize(outputs), output_count); 153 154 opcode = cont->Encode(opcode); 155 if (cont->IsDeoptimize()) { 156 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, 157 cont->reason(), cont->frame_state()); 158 } else { 159 selector->Emit(opcode, output_count, outputs, input_count, inputs); 160 } 161} 162 163 164// Shared routine for multiple binary operations. 165template <typename Matcher> 166void VisitBinop(InstructionSelector* selector, Node* node, 167 InstructionCode opcode, ImmediateMode operand_mode) { 168 FlagsContinuation cont; 169 VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont); 170} 171 172} // namespace 173 174 175void InstructionSelector::VisitLoad(Node* node) { 176 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); 177 PPCOperandGenerator g(this); 178 Node* base = node->InputAt(0); 179 Node* offset = node->InputAt(1); 180 ArchOpcode opcode = kArchNop; 181 ImmediateMode mode = kInt16Imm; 182 switch (load_rep.representation()) { 183 case MachineRepresentation::kFloat32: 184 opcode = kPPC_LoadFloat32; 185 break; 186 case MachineRepresentation::kFloat64: 187 opcode = kPPC_LoadDouble; 188 break; 189 case MachineRepresentation::kBit: // Fall through. 190 case MachineRepresentation::kWord8: 191 opcode = load_rep.IsSigned() ? kPPC_LoadWordS8 : kPPC_LoadWordU8; 192 break; 193 case MachineRepresentation::kWord16: 194 opcode = load_rep.IsSigned() ? kPPC_LoadWordS16 : kPPC_LoadWordU16; 195 break; 196#if !V8_TARGET_ARCH_PPC64 197 case MachineRepresentation::kTaggedSigned: // Fall through. 198 case MachineRepresentation::kTaggedPointer: // Fall through. 199 case MachineRepresentation::kTagged: // Fall through. 200#endif 201 case MachineRepresentation::kWord32: 202 opcode = kPPC_LoadWordU32; 203 break; 204#if V8_TARGET_ARCH_PPC64 205 case MachineRepresentation::kTaggedSigned: // Fall through. 206 case MachineRepresentation::kTaggedPointer: // Fall through. 207 case MachineRepresentation::kTagged: // Fall through. 208 case MachineRepresentation::kWord64: 209 opcode = kPPC_LoadWord64; 210 mode = kInt16Imm_4ByteAligned; 211 break; 212#else 213 case MachineRepresentation::kWord64: // Fall through. 214#endif 215 case MachineRepresentation::kSimd128: // Fall through. 216 case MachineRepresentation::kNone: 217 UNREACHABLE(); 218 return; 219 } 220 if (g.CanBeImmediate(offset, mode)) { 221 Emit(opcode | AddressingModeField::encode(kMode_MRI), 222 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(offset)); 223 } else if (g.CanBeImmediate(base, mode)) { 224 Emit(opcode | AddressingModeField::encode(kMode_MRI), 225 g.DefineAsRegister(node), g.UseRegister(offset), g.UseImmediate(base)); 226 } else { 227 Emit(opcode | AddressingModeField::encode(kMode_MRR), 228 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset)); 229 } 230} 231 232void InstructionSelector::VisitProtectedLoad(Node* node) { 233 // TODO(eholk) 234 UNIMPLEMENTED(); 235} 236 237void InstructionSelector::VisitStore(Node* node) { 238 PPCOperandGenerator g(this); 239 Node* base = node->InputAt(0); 240 Node* offset = node->InputAt(1); 241 Node* value = node->InputAt(2); 242 243 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); 244 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind(); 245 MachineRepresentation rep = store_rep.representation(); 246 247 if (write_barrier_kind != kNoWriteBarrier) { 248 DCHECK(CanBeTaggedPointer(rep)); 249 AddressingMode addressing_mode; 250 InstructionOperand inputs[3]; 251 size_t input_count = 0; 252 inputs[input_count++] = g.UseUniqueRegister(base); 253 // OutOfLineRecordWrite uses the offset in an 'add' instruction as well as 254 // for the store itself, so we must check compatibility with both. 255 if (g.CanBeImmediate(offset, kInt16Imm) 256#if V8_TARGET_ARCH_PPC64 257 && g.CanBeImmediate(offset, kInt16Imm_4ByteAligned) 258#endif 259 ) { 260 inputs[input_count++] = g.UseImmediate(offset); 261 addressing_mode = kMode_MRI; 262 } else { 263 inputs[input_count++] = g.UseUniqueRegister(offset); 264 addressing_mode = kMode_MRR; 265 } 266 inputs[input_count++] = g.UseUniqueRegister(value); 267 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny; 268 switch (write_barrier_kind) { 269 case kNoWriteBarrier: 270 UNREACHABLE(); 271 break; 272 case kMapWriteBarrier: 273 record_write_mode = RecordWriteMode::kValueIsMap; 274 break; 275 case kPointerWriteBarrier: 276 record_write_mode = RecordWriteMode::kValueIsPointer; 277 break; 278 case kFullWriteBarrier: 279 record_write_mode = RecordWriteMode::kValueIsAny; 280 break; 281 } 282 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; 283 size_t const temp_count = arraysize(temps); 284 InstructionCode code = kArchStoreWithWriteBarrier; 285 code |= AddressingModeField::encode(addressing_mode); 286 code |= MiscField::encode(static_cast<int>(record_write_mode)); 287 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); 288 } else { 289 ArchOpcode opcode = kArchNop; 290 ImmediateMode mode = kInt16Imm; 291 switch (rep) { 292 case MachineRepresentation::kFloat32: 293 opcode = kPPC_StoreFloat32; 294 break; 295 case MachineRepresentation::kFloat64: 296 opcode = kPPC_StoreDouble; 297 break; 298 case MachineRepresentation::kBit: // Fall through. 299 case MachineRepresentation::kWord8: 300 opcode = kPPC_StoreWord8; 301 break; 302 case MachineRepresentation::kWord16: 303 opcode = kPPC_StoreWord16; 304 break; 305#if !V8_TARGET_ARCH_PPC64 306 case MachineRepresentation::kTaggedSigned: // Fall through. 307 case MachineRepresentation::kTaggedPointer: // Fall through. 308 case MachineRepresentation::kTagged: // Fall through. 309#endif 310 case MachineRepresentation::kWord32: 311 opcode = kPPC_StoreWord32; 312 break; 313#if V8_TARGET_ARCH_PPC64 314 case MachineRepresentation::kTaggedSigned: // Fall through. 315 case MachineRepresentation::kTaggedPointer: // Fall through. 316 case MachineRepresentation::kTagged: // Fall through. 317 case MachineRepresentation::kWord64: 318 opcode = kPPC_StoreWord64; 319 mode = kInt16Imm_4ByteAligned; 320 break; 321#else 322 case MachineRepresentation::kWord64: // Fall through. 323#endif 324 case MachineRepresentation::kSimd128: // Fall through. 325 case MachineRepresentation::kNone: 326 UNREACHABLE(); 327 return; 328 } 329 if (g.CanBeImmediate(offset, mode)) { 330 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), 331 g.UseRegister(base), g.UseImmediate(offset), g.UseRegister(value)); 332 } else if (g.CanBeImmediate(base, mode)) { 333 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), 334 g.UseRegister(offset), g.UseImmediate(base), g.UseRegister(value)); 335 } else { 336 Emit(opcode | AddressingModeField::encode(kMode_MRR), g.NoOutput(), 337 g.UseRegister(base), g.UseRegister(offset), g.UseRegister(value)); 338 } 339 } 340} 341 342// Architecture supports unaligned access, therefore VisitLoad is used instead 343void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); } 344 345// Architecture supports unaligned access, therefore VisitStore is used instead 346void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); } 347 348void InstructionSelector::VisitCheckedLoad(Node* node) { 349 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); 350 PPCOperandGenerator g(this); 351 Node* const base = node->InputAt(0); 352 Node* const offset = node->InputAt(1); 353 Node* const length = node->InputAt(2); 354 ArchOpcode opcode = kArchNop; 355 switch (load_rep.representation()) { 356 case MachineRepresentation::kWord8: 357 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8; 358 break; 359 case MachineRepresentation::kWord16: 360 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16; 361 break; 362 case MachineRepresentation::kWord32: 363 opcode = kCheckedLoadWord32; 364 break; 365#if V8_TARGET_ARCH_PPC64 366 case MachineRepresentation::kWord64: 367 opcode = kCheckedLoadWord64; 368 break; 369#endif 370 case MachineRepresentation::kFloat32: 371 opcode = kCheckedLoadFloat32; 372 break; 373 case MachineRepresentation::kFloat64: 374 opcode = kCheckedLoadFloat64; 375 break; 376 case MachineRepresentation::kBit: // Fall through. 377 case MachineRepresentation::kTaggedSigned: // Fall through. 378 case MachineRepresentation::kTaggedPointer: // Fall through. 379 case MachineRepresentation::kTagged: // Fall through. 380#if !V8_TARGET_ARCH_PPC64 381 case MachineRepresentation::kWord64: // Fall through. 382#endif 383 case MachineRepresentation::kSimd128: // Fall through. 384 case MachineRepresentation::kNone: 385 UNREACHABLE(); 386 return; 387 } 388 AddressingMode addressingMode = kMode_MRR; 389 Emit(opcode | AddressingModeField::encode(addressingMode), 390 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset), 391 g.UseOperand(length, kInt16Imm_Unsigned)); 392} 393 394 395void InstructionSelector::VisitCheckedStore(Node* node) { 396 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op()); 397 PPCOperandGenerator g(this); 398 Node* const base = node->InputAt(0); 399 Node* const offset = node->InputAt(1); 400 Node* const length = node->InputAt(2); 401 Node* const value = node->InputAt(3); 402 ArchOpcode opcode = kArchNop; 403 switch (rep) { 404 case MachineRepresentation::kWord8: 405 opcode = kCheckedStoreWord8; 406 break; 407 case MachineRepresentation::kWord16: 408 opcode = kCheckedStoreWord16; 409 break; 410 case MachineRepresentation::kWord32: 411 opcode = kCheckedStoreWord32; 412 break; 413#if V8_TARGET_ARCH_PPC64 414 case MachineRepresentation::kWord64: 415 opcode = kCheckedStoreWord64; 416 break; 417#endif 418 case MachineRepresentation::kFloat32: 419 opcode = kCheckedStoreFloat32; 420 break; 421 case MachineRepresentation::kFloat64: 422 opcode = kCheckedStoreFloat64; 423 break; 424 case MachineRepresentation::kBit: // Fall through. 425 case MachineRepresentation::kTaggedSigned: // Fall through. 426 case MachineRepresentation::kTaggedPointer: // Fall through. 427 case MachineRepresentation::kTagged: // Fall through. 428#if !V8_TARGET_ARCH_PPC64 429 case MachineRepresentation::kWord64: // Fall through. 430#endif 431 case MachineRepresentation::kSimd128: // Fall through. 432 case MachineRepresentation::kNone: 433 UNREACHABLE(); 434 return; 435 } 436 AddressingMode addressingMode = kMode_MRR; 437 Emit(opcode | AddressingModeField::encode(addressingMode), g.NoOutput(), 438 g.UseRegister(base), g.UseRegister(offset), 439 g.UseOperand(length, kInt16Imm_Unsigned), g.UseRegister(value)); 440} 441 442 443template <typename Matcher> 444static void VisitLogical(InstructionSelector* selector, Node* node, Matcher* m, 445 ArchOpcode opcode, bool left_can_cover, 446 bool right_can_cover, ImmediateMode imm_mode) { 447 PPCOperandGenerator g(selector); 448 449 // Map instruction to equivalent operation with inverted right input. 450 ArchOpcode inv_opcode = opcode; 451 switch (opcode) { 452 case kPPC_And: 453 inv_opcode = kPPC_AndComplement; 454 break; 455 case kPPC_Or: 456 inv_opcode = kPPC_OrComplement; 457 break; 458 default: 459 UNREACHABLE(); 460 } 461 462 // Select Logical(y, ~x) for Logical(Xor(x, -1), y). 463 if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) && left_can_cover) { 464 Matcher mleft(m->left().node()); 465 if (mleft.right().Is(-1)) { 466 selector->Emit(inv_opcode, g.DefineAsRegister(node), 467 g.UseRegister(m->right().node()), 468 g.UseRegister(mleft.left().node())); 469 return; 470 } 471 } 472 473 // Select Logical(x, ~y) for Logical(x, Xor(y, -1)). 474 if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) && 475 right_can_cover) { 476 Matcher mright(m->right().node()); 477 if (mright.right().Is(-1)) { 478 // TODO(all): support shifted operand on right. 479 selector->Emit(inv_opcode, g.DefineAsRegister(node), 480 g.UseRegister(m->left().node()), 481 g.UseRegister(mright.left().node())); 482 return; 483 } 484 } 485 486 VisitBinop<Matcher>(selector, node, opcode, imm_mode); 487} 488 489 490static inline bool IsContiguousMask32(uint32_t value, int* mb, int* me) { 491 int mask_width = base::bits::CountPopulation32(value); 492 int mask_msb = base::bits::CountLeadingZeros32(value); 493 int mask_lsb = base::bits::CountTrailingZeros32(value); 494 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 32)) 495 return false; 496 *mb = mask_lsb + mask_width - 1; 497 *me = mask_lsb; 498 return true; 499} 500 501 502#if V8_TARGET_ARCH_PPC64 503static inline bool IsContiguousMask64(uint64_t value, int* mb, int* me) { 504 int mask_width = base::bits::CountPopulation64(value); 505 int mask_msb = base::bits::CountLeadingZeros64(value); 506 int mask_lsb = base::bits::CountTrailingZeros64(value); 507 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 64)) 508 return false; 509 *mb = mask_lsb + mask_width - 1; 510 *me = mask_lsb; 511 return true; 512} 513#endif 514 515 516// TODO(mbrandy): Absorb rotate-right into rlwinm? 517void InstructionSelector::VisitWord32And(Node* node) { 518 PPCOperandGenerator g(this); 519 Int32BinopMatcher m(node); 520 int mb = 0; 521 int me = 0; 522 if (m.right().HasValue() && IsContiguousMask32(m.right().Value(), &mb, &me)) { 523 int sh = 0; 524 Node* left = m.left().node(); 525 if ((m.left().IsWord32Shr() || m.left().IsWord32Shl()) && 526 CanCover(node, left)) { 527 // Try to absorb left/right shift into rlwinm 528 Int32BinopMatcher mleft(m.left().node()); 529 if (mleft.right().IsInRange(0, 31)) { 530 left = mleft.left().node(); 531 sh = mleft.right().Value(); 532 if (m.left().IsWord32Shr()) { 533 // Adjust the mask such that it doesn't include any rotated bits. 534 if (mb > 31 - sh) mb = 31 - sh; 535 sh = (32 - sh) & 0x1f; 536 } else { 537 // Adjust the mask such that it doesn't include any rotated bits. 538 if (me < sh) me = sh; 539 } 540 } 541 } 542 if (mb >= me) { 543 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node), g.UseRegister(left), 544 g.TempImmediate(sh), g.TempImmediate(mb), g.TempImmediate(me)); 545 return; 546 } 547 } 548 VisitLogical<Int32BinopMatcher>( 549 this, node, &m, kPPC_And, CanCover(node, m.left().node()), 550 CanCover(node, m.right().node()), kInt16Imm_Unsigned); 551} 552 553 554#if V8_TARGET_ARCH_PPC64 555// TODO(mbrandy): Absorb rotate-right into rldic? 556void InstructionSelector::VisitWord64And(Node* node) { 557 PPCOperandGenerator g(this); 558 Int64BinopMatcher m(node); 559 int mb = 0; 560 int me = 0; 561 if (m.right().HasValue() && IsContiguousMask64(m.right().Value(), &mb, &me)) { 562 int sh = 0; 563 Node* left = m.left().node(); 564 if ((m.left().IsWord64Shr() || m.left().IsWord64Shl()) && 565 CanCover(node, left)) { 566 // Try to absorb left/right shift into rldic 567 Int64BinopMatcher mleft(m.left().node()); 568 if (mleft.right().IsInRange(0, 63)) { 569 left = mleft.left().node(); 570 sh = mleft.right().Value(); 571 if (m.left().IsWord64Shr()) { 572 // Adjust the mask such that it doesn't include any rotated bits. 573 if (mb > 63 - sh) mb = 63 - sh; 574 sh = (64 - sh) & 0x3f; 575 } else { 576 // Adjust the mask such that it doesn't include any rotated bits. 577 if (me < sh) me = sh; 578 } 579 } 580 } 581 if (mb >= me) { 582 bool match = false; 583 ArchOpcode opcode; 584 int mask; 585 if (me == 0) { 586 match = true; 587 opcode = kPPC_RotLeftAndClearLeft64; 588 mask = mb; 589 } else if (mb == 63) { 590 match = true; 591 opcode = kPPC_RotLeftAndClearRight64; 592 mask = me; 593 } else if (sh && me <= sh && m.left().IsWord64Shl()) { 594 match = true; 595 opcode = kPPC_RotLeftAndClear64; 596 mask = mb; 597 } 598 if (match) { 599 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), 600 g.TempImmediate(sh), g.TempImmediate(mask)); 601 return; 602 } 603 } 604 } 605 VisitLogical<Int64BinopMatcher>( 606 this, node, &m, kPPC_And, CanCover(node, m.left().node()), 607 CanCover(node, m.right().node()), kInt16Imm_Unsigned); 608} 609#endif 610 611 612void InstructionSelector::VisitWord32Or(Node* node) { 613 Int32BinopMatcher m(node); 614 VisitLogical<Int32BinopMatcher>( 615 this, node, &m, kPPC_Or, CanCover(node, m.left().node()), 616 CanCover(node, m.right().node()), kInt16Imm_Unsigned); 617} 618 619 620#if V8_TARGET_ARCH_PPC64 621void InstructionSelector::VisitWord64Or(Node* node) { 622 Int64BinopMatcher m(node); 623 VisitLogical<Int64BinopMatcher>( 624 this, node, &m, kPPC_Or, CanCover(node, m.left().node()), 625 CanCover(node, m.right().node()), kInt16Imm_Unsigned); 626} 627#endif 628 629 630void InstructionSelector::VisitWord32Xor(Node* node) { 631 PPCOperandGenerator g(this); 632 Int32BinopMatcher m(node); 633 if (m.right().Is(-1)) { 634 Emit(kPPC_Not, g.DefineAsRegister(node), g.UseRegister(m.left().node())); 635 } else { 636 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Xor, kInt16Imm_Unsigned); 637 } 638} 639 640 641#if V8_TARGET_ARCH_PPC64 642void InstructionSelector::VisitWord64Xor(Node* node) { 643 PPCOperandGenerator g(this); 644 Int64BinopMatcher m(node); 645 if (m.right().Is(-1)) { 646 Emit(kPPC_Not, g.DefineAsRegister(node), g.UseRegister(m.left().node())); 647 } else { 648 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Xor, kInt16Imm_Unsigned); 649 } 650} 651#endif 652 653 654void InstructionSelector::VisitWord32Shl(Node* node) { 655 PPCOperandGenerator g(this); 656 Int32BinopMatcher m(node); 657 if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) { 658 // Try to absorb logical-and into rlwinm 659 Int32BinopMatcher mleft(m.left().node()); 660 int sh = m.right().Value(); 661 int mb; 662 int me; 663 if (mleft.right().HasValue() && 664 IsContiguousMask32(mleft.right().Value() << sh, &mb, &me)) { 665 // Adjust the mask such that it doesn't include any rotated bits. 666 if (me < sh) me = sh; 667 if (mb >= me) { 668 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node), 669 g.UseRegister(mleft.left().node()), g.TempImmediate(sh), 670 g.TempImmediate(mb), g.TempImmediate(me)); 671 return; 672 } 673 } 674 } 675 VisitRRO(this, kPPC_ShiftLeft32, node, kShift32Imm); 676} 677 678 679#if V8_TARGET_ARCH_PPC64 680void InstructionSelector::VisitWord64Shl(Node* node) { 681 PPCOperandGenerator g(this); 682 Int64BinopMatcher m(node); 683 // TODO(mbrandy): eliminate left sign extension if right >= 32 684 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) { 685 // Try to absorb logical-and into rldic 686 Int64BinopMatcher mleft(m.left().node()); 687 int sh = m.right().Value(); 688 int mb; 689 int me; 690 if (mleft.right().HasValue() && 691 IsContiguousMask64(mleft.right().Value() << sh, &mb, &me)) { 692 // Adjust the mask such that it doesn't include any rotated bits. 693 if (me < sh) me = sh; 694 if (mb >= me) { 695 bool match = false; 696 ArchOpcode opcode; 697 int mask; 698 if (me == 0) { 699 match = true; 700 opcode = kPPC_RotLeftAndClearLeft64; 701 mask = mb; 702 } else if (mb == 63) { 703 match = true; 704 opcode = kPPC_RotLeftAndClearRight64; 705 mask = me; 706 } else if (sh && me <= sh) { 707 match = true; 708 opcode = kPPC_RotLeftAndClear64; 709 mask = mb; 710 } 711 if (match) { 712 Emit(opcode, g.DefineAsRegister(node), 713 g.UseRegister(mleft.left().node()), g.TempImmediate(sh), 714 g.TempImmediate(mask)); 715 return; 716 } 717 } 718 } 719 } 720 VisitRRO(this, kPPC_ShiftLeft64, node, kShift64Imm); 721} 722#endif 723 724 725void InstructionSelector::VisitWord32Shr(Node* node) { 726 PPCOperandGenerator g(this); 727 Int32BinopMatcher m(node); 728 if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) { 729 // Try to absorb logical-and into rlwinm 730 Int32BinopMatcher mleft(m.left().node()); 731 int sh = m.right().Value(); 732 int mb; 733 int me; 734 if (mleft.right().HasValue() && 735 IsContiguousMask32((uint32_t)(mleft.right().Value()) >> sh, &mb, &me)) { 736 // Adjust the mask such that it doesn't include any rotated bits. 737 if (mb > 31 - sh) mb = 31 - sh; 738 sh = (32 - sh) & 0x1f; 739 if (mb >= me) { 740 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node), 741 g.UseRegister(mleft.left().node()), g.TempImmediate(sh), 742 g.TempImmediate(mb), g.TempImmediate(me)); 743 return; 744 } 745 } 746 } 747 VisitRRO(this, kPPC_ShiftRight32, node, kShift32Imm); 748} 749 750#if V8_TARGET_ARCH_PPC64 751void InstructionSelector::VisitWord64Shr(Node* node) { 752 PPCOperandGenerator g(this); 753 Int64BinopMatcher m(node); 754 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) { 755 // Try to absorb logical-and into rldic 756 Int64BinopMatcher mleft(m.left().node()); 757 int sh = m.right().Value(); 758 int mb; 759 int me; 760 if (mleft.right().HasValue() && 761 IsContiguousMask64((uint64_t)(mleft.right().Value()) >> sh, &mb, &me)) { 762 // Adjust the mask such that it doesn't include any rotated bits. 763 if (mb > 63 - sh) mb = 63 - sh; 764 sh = (64 - sh) & 0x3f; 765 if (mb >= me) { 766 bool match = false; 767 ArchOpcode opcode; 768 int mask; 769 if (me == 0) { 770 match = true; 771 opcode = kPPC_RotLeftAndClearLeft64; 772 mask = mb; 773 } else if (mb == 63) { 774 match = true; 775 opcode = kPPC_RotLeftAndClearRight64; 776 mask = me; 777 } 778 if (match) { 779 Emit(opcode, g.DefineAsRegister(node), 780 g.UseRegister(mleft.left().node()), g.TempImmediate(sh), 781 g.TempImmediate(mask)); 782 return; 783 } 784 } 785 } 786 } 787 VisitRRO(this, kPPC_ShiftRight64, node, kShift64Imm); 788} 789#endif 790 791 792void InstructionSelector::VisitWord32Sar(Node* node) { 793 PPCOperandGenerator g(this); 794 Int32BinopMatcher m(node); 795 // Replace with sign extension for (x << K) >> K where K is 16 or 24. 796 if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) { 797 Int32BinopMatcher mleft(m.left().node()); 798 if (mleft.right().Is(16) && m.right().Is(16)) { 799 Emit(kPPC_ExtendSignWord16, g.DefineAsRegister(node), 800 g.UseRegister(mleft.left().node())); 801 return; 802 } else if (mleft.right().Is(24) && m.right().Is(24)) { 803 Emit(kPPC_ExtendSignWord8, g.DefineAsRegister(node), 804 g.UseRegister(mleft.left().node())); 805 return; 806 } 807 } 808 VisitRRO(this, kPPC_ShiftRightAlg32, node, kShift32Imm); 809} 810 811#if !V8_TARGET_ARCH_PPC64 812void VisitPairBinop(InstructionSelector* selector, InstructionCode opcode, 813 InstructionCode opcode2, Node* node) { 814 PPCOperandGenerator g(selector); 815 816 Node* projection1 = NodeProperties::FindProjection(node, 1); 817 if (projection1) { 818 // We use UseUniqueRegister here to avoid register sharing with the output 819 // registers. 820 InstructionOperand inputs[] = { 821 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)), 822 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))}; 823 824 InstructionOperand outputs[] = { 825 g.DefineAsRegister(node), 826 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))}; 827 828 selector->Emit(opcode, 2, outputs, 4, inputs); 829 } else { 830 // The high word of the result is not used, so we emit the standard 32 bit 831 // instruction. 832 selector->Emit(opcode2, g.DefineSameAsFirst(node), 833 g.UseRegister(node->InputAt(0)), 834 g.UseRegister(node->InputAt(2))); 835 } 836} 837 838void InstructionSelector::VisitInt32PairAdd(Node* node) { 839 VisitPairBinop(this, kPPC_AddPair, kPPC_Add, node); 840} 841 842void InstructionSelector::VisitInt32PairSub(Node* node) { 843 VisitPairBinop(this, kPPC_SubPair, kPPC_Sub, node); 844} 845 846void InstructionSelector::VisitInt32PairMul(Node* node) { 847 PPCOperandGenerator g(this); 848 Node* projection1 = NodeProperties::FindProjection(node, 1); 849 if (projection1) { 850 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)), 851 g.UseUniqueRegister(node->InputAt(1)), 852 g.UseUniqueRegister(node->InputAt(2)), 853 g.UseUniqueRegister(node->InputAt(3))}; 854 855 InstructionOperand outputs[] = { 856 g.DefineAsRegister(node), 857 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))}; 858 859 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; 860 861 Emit(kPPC_MulPair, 2, outputs, 4, inputs, 2, temps); 862 } else { 863 // The high word of the result is not used, so we emit the standard 32 bit 864 // instruction. 865 Emit(kPPC_Mul32, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)), 866 g.UseRegister(node->InputAt(2))); 867 } 868} 869 870namespace { 871// Shared routine for multiple shift operations. 872void VisitPairShift(InstructionSelector* selector, InstructionCode opcode, 873 Node* node) { 874 PPCOperandGenerator g(selector); 875 // We use g.UseUniqueRegister here to guarantee that there is 876 // no register aliasing of input registers with output registers. 877 Int32Matcher m(node->InputAt(2)); 878 InstructionOperand shift_operand; 879 if (m.HasValue()) { 880 shift_operand = g.UseImmediate(m.node()); 881 } else { 882 shift_operand = g.UseUniqueRegister(m.node()); 883 } 884 885 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)), 886 g.UseUniqueRegister(node->InputAt(1)), 887 shift_operand}; 888 889 Node* projection1 = NodeProperties::FindProjection(node, 1); 890 891 InstructionOperand outputs[2]; 892 InstructionOperand temps[1]; 893 int32_t output_count = 0; 894 int32_t temp_count = 0; 895 896 outputs[output_count++] = g.DefineAsRegister(node); 897 if (projection1) { 898 outputs[output_count++] = g.DefineAsRegister(projection1); 899 } else { 900 temps[temp_count++] = g.TempRegister(); 901 } 902 903 selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps); 904} 905} // namespace 906 907void InstructionSelector::VisitWord32PairShl(Node* node) { 908 VisitPairShift(this, kPPC_ShiftLeftPair, node); 909} 910 911void InstructionSelector::VisitWord32PairShr(Node* node) { 912 VisitPairShift(this, kPPC_ShiftRightPair, node); 913} 914 915void InstructionSelector::VisitWord32PairSar(Node* node) { 916 VisitPairShift(this, kPPC_ShiftRightAlgPair, node); 917} 918#endif 919 920#if V8_TARGET_ARCH_PPC64 921void InstructionSelector::VisitWord64Sar(Node* node) { 922 PPCOperandGenerator g(this); 923 Int64BinopMatcher m(node); 924 if (CanCover(m.node(), m.left().node()) && m.left().IsLoad() && 925 m.right().Is(32)) { 926 // Just load and sign-extend the interesting 4 bytes instead. This happens, 927 // for example, when we're loading and untagging SMIs. 928 BaseWithIndexAndDisplacement64Matcher mleft(m.left().node(), 929 AddressOption::kAllowAll); 930 if (mleft.matches() && mleft.index() == nullptr) { 931 int64_t offset = 0; 932 Node* displacement = mleft.displacement(); 933 if (displacement != nullptr) { 934 Int64Matcher mdisplacement(displacement); 935 DCHECK(mdisplacement.HasValue()); 936 offset = mdisplacement.Value(); 937 } 938 offset = SmiWordOffset(offset); 939 if (g.CanBeImmediate(offset, kInt16Imm_4ByteAligned)) { 940 Emit(kPPC_LoadWordS32 | AddressingModeField::encode(kMode_MRI), 941 g.DefineAsRegister(node), g.UseRegister(mleft.base()), 942 g.TempImmediate(offset)); 943 return; 944 } 945 } 946 } 947 VisitRRO(this, kPPC_ShiftRightAlg64, node, kShift64Imm); 948} 949#endif 950 951 952// TODO(mbrandy): Absorb logical-and into rlwinm? 953void InstructionSelector::VisitWord32Ror(Node* node) { 954 VisitRRO(this, kPPC_RotRight32, node, kShift32Imm); 955} 956 957 958#if V8_TARGET_ARCH_PPC64 959// TODO(mbrandy): Absorb logical-and into rldic? 960void InstructionSelector::VisitWord64Ror(Node* node) { 961 VisitRRO(this, kPPC_RotRight64, node, kShift64Imm); 962} 963#endif 964 965 966void InstructionSelector::VisitWord32Clz(Node* node) { 967 PPCOperandGenerator g(this); 968 Emit(kPPC_Cntlz32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); 969} 970 971 972#if V8_TARGET_ARCH_PPC64 973void InstructionSelector::VisitWord64Clz(Node* node) { 974 PPCOperandGenerator g(this); 975 Emit(kPPC_Cntlz64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); 976} 977#endif 978 979 980void InstructionSelector::VisitWord32Popcnt(Node* node) { 981 PPCOperandGenerator g(this); 982 Emit(kPPC_Popcnt32, g.DefineAsRegister(node), 983 g.UseRegister(node->InputAt(0))); 984} 985 986 987#if V8_TARGET_ARCH_PPC64 988void InstructionSelector::VisitWord64Popcnt(Node* node) { 989 PPCOperandGenerator g(this); 990 Emit(kPPC_Popcnt64, g.DefineAsRegister(node), 991 g.UseRegister(node->InputAt(0))); 992} 993#endif 994 995 996void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } 997 998 999#if V8_TARGET_ARCH_PPC64 1000void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); } 1001#endif 1002 1003 1004void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } 1005 1006 1007#if V8_TARGET_ARCH_PPC64 1008void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); } 1009#endif 1010 1011void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); } 1012 1013void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); } 1014 1015void InstructionSelector::VisitInt32Add(Node* node) { 1016 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm); 1017} 1018 1019 1020#if V8_TARGET_ARCH_PPC64 1021void InstructionSelector::VisitInt64Add(Node* node) { 1022 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm); 1023} 1024#endif 1025 1026void InstructionSelector::VisitInt32Sub(Node* node) { 1027 PPCOperandGenerator g(this); 1028 Int32BinopMatcher m(node); 1029 if (m.left().Is(0)) { 1030 Emit(kPPC_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node())); 1031 } else { 1032 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate); 1033 } 1034} 1035 1036 1037#if V8_TARGET_ARCH_PPC64 1038void InstructionSelector::VisitInt64Sub(Node* node) { 1039 PPCOperandGenerator g(this); 1040 Int64BinopMatcher m(node); 1041 if (m.left().Is(0)) { 1042 Emit(kPPC_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node())); 1043 } else { 1044 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate); 1045 } 1046} 1047#endif 1048 1049namespace { 1050 1051void VisitCompare(InstructionSelector* selector, InstructionCode opcode, 1052 InstructionOperand left, InstructionOperand right, 1053 FlagsContinuation* cont); 1054void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node, 1055 FlagsContinuation* cont) { 1056 PPCOperandGenerator g(selector); 1057 Int32BinopMatcher m(node); 1058 InstructionOperand result_operand = g.DefineAsRegister(node); 1059 InstructionOperand high32_operand = g.TempRegister(); 1060 InstructionOperand temp_operand = g.TempRegister(); 1061 { 1062 InstructionOperand outputs[] = {result_operand, high32_operand}; 1063 InstructionOperand inputs[] = {g.UseRegister(m.left().node()), 1064 g.UseRegister(m.right().node())}; 1065 selector->Emit(kPPC_Mul32WithHigh32, 2, outputs, 2, inputs); 1066 } 1067 { 1068 InstructionOperand shift_31 = g.UseImmediate(31); 1069 InstructionOperand outputs[] = {temp_operand}; 1070 InstructionOperand inputs[] = {result_operand, shift_31}; 1071 selector->Emit(kPPC_ShiftRightAlg32, 1, outputs, 2, inputs); 1072 } 1073 1074 VisitCompare(selector, kPPC_Cmp32, high32_operand, temp_operand, cont); 1075} 1076 1077} // namespace 1078 1079 1080void InstructionSelector::VisitInt32Mul(Node* node) { 1081 VisitRRR(this, kPPC_Mul32, node); 1082} 1083 1084 1085#if V8_TARGET_ARCH_PPC64 1086void InstructionSelector::VisitInt64Mul(Node* node) { 1087 VisitRRR(this, kPPC_Mul64, node); 1088} 1089#endif 1090 1091 1092void InstructionSelector::VisitInt32MulHigh(Node* node) { 1093 PPCOperandGenerator g(this); 1094 Emit(kPPC_MulHigh32, g.DefineAsRegister(node), 1095 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); 1096} 1097 1098 1099void InstructionSelector::VisitUint32MulHigh(Node* node) { 1100 PPCOperandGenerator g(this); 1101 Emit(kPPC_MulHighU32, g.DefineAsRegister(node), 1102 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); 1103} 1104 1105 1106void InstructionSelector::VisitInt32Div(Node* node) { 1107 VisitRRR(this, kPPC_Div32, node); 1108} 1109 1110 1111#if V8_TARGET_ARCH_PPC64 1112void InstructionSelector::VisitInt64Div(Node* node) { 1113 VisitRRR(this, kPPC_Div64, node); 1114} 1115#endif 1116 1117 1118void InstructionSelector::VisitUint32Div(Node* node) { 1119 VisitRRR(this, kPPC_DivU32, node); 1120} 1121 1122 1123#if V8_TARGET_ARCH_PPC64 1124void InstructionSelector::VisitUint64Div(Node* node) { 1125 VisitRRR(this, kPPC_DivU64, node); 1126} 1127#endif 1128 1129 1130void InstructionSelector::VisitInt32Mod(Node* node) { 1131 VisitRRR(this, kPPC_Mod32, node); 1132} 1133 1134 1135#if V8_TARGET_ARCH_PPC64 1136void InstructionSelector::VisitInt64Mod(Node* node) { 1137 VisitRRR(this, kPPC_Mod64, node); 1138} 1139#endif 1140 1141 1142void InstructionSelector::VisitUint32Mod(Node* node) { 1143 VisitRRR(this, kPPC_ModU32, node); 1144} 1145 1146 1147#if V8_TARGET_ARCH_PPC64 1148void InstructionSelector::VisitUint64Mod(Node* node) { 1149 VisitRRR(this, kPPC_ModU64, node); 1150} 1151#endif 1152 1153 1154void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { 1155 VisitRR(this, kPPC_Float32ToDouble, node); 1156} 1157 1158 1159void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) { 1160 VisitRR(this, kPPC_Int32ToFloat32, node); 1161} 1162 1163 1164void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) { 1165 VisitRR(this, kPPC_Uint32ToFloat32, node); 1166} 1167 1168 1169void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { 1170 VisitRR(this, kPPC_Int32ToDouble, node); 1171} 1172 1173 1174void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { 1175 VisitRR(this, kPPC_Uint32ToDouble, node); 1176} 1177 1178 1179void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { 1180 VisitRR(this, kPPC_DoubleToInt32, node); 1181} 1182 1183 1184void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { 1185 VisitRR(this, kPPC_DoubleToUint32, node); 1186} 1187 1188void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) { 1189 VisitRR(this, kPPC_DoubleToUint32, node); 1190} 1191 1192#if V8_TARGET_ARCH_PPC64 1193void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) { 1194 VisitTryTruncateDouble(this, kPPC_DoubleToInt64, node); 1195} 1196 1197 1198void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) { 1199 VisitTryTruncateDouble(this, kPPC_DoubleToInt64, node); 1200} 1201 1202 1203void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) { 1204 VisitTryTruncateDouble(this, kPPC_DoubleToUint64, node); 1205} 1206 1207 1208void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) { 1209 VisitTryTruncateDouble(this, kPPC_DoubleToUint64, node); 1210} 1211 1212 1213void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { 1214 // TODO(mbrandy): inspect input to see if nop is appropriate. 1215 VisitRR(this, kPPC_ExtendSignWord32, node); 1216} 1217 1218 1219void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { 1220 // TODO(mbrandy): inspect input to see if nop is appropriate. 1221 VisitRR(this, kPPC_Uint32ToUint64, node); 1222} 1223#endif 1224 1225 1226void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { 1227 VisitRR(this, kPPC_DoubleToFloat32, node); 1228} 1229 1230void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) { 1231 VisitRR(this, kArchTruncateDoubleToI, node); 1232} 1233 1234void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) { 1235 VisitRR(this, kPPC_DoubleToInt32, node); 1236} 1237 1238 1239void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) { 1240 VisitRR(this, kPPC_DoubleToInt32, node); 1241} 1242 1243 1244void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) { 1245 VisitRR(this, kPPC_DoubleToUint32, node); 1246} 1247 1248 1249#if V8_TARGET_ARCH_PPC64 1250void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { 1251 // TODO(mbrandy): inspect input to see if nop is appropriate. 1252 VisitRR(this, kPPC_Int64ToInt32, node); 1253} 1254 1255 1256void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) { 1257 VisitRR(this, kPPC_Int64ToFloat32, node); 1258} 1259 1260 1261void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) { 1262 VisitRR(this, kPPC_Int64ToDouble, node); 1263} 1264 1265 1266void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) { 1267 VisitRR(this, kPPC_Uint64ToFloat32, node); 1268} 1269 1270 1271void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) { 1272 VisitRR(this, kPPC_Uint64ToDouble, node); 1273} 1274#endif 1275 1276 1277void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) { 1278 VisitRR(this, kPPC_BitcastFloat32ToInt32, node); 1279} 1280 1281 1282#if V8_TARGET_ARCH_PPC64 1283void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) { 1284 VisitRR(this, kPPC_BitcastDoubleToInt64, node); 1285} 1286#endif 1287 1288 1289void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { 1290 VisitRR(this, kPPC_BitcastInt32ToFloat32, node); 1291} 1292 1293 1294#if V8_TARGET_ARCH_PPC64 1295void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) { 1296 VisitRR(this, kPPC_BitcastInt64ToDouble, node); 1297} 1298#endif 1299 1300 1301void InstructionSelector::VisitFloat32Add(Node* node) { 1302 VisitRRR(this, kPPC_AddDouble | MiscField::encode(1), node); 1303} 1304 1305 1306void InstructionSelector::VisitFloat64Add(Node* node) { 1307 // TODO(mbrandy): detect multiply-add 1308 VisitRRR(this, kPPC_AddDouble, node); 1309} 1310 1311 1312void InstructionSelector::VisitFloat32Sub(Node* node) { 1313 VisitRRR(this, kPPC_SubDouble | MiscField::encode(1), node); 1314} 1315 1316void InstructionSelector::VisitFloat64Sub(Node* node) { 1317 // TODO(mbrandy): detect multiply-subtract 1318 VisitRRR(this, kPPC_SubDouble, node); 1319} 1320 1321void InstructionSelector::VisitFloat32Mul(Node* node) { 1322 VisitRRR(this, kPPC_MulDouble | MiscField::encode(1), node); 1323} 1324 1325 1326void InstructionSelector::VisitFloat64Mul(Node* node) { 1327 // TODO(mbrandy): detect negate 1328 VisitRRR(this, kPPC_MulDouble, node); 1329} 1330 1331 1332void InstructionSelector::VisitFloat32Div(Node* node) { 1333 VisitRRR(this, kPPC_DivDouble | MiscField::encode(1), node); 1334} 1335 1336 1337void InstructionSelector::VisitFloat64Div(Node* node) { 1338 VisitRRR(this, kPPC_DivDouble, node); 1339} 1340 1341 1342void InstructionSelector::VisitFloat64Mod(Node* node) { 1343 PPCOperandGenerator g(this); 1344 Emit(kPPC_ModDouble, g.DefineAsFixed(node, d1), 1345 g.UseFixed(node->InputAt(0), d1), 1346 g.UseFixed(node->InputAt(1), d2))->MarkAsCall(); 1347} 1348 1349void InstructionSelector::VisitFloat32Max(Node* node) { 1350 VisitRRR(this, kPPC_MaxDouble | MiscField::encode(1), node); 1351} 1352 1353void InstructionSelector::VisitFloat64Max(Node* node) { 1354 VisitRRR(this, kPPC_MaxDouble, node); 1355} 1356 1357 1358void InstructionSelector::VisitFloat64SilenceNaN(Node* node) { 1359 VisitRR(this, kPPC_Float64SilenceNaN, node); 1360} 1361 1362void InstructionSelector::VisitFloat32Min(Node* node) { 1363 VisitRRR(this, kPPC_MinDouble | MiscField::encode(1), node); 1364} 1365 1366void InstructionSelector::VisitFloat64Min(Node* node) { 1367 VisitRRR(this, kPPC_MinDouble, node); 1368} 1369 1370 1371void InstructionSelector::VisitFloat32Abs(Node* node) { 1372 VisitRR(this, kPPC_AbsDouble | MiscField::encode(1), node); 1373} 1374 1375 1376void InstructionSelector::VisitFloat64Abs(Node* node) { 1377 VisitRR(this, kPPC_AbsDouble, node); 1378} 1379 1380void InstructionSelector::VisitFloat32Sqrt(Node* node) { 1381 VisitRR(this, kPPC_SqrtDouble | MiscField::encode(1), node); 1382} 1383 1384void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, 1385 InstructionCode opcode) { 1386 PPCOperandGenerator g(this); 1387 Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1)) 1388 ->MarkAsCall(); 1389} 1390 1391void InstructionSelector::VisitFloat64Ieee754Binop(Node* node, 1392 InstructionCode opcode) { 1393 PPCOperandGenerator g(this); 1394 Emit(opcode, g.DefineAsFixed(node, d1), 1395 g.UseFixed(node->InputAt(0), d1), 1396 g.UseFixed(node->InputAt(1), d2))->MarkAsCall(); 1397} 1398 1399void InstructionSelector::VisitFloat64Sqrt(Node* node) { 1400 VisitRR(this, kPPC_SqrtDouble, node); 1401} 1402 1403 1404void InstructionSelector::VisitFloat32RoundDown(Node* node) { 1405 VisitRR(this, kPPC_FloorDouble | MiscField::encode(1), node); 1406} 1407 1408 1409void InstructionSelector::VisitFloat64RoundDown(Node* node) { 1410 VisitRR(this, kPPC_FloorDouble, node); 1411} 1412 1413 1414void InstructionSelector::VisitFloat32RoundUp(Node* node) { 1415 VisitRR(this, kPPC_CeilDouble | MiscField::encode(1), node); 1416} 1417 1418 1419void InstructionSelector::VisitFloat64RoundUp(Node* node) { 1420 VisitRR(this, kPPC_CeilDouble, node); 1421} 1422 1423 1424void InstructionSelector::VisitFloat32RoundTruncate(Node* node) { 1425 VisitRR(this, kPPC_TruncateDouble | MiscField::encode(1), node); 1426} 1427 1428 1429void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { 1430 VisitRR(this, kPPC_TruncateDouble, node); 1431} 1432 1433 1434void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { 1435 VisitRR(this, kPPC_RoundDouble, node); 1436} 1437 1438 1439void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { 1440 UNREACHABLE(); 1441} 1442 1443 1444void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { 1445 UNREACHABLE(); 1446} 1447 1448void InstructionSelector::VisitFloat32Neg(Node* node) { 1449 VisitRR(this, kPPC_NegDouble, node); 1450} 1451 1452void InstructionSelector::VisitFloat64Neg(Node* node) { 1453 VisitRR(this, kPPC_NegDouble, node); 1454} 1455 1456void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { 1457 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1458 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); 1459 return VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32, 1460 kInt16Imm, &cont); 1461 } 1462 FlagsContinuation cont; 1463 VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32, kInt16Imm, 1464 &cont); 1465} 1466 1467 1468void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { 1469 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1470 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); 1471 return VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32, 1472 kInt16Imm_Negate, &cont); 1473 } 1474 FlagsContinuation cont; 1475 VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32, 1476 kInt16Imm_Negate, &cont); 1477} 1478 1479 1480#if V8_TARGET_ARCH_PPC64 1481void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { 1482 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1483 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); 1484 return VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm, 1485 &cont); 1486 } 1487 FlagsContinuation cont; 1488 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm, &cont); 1489} 1490 1491 1492void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { 1493 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1494 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); 1495 return VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate, 1496 &cont); 1497 } 1498 FlagsContinuation cont; 1499 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate, &cont); 1500} 1501#endif 1502 1503 1504static bool CompareLogical(FlagsContinuation* cont) { 1505 switch (cont->condition()) { 1506 case kUnsignedLessThan: 1507 case kUnsignedGreaterThanOrEqual: 1508 case kUnsignedLessThanOrEqual: 1509 case kUnsignedGreaterThan: 1510 return true; 1511 default: 1512 return false; 1513 } 1514 UNREACHABLE(); 1515 return false; 1516} 1517 1518 1519namespace { 1520 1521// Shared routine for multiple compare operations. 1522void VisitCompare(InstructionSelector* selector, InstructionCode opcode, 1523 InstructionOperand left, InstructionOperand right, 1524 FlagsContinuation* cont) { 1525 PPCOperandGenerator g(selector); 1526 opcode = cont->Encode(opcode); 1527 if (cont->IsBranch()) { 1528 selector->Emit(opcode, g.NoOutput(), left, right, 1529 g.Label(cont->true_block()), g.Label(cont->false_block())); 1530 } else if (cont->IsDeoptimize()) { 1531 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->reason(), 1532 cont->frame_state()); 1533 } else { 1534 DCHECK(cont->IsSet()); 1535 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); 1536 } 1537} 1538 1539 1540// Shared routine for multiple word compare operations. 1541void VisitWordCompare(InstructionSelector* selector, Node* node, 1542 InstructionCode opcode, FlagsContinuation* cont, 1543 bool commutative, ImmediateMode immediate_mode) { 1544 PPCOperandGenerator g(selector); 1545 Node* left = node->InputAt(0); 1546 Node* right = node->InputAt(1); 1547 1548 // Match immediates on left or right side of comparison. 1549 if (g.CanBeImmediate(right, immediate_mode)) { 1550 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), 1551 cont); 1552 } else if (g.CanBeImmediate(left, immediate_mode)) { 1553 if (!commutative) cont->Commute(); 1554 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), 1555 cont); 1556 } else { 1557 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), 1558 cont); 1559 } 1560} 1561 1562 1563void VisitWord32Compare(InstructionSelector* selector, Node* node, 1564 FlagsContinuation* cont) { 1565 ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm); 1566 VisitWordCompare(selector, node, kPPC_Cmp32, cont, false, mode); 1567} 1568 1569 1570#if V8_TARGET_ARCH_PPC64 1571void VisitWord64Compare(InstructionSelector* selector, Node* node, 1572 FlagsContinuation* cont) { 1573 ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm); 1574 VisitWordCompare(selector, node, kPPC_Cmp64, cont, false, mode); 1575} 1576#endif 1577 1578 1579// Shared routine for multiple float32 compare operations. 1580void VisitFloat32Compare(InstructionSelector* selector, Node* node, 1581 FlagsContinuation* cont) { 1582 PPCOperandGenerator g(selector); 1583 Node* left = node->InputAt(0); 1584 Node* right = node->InputAt(1); 1585 VisitCompare(selector, kPPC_CmpDouble, g.UseRegister(left), 1586 g.UseRegister(right), cont); 1587} 1588 1589 1590// Shared routine for multiple float64 compare operations. 1591void VisitFloat64Compare(InstructionSelector* selector, Node* node, 1592 FlagsContinuation* cont) { 1593 PPCOperandGenerator g(selector); 1594 Node* left = node->InputAt(0); 1595 Node* right = node->InputAt(1); 1596 VisitCompare(selector, kPPC_CmpDouble, g.UseRegister(left), 1597 g.UseRegister(right), cont); 1598} 1599 1600 1601// Shared routine for word comparisons against zero. 1602void VisitWordCompareZero(InstructionSelector* selector, Node* user, 1603 Node* value, InstructionCode opcode, 1604 FlagsContinuation* cont) { 1605 // Try to combine with comparisons against 0 by simply inverting the branch. 1606 while (value->opcode() == IrOpcode::kWord32Equal && 1607 selector->CanCover(user, value)) { 1608 Int32BinopMatcher m(value); 1609 if (!m.right().Is(0)) break; 1610 1611 user = value; 1612 value = m.left().node(); 1613 cont->Negate(); 1614 } 1615 1616 if (selector->CanCover(user, value)) { 1617 switch (value->opcode()) { 1618 case IrOpcode::kWord32Equal: 1619 cont->OverwriteAndNegateIfEqual(kEqual); 1620 return VisitWord32Compare(selector, value, cont); 1621 case IrOpcode::kInt32LessThan: 1622 cont->OverwriteAndNegateIfEqual(kSignedLessThan); 1623 return VisitWord32Compare(selector, value, cont); 1624 case IrOpcode::kInt32LessThanOrEqual: 1625 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); 1626 return VisitWord32Compare(selector, value, cont); 1627 case IrOpcode::kUint32LessThan: 1628 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); 1629 return VisitWord32Compare(selector, value, cont); 1630 case IrOpcode::kUint32LessThanOrEqual: 1631 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); 1632 return VisitWord32Compare(selector, value, cont); 1633#if V8_TARGET_ARCH_PPC64 1634 case IrOpcode::kWord64Equal: 1635 cont->OverwriteAndNegateIfEqual(kEqual); 1636 return VisitWord64Compare(selector, value, cont); 1637 case IrOpcode::kInt64LessThan: 1638 cont->OverwriteAndNegateIfEqual(kSignedLessThan); 1639 return VisitWord64Compare(selector, value, cont); 1640 case IrOpcode::kInt64LessThanOrEqual: 1641 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); 1642 return VisitWord64Compare(selector, value, cont); 1643 case IrOpcode::kUint64LessThan: 1644 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); 1645 return VisitWord64Compare(selector, value, cont); 1646 case IrOpcode::kUint64LessThanOrEqual: 1647 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); 1648 return VisitWord64Compare(selector, value, cont); 1649#endif 1650 case IrOpcode::kFloat32Equal: 1651 cont->OverwriteAndNegateIfEqual(kEqual); 1652 return VisitFloat32Compare(selector, value, cont); 1653 case IrOpcode::kFloat32LessThan: 1654 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); 1655 return VisitFloat32Compare(selector, value, cont); 1656 case IrOpcode::kFloat32LessThanOrEqual: 1657 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); 1658 return VisitFloat32Compare(selector, value, cont); 1659 case IrOpcode::kFloat64Equal: 1660 cont->OverwriteAndNegateIfEqual(kEqual); 1661 return VisitFloat64Compare(selector, value, cont); 1662 case IrOpcode::kFloat64LessThan: 1663 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); 1664 return VisitFloat64Compare(selector, value, cont); 1665 case IrOpcode::kFloat64LessThanOrEqual: 1666 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); 1667 return VisitFloat64Compare(selector, value, cont); 1668 case IrOpcode::kProjection: 1669 // Check if this is the overflow output projection of an 1670 // <Operation>WithOverflow node. 1671 if (ProjectionIndexOf(value->op()) == 1u) { 1672 // We cannot combine the <Operation>WithOverflow with this branch 1673 // unless the 0th projection (the use of the actual value of the 1674 // <Operation> is either nullptr, which means there's no use of the 1675 // actual value, or was already defined, which means it is scheduled 1676 // *AFTER* this branch). 1677 Node* const node = value->InputAt(0); 1678 Node* const result = NodeProperties::FindProjection(node, 0); 1679 if (result == nullptr || selector->IsDefined(result)) { 1680 switch (node->opcode()) { 1681 case IrOpcode::kInt32AddWithOverflow: 1682 cont->OverwriteAndNegateIfEqual(kOverflow); 1683 return VisitBinop<Int32BinopMatcher>( 1684 selector, node, kPPC_AddWithOverflow32, kInt16Imm, cont); 1685 case IrOpcode::kInt32SubWithOverflow: 1686 cont->OverwriteAndNegateIfEqual(kOverflow); 1687 return VisitBinop<Int32BinopMatcher>(selector, node, 1688 kPPC_SubWithOverflow32, 1689 kInt16Imm_Negate, cont); 1690 case IrOpcode::kInt32MulWithOverflow: 1691 cont->OverwriteAndNegateIfEqual(kNotEqual); 1692 return EmitInt32MulWithOverflow(selector, node, cont); 1693#if V8_TARGET_ARCH_PPC64 1694 case IrOpcode::kInt64AddWithOverflow: 1695 cont->OverwriteAndNegateIfEqual(kOverflow); 1696 return VisitBinop<Int64BinopMatcher>(selector, node, kPPC_Add, 1697 kInt16Imm, cont); 1698 case IrOpcode::kInt64SubWithOverflow: 1699 cont->OverwriteAndNegateIfEqual(kOverflow); 1700 return VisitBinop<Int64BinopMatcher>(selector, node, kPPC_Sub, 1701 kInt16Imm_Negate, cont); 1702#endif 1703 default: 1704 break; 1705 } 1706 } 1707 } 1708 break; 1709 case IrOpcode::kInt32Sub: 1710 return VisitWord32Compare(selector, value, cont); 1711 case IrOpcode::kWord32And: 1712 // TODO(mbandy): opportunity for rlwinm? 1713 return VisitWordCompare(selector, value, kPPC_Tst32, cont, true, 1714 kInt16Imm_Unsigned); 1715// TODO(mbrandy): Handle? 1716// case IrOpcode::kInt32Add: 1717// case IrOpcode::kWord32Or: 1718// case IrOpcode::kWord32Xor: 1719// case IrOpcode::kWord32Sar: 1720// case IrOpcode::kWord32Shl: 1721// case IrOpcode::kWord32Shr: 1722// case IrOpcode::kWord32Ror: 1723#if V8_TARGET_ARCH_PPC64 1724 case IrOpcode::kInt64Sub: 1725 return VisitWord64Compare(selector, value, cont); 1726 case IrOpcode::kWord64And: 1727 // TODO(mbandy): opportunity for rldic? 1728 return VisitWordCompare(selector, value, kPPC_Tst64, cont, true, 1729 kInt16Imm_Unsigned); 1730// TODO(mbrandy): Handle? 1731// case IrOpcode::kInt64Add: 1732// case IrOpcode::kWord64Or: 1733// case IrOpcode::kWord64Xor: 1734// case IrOpcode::kWord64Sar: 1735// case IrOpcode::kWord64Shl: 1736// case IrOpcode::kWord64Shr: 1737// case IrOpcode::kWord64Ror: 1738#endif 1739 default: 1740 break; 1741 } 1742 } 1743 1744 // Branch could not be combined with a compare, emit compare against 0. 1745 PPCOperandGenerator g(selector); 1746 VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0), 1747 cont); 1748} 1749 1750 1751void VisitWord32CompareZero(InstructionSelector* selector, Node* user, 1752 Node* value, FlagsContinuation* cont) { 1753 VisitWordCompareZero(selector, user, value, kPPC_Cmp32, cont); 1754} 1755 1756 1757#if V8_TARGET_ARCH_PPC64 1758void VisitWord64CompareZero(InstructionSelector* selector, Node* user, 1759 Node* value, FlagsContinuation* cont) { 1760 VisitWordCompareZero(selector, user, value, kPPC_Cmp64, cont); 1761} 1762#endif 1763 1764} // namespace 1765 1766 1767void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, 1768 BasicBlock* fbranch) { 1769 FlagsContinuation cont(kNotEqual, tbranch, fbranch); 1770 VisitWord32CompareZero(this, branch, branch->InputAt(0), &cont); 1771} 1772 1773void InstructionSelector::VisitDeoptimizeIf(Node* node) { 1774 FlagsContinuation cont = FlagsContinuation::ForDeoptimize( 1775 kNotEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1)); 1776 VisitWord32CompareZero(this, node, node->InputAt(0), &cont); 1777} 1778 1779void InstructionSelector::VisitDeoptimizeUnless(Node* node) { 1780 FlagsContinuation cont = FlagsContinuation::ForDeoptimize( 1781 kEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1)); 1782 VisitWord32CompareZero(this, node, node->InputAt(0), &cont); 1783} 1784 1785void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { 1786 PPCOperandGenerator g(this); 1787 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); 1788 1789 // Emit either ArchTableSwitch or ArchLookupSwitch. 1790 size_t table_space_cost = 4 + sw.value_range; 1791 size_t table_time_cost = 3; 1792 size_t lookup_space_cost = 3 + 2 * sw.case_count; 1793 size_t lookup_time_cost = sw.case_count; 1794 if (sw.case_count > 0 && 1795 table_space_cost + 3 * table_time_cost <= 1796 lookup_space_cost + 3 * lookup_time_cost && 1797 sw.min_value > std::numeric_limits<int32_t>::min()) { 1798 InstructionOperand index_operand = value_operand; 1799 if (sw.min_value) { 1800 index_operand = g.TempRegister(); 1801 Emit(kPPC_Sub, index_operand, value_operand, 1802 g.TempImmediate(sw.min_value)); 1803 } 1804 // Generate a table lookup. 1805 return EmitTableSwitch(sw, index_operand); 1806 } 1807 1808 // Generate a sequence of conditional jumps. 1809 return EmitLookupSwitch(sw, value_operand); 1810} 1811 1812 1813void InstructionSelector::VisitWord32Equal(Node* const node) { 1814 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); 1815 Int32BinopMatcher m(node); 1816 if (m.right().Is(0)) { 1817 return VisitWord32CompareZero(this, m.node(), m.left().node(), &cont); 1818 } 1819 VisitWord32Compare(this, node, &cont); 1820} 1821 1822 1823void InstructionSelector::VisitInt32LessThan(Node* node) { 1824 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); 1825 VisitWord32Compare(this, node, &cont); 1826} 1827 1828 1829void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { 1830 FlagsContinuation cont = 1831 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); 1832 VisitWord32Compare(this, node, &cont); 1833} 1834 1835 1836void InstructionSelector::VisitUint32LessThan(Node* node) { 1837 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); 1838 VisitWord32Compare(this, node, &cont); 1839} 1840 1841 1842void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { 1843 FlagsContinuation cont = 1844 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); 1845 VisitWord32Compare(this, node, &cont); 1846} 1847 1848 1849#if V8_TARGET_ARCH_PPC64 1850void InstructionSelector::VisitWord64Equal(Node* const node) { 1851 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); 1852 Int64BinopMatcher m(node); 1853 if (m.right().Is(0)) { 1854 return VisitWord64CompareZero(this, m.node(), m.left().node(), &cont); 1855 } 1856 VisitWord64Compare(this, node, &cont); 1857} 1858 1859 1860void InstructionSelector::VisitInt64LessThan(Node* node) { 1861 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); 1862 VisitWord64Compare(this, node, &cont); 1863} 1864 1865 1866void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { 1867 FlagsContinuation cont = 1868 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); 1869 VisitWord64Compare(this, node, &cont); 1870} 1871 1872 1873void InstructionSelector::VisitUint64LessThan(Node* node) { 1874 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); 1875 VisitWord64Compare(this, node, &cont); 1876} 1877 1878 1879void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { 1880 FlagsContinuation cont = 1881 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); 1882 VisitWord64Compare(this, node, &cont); 1883} 1884#endif 1885 1886void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { 1887 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1888 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); 1889 return EmitInt32MulWithOverflow(this, node, &cont); 1890 } 1891 FlagsContinuation cont; 1892 EmitInt32MulWithOverflow(this, node, &cont); 1893} 1894 1895 1896void InstructionSelector::VisitFloat32Equal(Node* node) { 1897 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); 1898 VisitFloat32Compare(this, node, &cont); 1899} 1900 1901 1902void InstructionSelector::VisitFloat32LessThan(Node* node) { 1903 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); 1904 VisitFloat32Compare(this, node, &cont); 1905} 1906 1907 1908void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { 1909 FlagsContinuation cont = 1910 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); 1911 VisitFloat32Compare(this, node, &cont); 1912} 1913 1914 1915void InstructionSelector::VisitFloat64Equal(Node* node) { 1916 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); 1917 VisitFloat64Compare(this, node, &cont); 1918} 1919 1920 1921void InstructionSelector::VisitFloat64LessThan(Node* node) { 1922 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); 1923 VisitFloat64Compare(this, node, &cont); 1924} 1925 1926 1927void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { 1928 FlagsContinuation cont = 1929 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); 1930 VisitFloat64Compare(this, node, &cont); 1931} 1932 1933 1934void InstructionSelector::EmitPrepareArguments( 1935 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor, 1936 Node* node) { 1937 PPCOperandGenerator g(this); 1938 1939 // Prepare for C function call. 1940 if (descriptor->IsCFunctionCall()) { 1941 Emit(kArchPrepareCallCFunction | 1942 MiscField::encode(static_cast<int>(descriptor->ParameterCount())), 1943 0, nullptr, 0, nullptr); 1944 1945 // Poke any stack arguments. 1946 int slot = kStackFrameExtraParamSlot; 1947 for (PushParameter input : (*arguments)) { 1948 Emit(kPPC_StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()), 1949 g.TempImmediate(slot)); 1950 ++slot; 1951 } 1952 } else { 1953 // Push any stack arguments. 1954 int num_slots = static_cast<int>(descriptor->StackParameterCount()); 1955 int slot = 0; 1956 for (PushParameter input : (*arguments)) { 1957 if (slot == 0) { 1958 DCHECK(input.node()); 1959 Emit(kPPC_PushFrame, g.NoOutput(), g.UseRegister(input.node()), 1960 g.TempImmediate(num_slots)); 1961 } else { 1962 // Skip any alignment holes in pushed nodes. 1963 if (input.node()) { 1964 Emit(kPPC_StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()), 1965 g.TempImmediate(slot)); 1966 } 1967 } 1968 ++slot; 1969 } 1970 } 1971} 1972 1973 1974bool InstructionSelector::IsTailCallAddressImmediate() { return false; } 1975 1976int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; } 1977 1978void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { 1979 PPCOperandGenerator g(this); 1980 Emit(kPPC_DoubleExtractLowWord32, g.DefineAsRegister(node), 1981 g.UseRegister(node->InputAt(0))); 1982} 1983 1984 1985void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { 1986 PPCOperandGenerator g(this); 1987 Emit(kPPC_DoubleExtractHighWord32, g.DefineAsRegister(node), 1988 g.UseRegister(node->InputAt(0))); 1989} 1990 1991 1992void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { 1993 PPCOperandGenerator g(this); 1994 Node* left = node->InputAt(0); 1995 Node* right = node->InputAt(1); 1996 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 && 1997 CanCover(node, left)) { 1998 left = left->InputAt(1); 1999 Emit(kPPC_DoubleConstruct, g.DefineAsRegister(node), g.UseRegister(left), 2000 g.UseRegister(right)); 2001 return; 2002 } 2003 Emit(kPPC_DoubleInsertLowWord32, g.DefineSameAsFirst(node), 2004 g.UseRegister(left), g.UseRegister(right)); 2005} 2006 2007 2008void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { 2009 PPCOperandGenerator g(this); 2010 Node* left = node->InputAt(0); 2011 Node* right = node->InputAt(1); 2012 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 && 2013 CanCover(node, left)) { 2014 left = left->InputAt(1); 2015 Emit(kPPC_DoubleConstruct, g.DefineAsRegister(node), g.UseRegister(right), 2016 g.UseRegister(left)); 2017 return; 2018 } 2019 Emit(kPPC_DoubleInsertHighWord32, g.DefineSameAsFirst(node), 2020 g.UseRegister(left), g.UseRegister(right)); 2021} 2022 2023void InstructionSelector::VisitAtomicLoad(Node* node) { 2024 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); 2025 PPCOperandGenerator g(this); 2026 Node* base = node->InputAt(0); 2027 Node* index = node->InputAt(1); 2028 ArchOpcode opcode = kArchNop; 2029 switch (load_rep.representation()) { 2030 case MachineRepresentation::kWord8: 2031 opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8; 2032 break; 2033 case MachineRepresentation::kWord16: 2034 opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16; 2035 break; 2036 case MachineRepresentation::kWord32: 2037 opcode = kAtomicLoadWord32; 2038 break; 2039 default: 2040 UNREACHABLE(); 2041 return; 2042 } 2043 Emit(opcode | AddressingModeField::encode(kMode_MRR), 2044 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); 2045} 2046 2047void InstructionSelector::VisitAtomicStore(Node* node) { 2048 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op()); 2049 PPCOperandGenerator g(this); 2050 Node* base = node->InputAt(0); 2051 Node* index = node->InputAt(1); 2052 Node* value = node->InputAt(2); 2053 ArchOpcode opcode = kArchNop; 2054 switch (rep) { 2055 case MachineRepresentation::kWord8: 2056 opcode = kAtomicStoreWord8; 2057 break; 2058 case MachineRepresentation::kWord16: 2059 opcode = kAtomicStoreWord16; 2060 break; 2061 case MachineRepresentation::kWord32: 2062 opcode = kAtomicStoreWord32; 2063 break; 2064 default: 2065 UNREACHABLE(); 2066 return; 2067 } 2068 2069 InstructionOperand inputs[4]; 2070 size_t input_count = 0; 2071 inputs[input_count++] = g.UseUniqueRegister(base); 2072 inputs[input_count++] = g.UseUniqueRegister(index); 2073 inputs[input_count++] = g.UseUniqueRegister(value); 2074 Emit(opcode | AddressingModeField::encode(kMode_MRR), 2075 0, nullptr, input_count, inputs); 2076} 2077 2078// static 2079MachineOperatorBuilder::Flags 2080InstructionSelector::SupportedMachineOperatorFlags() { 2081 return MachineOperatorBuilder::kFloat32RoundDown | 2082 MachineOperatorBuilder::kFloat64RoundDown | 2083 MachineOperatorBuilder::kFloat32RoundUp | 2084 MachineOperatorBuilder::kFloat64RoundUp | 2085 MachineOperatorBuilder::kFloat32RoundTruncate | 2086 MachineOperatorBuilder::kFloat64RoundTruncate | 2087 MachineOperatorBuilder::kFloat64RoundTiesAway | 2088 MachineOperatorBuilder::kWord32Popcnt | 2089 MachineOperatorBuilder::kWord64Popcnt; 2090 // We omit kWord32ShiftIsSafe as s[rl]w use 0x3f as a mask rather than 0x1f. 2091} 2092 2093// static 2094MachineOperatorBuilder::AlignmentRequirements 2095InstructionSelector::AlignmentRequirements() { 2096 return MachineOperatorBuilder::AlignmentRequirements:: 2097 FullUnalignedAccessSupport(); 2098} 2099 2100} // namespace compiler 2101} // namespace internal 2102} // namespace v8 2103