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/code-generator.h" 6 7 #include "src/assembler-inl.h" 8 #include "src/callable.h" 9 #include "src/compiler/code-generator-impl.h" 10 #include "src/compiler/gap-resolver.h" 11 #include "src/compiler/node-matchers.h" 12 #include "src/compiler/osr.h" 13 #include "src/double.h" 14 #include "src/optimized-compilation-info.h" 15 #include "src/ppc/macro-assembler-ppc.h" 16 #include "src/wasm/wasm-objects.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace compiler { 21 22 #define __ tasm()-> 23 24 #define kScratchReg r11 25 26 27 // Adds PPC-specific methods to convert InstructionOperands. 28 class PPCOperandConverter final : public InstructionOperandConverter { 29 public: 30 PPCOperandConverter(CodeGenerator* gen, Instruction* instr) 31 : InstructionOperandConverter(gen, instr) {} 32 33 size_t OutputCount() { return instr_->OutputCount(); } 34 35 RCBit OutputRCBit() const { 36 switch (instr_->flags_mode()) { 37 case kFlags_branch: 38 case kFlags_branch_and_poison: 39 case kFlags_deoptimize: 40 case kFlags_deoptimize_and_poison: 41 case kFlags_set: 42 case kFlags_trap: 43 return SetRC; 44 case kFlags_none: 45 return LeaveRC; 46 } 47 UNREACHABLE(); 48 } 49 50 bool CompareLogical() const { 51 switch (instr_->flags_condition()) { 52 case kUnsignedLessThan: 53 case kUnsignedGreaterThanOrEqual: 54 case kUnsignedLessThanOrEqual: 55 case kUnsignedGreaterThan: 56 return true; 57 default: 58 return false; 59 } 60 UNREACHABLE(); 61 } 62 63 Operand InputImmediate(size_t index) { 64 Constant constant = ToConstant(instr_->InputAt(index)); 65 switch (constant.type()) { 66 case Constant::kInt32: 67 return Operand(constant.ToInt32()); 68 case Constant::kFloat32: 69 return Operand::EmbeddedNumber(constant.ToFloat32()); 70 case Constant::kFloat64: 71 return Operand::EmbeddedNumber(constant.ToFloat64().value()); 72 case Constant::kInt64: 73 #if V8_TARGET_ARCH_PPC64 74 return Operand(constant.ToInt64()); 75 #endif 76 case Constant::kExternalReference: 77 case Constant::kHeapObject: 78 case Constant::kRpoNumber: 79 break; 80 } 81 UNREACHABLE(); 82 } 83 84 MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) { 85 const size_t index = *first_index; 86 *mode = AddressingModeField::decode(instr_->opcode()); 87 switch (*mode) { 88 case kMode_None: 89 break; 90 case kMode_MRI: 91 *first_index += 2; 92 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); 93 case kMode_MRR: 94 *first_index += 2; 95 return MemOperand(InputRegister(index + 0), InputRegister(index + 1)); 96 } 97 UNREACHABLE(); 98 } 99 100 MemOperand MemoryOperand(AddressingMode* mode, size_t first_index = 0) { 101 return MemoryOperand(mode, &first_index); 102 } 103 104 MemOperand ToMemOperand(InstructionOperand* op) const { 105 DCHECK_NOT_NULL(op); 106 DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); 107 return SlotToMemOperand(AllocatedOperand::cast(op)->index()); 108 } 109 110 MemOperand SlotToMemOperand(int slot) const { 111 FrameOffset offset = frame_access_state()->GetFrameOffset(slot); 112 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); 113 } 114 }; 115 116 117 static inline bool HasRegisterInput(Instruction* instr, size_t index) { 118 return instr->InputAt(index)->IsRegister(); 119 } 120 121 122 namespace { 123 124 class OutOfLineRecordWrite final : public OutOfLineCode { 125 public: 126 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register offset, 127 Register value, Register scratch0, Register scratch1, 128 RecordWriteMode mode) 129 : OutOfLineCode(gen), 130 object_(object), 131 offset_(offset), 132 offset_immediate_(0), 133 value_(value), 134 scratch0_(scratch0), 135 scratch1_(scratch1), 136 mode_(mode), 137 must_save_lr_(!gen->frame_access_state()->has_frame()), 138 zone_(gen->zone()) {} 139 140 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t offset, 141 Register value, Register scratch0, Register scratch1, 142 RecordWriteMode mode) 143 : OutOfLineCode(gen), 144 object_(object), 145 offset_(no_reg), 146 offset_immediate_(offset), 147 value_(value), 148 scratch0_(scratch0), 149 scratch1_(scratch1), 150 mode_(mode), 151 must_save_lr_(!gen->frame_access_state()->has_frame()), 152 zone_(gen->zone()) {} 153 154 void SaveRegisters(RegList registers) { 155 DCHECK_LT(0, NumRegs(registers)); 156 RegList regs = 0; 157 for (int i = 0; i < Register::kNumRegisters; ++i) { 158 if ((registers >> i) & 1u) { 159 regs |= Register::from_code(i).bit(); 160 } 161 } 162 163 __ MultiPush(regs); 164 } 165 166 void RestoreRegisters(RegList registers) { 167 DCHECK_LT(0, NumRegs(registers)); 168 RegList regs = 0; 169 for (int i = 0; i < Register::kNumRegisters; ++i) { 170 if ((registers >> i) & 1u) { 171 regs |= Register::from_code(i).bit(); 172 } 173 } 174 __ MultiPop(regs); 175 } 176 177 void Generate() final { 178 ConstantPoolUnavailableScope constant_pool_unavailable(tasm()); 179 if (mode_ > RecordWriteMode::kValueIsPointer) { 180 __ JumpIfSmi(value_, exit()); 181 } 182 __ CheckPageFlag(value_, scratch0_, 183 MemoryChunk::kPointersToHereAreInterestingMask, eq, 184 exit()); 185 if (offset_ == no_reg) { 186 __ addi(scratch1_, object_, Operand(offset_immediate_)); 187 } else { 188 DCHECK_EQ(0, offset_immediate_); 189 __ add(scratch1_, object_, offset_); 190 } 191 RememberedSetAction const remembered_set_action = 192 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET 193 : OMIT_REMEMBERED_SET; 194 SaveFPRegsMode const save_fp_mode = 195 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; 196 if (must_save_lr_) { 197 // We need to save and restore lr if the frame was elided. 198 __ mflr(scratch0_); 199 __ Push(scratch0_); 200 } 201 __ CallRecordWriteStub(object_, scratch1_, remembered_set_action, 202 save_fp_mode); 203 if (must_save_lr_) { 204 // We need to save and restore lr if the frame was elided. 205 __ Pop(scratch0_); 206 __ mtlr(scratch0_); 207 } 208 } 209 210 private: 211 Register const object_; 212 Register const offset_; 213 int32_t const offset_immediate_; // Valid if offset_ == no_reg. 214 Register const value_; 215 Register const scratch0_; 216 Register const scratch1_; 217 RecordWriteMode const mode_; 218 bool must_save_lr_; 219 Zone* zone_; 220 }; 221 222 223 Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) { 224 switch (condition) { 225 case kEqual: 226 return eq; 227 case kNotEqual: 228 return ne; 229 case kSignedLessThan: 230 case kUnsignedLessThan: 231 return lt; 232 case kSignedGreaterThanOrEqual: 233 case kUnsignedGreaterThanOrEqual: 234 return ge; 235 case kSignedLessThanOrEqual: 236 case kUnsignedLessThanOrEqual: 237 return le; 238 case kSignedGreaterThan: 239 case kUnsignedGreaterThan: 240 return gt; 241 case kOverflow: 242 // Overflow checked for add/sub only. 243 switch (op) { 244 #if V8_TARGET_ARCH_PPC64 245 case kPPC_Add32: 246 case kPPC_Add64: 247 case kPPC_Sub: 248 #endif 249 case kPPC_AddWithOverflow32: 250 case kPPC_SubWithOverflow32: 251 return lt; 252 default: 253 break; 254 } 255 break; 256 case kNotOverflow: 257 switch (op) { 258 #if V8_TARGET_ARCH_PPC64 259 case kPPC_Add32: 260 case kPPC_Add64: 261 case kPPC_Sub: 262 #endif 263 case kPPC_AddWithOverflow32: 264 case kPPC_SubWithOverflow32: 265 return ge; 266 default: 267 break; 268 } 269 break; 270 default: 271 break; 272 } 273 UNREACHABLE(); 274 } 275 276 void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr, 277 PPCOperandConverter& i) { 278 const MemoryAccessMode access_mode = 279 static_cast<MemoryAccessMode>(MiscField::decode(instr->opcode())); 280 if (access_mode == kMemoryAccessPoisoned) { 281 Register value = i.OutputRegister(); 282 codegen->tasm()->and_(value, value, kSpeculationPoisonRegister); 283 } 284 } 285 286 } // namespace 287 288 #define ASSEMBLE_FLOAT_UNOP_RC(asm_instr, round) \ 289 do { \ 290 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \ 291 i.OutputRCBit()); \ 292 if (round) { \ 293 __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 294 } \ 295 } while (0) 296 297 #define ASSEMBLE_FLOAT_BINOP_RC(asm_instr, round) \ 298 do { \ 299 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \ 300 i.InputDoubleRegister(1), i.OutputRCBit()); \ 301 if (round) { \ 302 __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 303 } \ 304 } while (0) 305 306 #define ASSEMBLE_BINOP(asm_instr_reg, asm_instr_imm) \ 307 do { \ 308 if (HasRegisterInput(instr, 1)) { \ 309 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \ 310 i.InputRegister(1)); \ 311 } else { \ 312 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \ 313 i.InputImmediate(1)); \ 314 } \ 315 } while (0) 316 317 318 #define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm) \ 319 do { \ 320 if (HasRegisterInput(instr, 1)) { \ 321 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \ 322 i.InputRegister(1), i.OutputRCBit()); \ 323 } else { \ 324 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \ 325 i.InputImmediate(1), i.OutputRCBit()); \ 326 } \ 327 } while (0) 328 329 330 #define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm) \ 331 do { \ 332 if (HasRegisterInput(instr, 1)) { \ 333 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \ 334 i.InputRegister(1), i.OutputRCBit()); \ 335 } else { \ 336 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \ 337 i.InputInt32(1), i.OutputRCBit()); \ 338 } \ 339 } while (0) 340 341 342 #define ASSEMBLE_ADD_WITH_OVERFLOW() \ 343 do { \ 344 if (HasRegisterInput(instr, 1)) { \ 345 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \ 346 i.InputRegister(1), kScratchReg, r0); \ 347 } else { \ 348 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \ 349 i.InputInt32(1), kScratchReg, r0); \ 350 } \ 351 } while (0) 352 353 354 #define ASSEMBLE_SUB_WITH_OVERFLOW() \ 355 do { \ 356 if (HasRegisterInput(instr, 1)) { \ 357 __ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \ 358 i.InputRegister(1), kScratchReg, r0); \ 359 } else { \ 360 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \ 361 -i.InputInt32(1), kScratchReg, r0); \ 362 } \ 363 } while (0) 364 365 366 #if V8_TARGET_ARCH_PPC64 367 #define ASSEMBLE_ADD_WITH_OVERFLOW32() \ 368 do { \ 369 ASSEMBLE_ADD_WITH_OVERFLOW(); \ 370 __ extsw(kScratchReg, kScratchReg, SetRC); \ 371 } while (0) 372 373 #define ASSEMBLE_SUB_WITH_OVERFLOW32() \ 374 do { \ 375 ASSEMBLE_SUB_WITH_OVERFLOW(); \ 376 __ extsw(kScratchReg, kScratchReg, SetRC); \ 377 } while (0) 378 #else 379 #define ASSEMBLE_ADD_WITH_OVERFLOW32 ASSEMBLE_ADD_WITH_OVERFLOW 380 #define ASSEMBLE_SUB_WITH_OVERFLOW32 ASSEMBLE_SUB_WITH_OVERFLOW 381 #endif 382 383 384 #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \ 385 do { \ 386 const CRegister cr = cr0; \ 387 if (HasRegisterInput(instr, 1)) { \ 388 if (i.CompareLogical()) { \ 389 __ cmpl_instr(i.InputRegister(0), i.InputRegister(1), cr); \ 390 } else { \ 391 __ cmp_instr(i.InputRegister(0), i.InputRegister(1), cr); \ 392 } \ 393 } else { \ 394 if (i.CompareLogical()) { \ 395 __ cmpl_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \ 396 } else { \ 397 __ cmp_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \ 398 } \ 399 } \ 400 DCHECK_EQ(SetRC, i.OutputRCBit()); \ 401 } while (0) 402 403 404 #define ASSEMBLE_FLOAT_COMPARE(cmp_instr) \ 405 do { \ 406 const CRegister cr = cr0; \ 407 __ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1), cr); \ 408 DCHECK_EQ(SetRC, i.OutputRCBit()); \ 409 } while (0) 410 411 412 #define ASSEMBLE_MODULO(div_instr, mul_instr) \ 413 do { \ 414 const Register scratch = kScratchReg; \ 415 __ div_instr(scratch, i.InputRegister(0), i.InputRegister(1)); \ 416 __ mul_instr(scratch, scratch, i.InputRegister(1)); \ 417 __ sub(i.OutputRegister(), i.InputRegister(0), scratch, LeaveOE, \ 418 i.OutputRCBit()); \ 419 } while (0) 420 421 #define ASSEMBLE_FLOAT_MODULO() \ 422 do { \ 423 FrameScope scope(tasm(), StackFrame::MANUAL); \ 424 __ PrepareCallCFunction(0, 2, kScratchReg); \ 425 __ MovToFloatParameters(i.InputDoubleRegister(0), \ 426 i.InputDoubleRegister(1)); \ 427 __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); \ 428 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 429 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 430 } while (0) 431 432 #define ASSEMBLE_IEEE754_UNOP(name) \ 433 do { \ 434 /* TODO(bmeurer): We should really get rid of this special instruction, */ \ 435 /* and generate a CallAddress instruction instead. */ \ 436 FrameScope scope(tasm(), StackFrame::MANUAL); \ 437 __ PrepareCallCFunction(0, 1, kScratchReg); \ 438 __ MovToFloatParameter(i.InputDoubleRegister(0)); \ 439 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \ 440 /* Move the result in the double result register. */ \ 441 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 442 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 443 } while (0) 444 445 #define ASSEMBLE_IEEE754_BINOP(name) \ 446 do { \ 447 /* TODO(bmeurer): We should really get rid of this special instruction, */ \ 448 /* and generate a CallAddress instruction instead. */ \ 449 FrameScope scope(tasm(), StackFrame::MANUAL); \ 450 __ PrepareCallCFunction(0, 2, kScratchReg); \ 451 __ MovToFloatParameters(i.InputDoubleRegister(0), \ 452 i.InputDoubleRegister(1)); \ 453 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \ 454 /* Move the result in the double result register. */ \ 455 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 456 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 457 } while (0) 458 459 #define ASSEMBLE_FLOAT_MAX() \ 460 do { \ 461 DoubleRegister left_reg = i.InputDoubleRegister(0); \ 462 DoubleRegister right_reg = i.InputDoubleRegister(1); \ 463 DoubleRegister result_reg = i.OutputDoubleRegister(); \ 464 Label check_nan_left, check_zero, return_left, return_right, done; \ 465 __ fcmpu(left_reg, right_reg); \ 466 __ bunordered(&check_nan_left); \ 467 __ beq(&check_zero); \ 468 __ bge(&return_left); \ 469 __ b(&return_right); \ 470 \ 471 __ bind(&check_zero); \ 472 __ fcmpu(left_reg, kDoubleRegZero); \ 473 /* left == right != 0. */ \ 474 __ bne(&return_left); \ 475 /* At this point, both left and right are either 0 or -0. */ \ 476 __ fadd(result_reg, left_reg, right_reg); \ 477 __ b(&done); \ 478 \ 479 __ bind(&check_nan_left); \ 480 __ fcmpu(left_reg, left_reg); \ 481 /* left == NaN. */ \ 482 __ bunordered(&return_left); \ 483 __ bind(&return_right); \ 484 if (right_reg != result_reg) { \ 485 __ fmr(result_reg, right_reg); \ 486 } \ 487 __ b(&done); \ 488 \ 489 __ bind(&return_left); \ 490 if (left_reg != result_reg) { \ 491 __ fmr(result_reg, left_reg); \ 492 } \ 493 __ bind(&done); \ 494 } while (0) 495 496 #define ASSEMBLE_FLOAT_MIN() \ 497 do { \ 498 DoubleRegister left_reg = i.InputDoubleRegister(0); \ 499 DoubleRegister right_reg = i.InputDoubleRegister(1); \ 500 DoubleRegister result_reg = i.OutputDoubleRegister(); \ 501 Label check_nan_left, check_zero, return_left, return_right, done; \ 502 __ fcmpu(left_reg, right_reg); \ 503 __ bunordered(&check_nan_left); \ 504 __ beq(&check_zero); \ 505 __ ble(&return_left); \ 506 __ b(&return_right); \ 507 \ 508 __ bind(&check_zero); \ 509 __ fcmpu(left_reg, kDoubleRegZero); \ 510 /* left == right != 0. */ \ 511 __ bne(&return_left); \ 512 /* At this point, both left and right are either 0 or -0. */ \ 513 /* Min: The algorithm is: -((-L) + (-R)), which in case of L and R */ \ 514 /* being different registers is most efficiently expressed */ \ 515 /* as -((-L) - R). */ \ 516 __ fneg(left_reg, left_reg); \ 517 if (left_reg == right_reg) { \ 518 __ fadd(result_reg, left_reg, right_reg); \ 519 } else { \ 520 __ fsub(result_reg, left_reg, right_reg); \ 521 } \ 522 __ fneg(result_reg, result_reg); \ 523 __ b(&done); \ 524 \ 525 __ bind(&check_nan_left); \ 526 __ fcmpu(left_reg, left_reg); \ 527 /* left == NaN. */ \ 528 __ bunordered(&return_left); \ 529 \ 530 __ bind(&return_right); \ 531 if (right_reg != result_reg) { \ 532 __ fmr(result_reg, right_reg); \ 533 } \ 534 __ b(&done); \ 535 \ 536 __ bind(&return_left); \ 537 if (left_reg != result_reg) { \ 538 __ fmr(result_reg, left_reg); \ 539 } \ 540 __ bind(&done); \ 541 } while (0) 542 543 #define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx) \ 544 do { \ 545 DoubleRegister result = i.OutputDoubleRegister(); \ 546 AddressingMode mode = kMode_None; \ 547 MemOperand operand = i.MemoryOperand(&mode); \ 548 if (mode == kMode_MRI) { \ 549 __ asm_instr(result, operand); \ 550 } else { \ 551 __ asm_instrx(result, operand); \ 552 } \ 553 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 554 } while (0) 555 556 557 #define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrx) \ 558 do { \ 559 Register result = i.OutputRegister(); \ 560 AddressingMode mode = kMode_None; \ 561 MemOperand operand = i.MemoryOperand(&mode); \ 562 if (mode == kMode_MRI) { \ 563 __ asm_instr(result, operand); \ 564 } else { \ 565 __ asm_instrx(result, operand); \ 566 } \ 567 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 568 } while (0) 569 570 571 #define ASSEMBLE_STORE_FLOAT32() \ 572 do { \ 573 size_t index = 0; \ 574 AddressingMode mode = kMode_None; \ 575 MemOperand operand = i.MemoryOperand(&mode, &index); \ 576 DoubleRegister value = i.InputDoubleRegister(index); \ 577 /* removed frsp as instruction-selector checked */ \ 578 /* value to be kFloat32 */ \ 579 if (mode == kMode_MRI) { \ 580 __ stfs(value, operand); \ 581 } else { \ 582 __ stfsx(value, operand); \ 583 } \ 584 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 585 } while (0) 586 587 588 #define ASSEMBLE_STORE_DOUBLE() \ 589 do { \ 590 size_t index = 0; \ 591 AddressingMode mode = kMode_None; \ 592 MemOperand operand = i.MemoryOperand(&mode, &index); \ 593 DoubleRegister value = i.InputDoubleRegister(index); \ 594 if (mode == kMode_MRI) { \ 595 __ stfd(value, operand); \ 596 } else { \ 597 __ stfdx(value, operand); \ 598 } \ 599 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 600 } while (0) 601 602 603 #define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrx) \ 604 do { \ 605 size_t index = 0; \ 606 AddressingMode mode = kMode_None; \ 607 MemOperand operand = i.MemoryOperand(&mode, &index); \ 608 Register value = i.InputRegister(index); \ 609 if (mode == kMode_MRI) { \ 610 __ asm_instr(value, operand); \ 611 } else { \ 612 __ asm_instrx(value, operand); \ 613 } \ 614 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 615 } while (0) 616 617 #if V8_TARGET_ARCH_PPC64 618 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits. 619 #define CleanUInt32(x) __ ClearLeftImm(x, x, Operand(32)) 620 #else 621 #define CleanUInt32(x) 622 #endif 623 624 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr, asm_instrx) \ 625 do { \ 626 Label done; \ 627 Register result = i.OutputRegister(); \ 628 AddressingMode mode = kMode_None; \ 629 MemOperand operand = i.MemoryOperand(&mode); \ 630 if (mode == kMode_MRI) { \ 631 __ asm_instr(result, operand); \ 632 } else { \ 633 __ asm_instrx(result, operand); \ 634 } \ 635 __ lwsync(); \ 636 } while (0) 637 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr, asm_instrx) \ 638 do { \ 639 size_t index = 0; \ 640 AddressingMode mode = kMode_None; \ 641 MemOperand operand = i.MemoryOperand(&mode, &index); \ 642 Register value = i.InputRegister(index); \ 643 __ lwsync(); \ 644 if (mode == kMode_MRI) { \ 645 __ asm_instr(value, operand); \ 646 } else { \ 647 __ asm_instrx(value, operand); \ 648 } \ 649 __ sync(); \ 650 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \ 651 } while (0) 652 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \ 653 do { \ 654 Label exchange; \ 655 __ bind(&exchange); \ 656 __ load_instr(i.OutputRegister(0), \ 657 MemOperand(i.InputRegister(0), i.InputRegister(1))); \ 658 __ store_instr(i.InputRegister(2), \ 659 MemOperand(i.InputRegister(0), i.InputRegister(1))); \ 660 __ bne(&exchange, cr0); \ 661 } while (0) 662 663 #define ASSEMBLE_ATOMIC_BINOP(bin_inst, load_inst, store_inst) \ 664 do { \ 665 MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \ 666 Label binop; \ 667 __ bind(&binop); \ 668 __ load_inst(i.OutputRegister(), operand); \ 669 __ bin_inst(i.InputRegister(2), i.OutputRegister(), i.InputRegister(2)); \ 670 __ store_inst(i.InputRegister(2), operand); \ 671 __ bne(&binop, cr0); \ 672 } while (false) 673 674 #define ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(bin_inst, load_inst, \ 675 store_inst, ext_instr) \ 676 do { \ 677 MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \ 678 Label binop; \ 679 __ bind(&binop); \ 680 __ load_inst(i.OutputRegister(), operand); \ 681 __ ext_instr(i.OutputRegister(), i.OutputRegister()); \ 682 __ bin_inst(i.InputRegister(2), i.OutputRegister(), i.InputRegister(2)); \ 683 __ store_inst(i.InputRegister(2), operand); \ 684 __ bne(&binop, cr0); \ 685 } while (false) 686 687 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp_inst, load_inst, store_inst) \ 688 do { \ 689 MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \ 690 Label loop; \ 691 Label exit; \ 692 __ bind(&loop); \ 693 __ load_inst(i.OutputRegister(), operand); \ 694 __ cmp_inst(i.OutputRegister(), i.InputRegister(2)); \ 695 __ bne(&exit, cr0); \ 696 __ store_inst(i.InputRegister(3), operand); \ 697 __ bne(&loop, cr0); \ 698 __ bind(&exit); \ 699 } while (false) 700 701 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp_inst, load_inst, \ 702 store_inst, ext_instr) \ 703 do { \ 704 MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \ 705 Label loop; \ 706 Label exit; \ 707 __ bind(&loop); \ 708 __ load_inst(i.OutputRegister(), operand); \ 709 __ ext_instr(i.OutputRegister(), i.OutputRegister()); \ 710 __ cmp_inst(i.OutputRegister(), i.InputRegister(2)); \ 711 __ bne(&exit, cr0); \ 712 __ store_inst(i.InputRegister(3), operand); \ 713 __ bne(&loop, cr0); \ 714 __ bind(&exit); \ 715 } while (false) 716 717 void CodeGenerator::AssembleDeconstructFrame() { 718 __ LeaveFrame(StackFrame::MANUAL); 719 } 720 721 void CodeGenerator::AssemblePrepareTailCall() { 722 if (frame_access_state()->has_frame()) { 723 __ RestoreFrameStateForTailCall(); 724 } 725 frame_access_state()->SetFrameAccessToSP(); 726 } 727 728 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, 729 Register scratch1, 730 Register scratch2, 731 Register scratch3) { 732 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); 733 Label done; 734 735 // Check if current frame is an arguments adaptor frame. 736 __ LoadP(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset)); 737 __ cmpi(scratch1, 738 Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); 739 __ bne(&done); 740 741 // Load arguments count from current arguments adaptor frame (note, it 742 // does not include receiver). 743 Register caller_args_count_reg = scratch1; 744 __ LoadP(caller_args_count_reg, 745 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 746 __ SmiUntag(caller_args_count_reg); 747 748 ParameterCount callee_args_count(args_reg); 749 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, 750 scratch3); 751 __ bind(&done); 752 } 753 754 namespace { 755 756 void FlushPendingPushRegisters(TurboAssembler* tasm, 757 FrameAccessState* frame_access_state, 758 ZoneVector<Register>* pending_pushes) { 759 switch (pending_pushes->size()) { 760 case 0: 761 break; 762 case 1: 763 tasm->Push((*pending_pushes)[0]); 764 break; 765 case 2: 766 tasm->Push((*pending_pushes)[0], (*pending_pushes)[1]); 767 break; 768 case 3: 769 tasm->Push((*pending_pushes)[0], (*pending_pushes)[1], 770 (*pending_pushes)[2]); 771 break; 772 default: 773 UNREACHABLE(); 774 break; 775 } 776 frame_access_state->IncreaseSPDelta(pending_pushes->size()); 777 pending_pushes->clear(); 778 } 779 780 void AdjustStackPointerForTailCall( 781 TurboAssembler* tasm, FrameAccessState* state, int new_slot_above_sp, 782 ZoneVector<Register>* pending_pushes = nullptr, 783 bool allow_shrinkage = true) { 784 int current_sp_offset = state->GetSPToFPSlotCount() + 785 StandardFrameConstants::kFixedSlotCountAboveFp; 786 int stack_slot_delta = new_slot_above_sp - current_sp_offset; 787 if (stack_slot_delta > 0) { 788 if (pending_pushes != nullptr) { 789 FlushPendingPushRegisters(tasm, state, pending_pushes); 790 } 791 tasm->Add(sp, sp, -stack_slot_delta * kPointerSize, r0); 792 state->IncreaseSPDelta(stack_slot_delta); 793 } else if (allow_shrinkage && stack_slot_delta < 0) { 794 if (pending_pushes != nullptr) { 795 FlushPendingPushRegisters(tasm, state, pending_pushes); 796 } 797 tasm->Add(sp, sp, -stack_slot_delta * kPointerSize, r0); 798 state->IncreaseSPDelta(stack_slot_delta); 799 } 800 } 801 802 } // namespace 803 804 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, 805 int first_unused_stack_slot) { 806 ZoneVector<MoveOperands*> pushes(zone()); 807 GetPushCompatibleMoves(instr, kRegisterPush, &pushes); 808 809 if (!pushes.empty() && 810 (LocationOperand::cast(pushes.back()->destination()).index() + 1 == 811 first_unused_stack_slot)) { 812 PPCOperandConverter g(this, instr); 813 ZoneVector<Register> pending_pushes(zone()); 814 for (auto move : pushes) { 815 LocationOperand destination_location( 816 LocationOperand::cast(move->destination())); 817 InstructionOperand source(move->source()); 818 AdjustStackPointerForTailCall( 819 tasm(), frame_access_state(), 820 destination_location.index() - pending_pushes.size(), 821 &pending_pushes); 822 // Pushes of non-register data types are not supported. 823 DCHECK(source.IsRegister()); 824 LocationOperand source_location(LocationOperand::cast(source)); 825 pending_pushes.push_back(source_location.GetRegister()); 826 // TODO(arm): We can push more than 3 registers at once. Add support in 827 // the macro-assembler for pushing a list of registers. 828 if (pending_pushes.size() == 3) { 829 FlushPendingPushRegisters(tasm(), frame_access_state(), 830 &pending_pushes); 831 } 832 move->Eliminate(); 833 } 834 FlushPendingPushRegisters(tasm(), frame_access_state(), &pending_pushes); 835 } 836 AdjustStackPointerForTailCall(tasm(), frame_access_state(), 837 first_unused_stack_slot, nullptr, false); 838 } 839 840 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, 841 int first_unused_stack_slot) { 842 AdjustStackPointerForTailCall(tasm(), frame_access_state(), 843 first_unused_stack_slot); 844 } 845 846 // Check that {kJavaScriptCallCodeStartRegister} is correct. 847 void CodeGenerator::AssembleCodeStartRegisterCheck() { 848 Register scratch = kScratchReg; 849 __ ComputeCodeStartAddress(scratch); 850 __ cmp(scratch, kJavaScriptCallCodeStartRegister); 851 __ Assert(eq, AbortReason::kWrongFunctionCodeStart); 852 } 853 854 // Check if the code object is marked for deoptimization. If it is, then it 855 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need 856 // to: 857 // 1. read from memory the word that contains that bit, which can be found in 858 // the flags in the referenced {CodeDataContainer} object; 859 // 2. test kMarkedForDeoptimizationBit in those flags; and 860 // 3. if it is not zero then it jumps to the builtin. 861 void CodeGenerator::BailoutIfDeoptimized() { 862 if (FLAG_debug_code) { 863 // Check that {kJavaScriptCallCodeStartRegister} is correct. 864 __ ComputeCodeStartAddress(ip); 865 __ cmp(ip, kJavaScriptCallCodeStartRegister); 866 __ Assert(eq, AbortReason::kWrongFunctionCodeStart); 867 } 868 869 int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize; 870 __ LoadP(r11, MemOperand(kJavaScriptCallCodeStartRegister, offset)); 871 __ LoadWordArith( 872 r11, FieldMemOperand(r11, CodeDataContainer::kKindSpecificFlagsOffset)); 873 __ TestBit(r11, Code::kMarkedForDeoptimizationBit); 874 // Ensure we're not serializing (otherwise we'd need to use an indirection to 875 // access the builtin below). 876 DCHECK(!isolate()->ShouldLoadConstantsFromRootList()); 877 Handle<Code> code = isolate()->builtins()->builtin_handle( 878 Builtins::kCompileLazyDeoptimizedCode); 879 __ Jump(code, RelocInfo::CODE_TARGET, ne, cr0); 880 } 881 882 void CodeGenerator::GenerateSpeculationPoisonFromCodeStartRegister() { 883 Register scratch = kScratchReg; 884 885 __ ComputeCodeStartAddress(scratch); 886 887 // Calculate a mask which has all bits set in the normal case, but has all 888 // bits cleared if we are speculatively executing the wrong PC. 889 __ cmp(kJavaScriptCallCodeStartRegister, scratch); 890 __ li(scratch, Operand::Zero()); 891 __ notx(kSpeculationPoisonRegister, scratch); 892 __ isel(eq, kSpeculationPoisonRegister, 893 kSpeculationPoisonRegister, scratch); 894 } 895 896 void CodeGenerator::AssembleRegisterArgumentPoisoning() { 897 __ and_(kJSFunctionRegister, kJSFunctionRegister, kSpeculationPoisonRegister); 898 __ and_(kContextRegister, kContextRegister, kSpeculationPoisonRegister); 899 __ and_(sp, sp, kSpeculationPoisonRegister); 900 } 901 902 // Assembles an instruction after register allocation, producing machine code. 903 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( 904 Instruction* instr) { 905 PPCOperandConverter i(this, instr); 906 ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode()); 907 908 switch (opcode) { 909 case kArchCallCodeObject: { 910 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool( 911 tasm()); 912 if (HasRegisterInput(instr, 0)) { 913 Register reg = i.InputRegister(0); 914 DCHECK_IMPLIES( 915 HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), 916 reg == kJavaScriptCallCodeStartRegister); 917 __ addi(reg, reg, Operand(Code::kHeaderSize - kHeapObjectTag)); 918 __ Call(reg); 919 } else { 920 __ Call(i.InputCode(0), RelocInfo::CODE_TARGET); 921 } 922 RecordCallPosition(instr); 923 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 924 frame_access_state()->ClearSPDelta(); 925 break; 926 } 927 case kArchCallWasmFunction: { 928 // We must not share code targets for calls to builtins for wasm code, as 929 // they might need to be patched individually. 930 if (instr->InputAt(0)->IsImmediate()) { 931 Constant constant = i.ToConstant(instr->InputAt(0)); 932 #ifdef V8_TARGET_ARCH_PPC64 933 Address wasm_code = static_cast<Address>(constant.ToInt64()); 934 #else 935 Address wasm_code = static_cast<Address>(constant.ToInt32()); 936 #endif 937 __ Call(wasm_code, constant.rmode()); 938 } else { 939 __ Call(i.InputRegister(0)); 940 } 941 RecordCallPosition(instr); 942 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 943 frame_access_state()->ClearSPDelta(); 944 break; 945 } 946 case kArchTailCallCodeObjectFromJSFunction: 947 case kArchTailCallCodeObject: { 948 if (opcode == kArchTailCallCodeObjectFromJSFunction) { 949 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 950 i.TempRegister(0), i.TempRegister(1), 951 i.TempRegister(2)); 952 } 953 if (HasRegisterInput(instr, 0)) { 954 Register reg = i.InputRegister(0); 955 DCHECK_IMPLIES( 956 HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), 957 reg == kJavaScriptCallCodeStartRegister); 958 __ addi(reg, reg, Operand(Code::kHeaderSize - kHeapObjectTag)); 959 __ Jump(reg); 960 } else { 961 // We cannot use the constant pool to load the target since 962 // we've already restored the caller's frame. 963 ConstantPoolUnavailableScope constant_pool_unavailable(tasm()); 964 __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET); 965 } 966 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 967 frame_access_state()->ClearSPDelta(); 968 frame_access_state()->SetFrameAccessToDefault(); 969 break; 970 } 971 case kArchTailCallWasm: { 972 // We must not share code targets for calls to builtins for wasm code, as 973 // they might need to be patched individually. 974 if (instr->InputAt(0)->IsImmediate()) { 975 Constant constant = i.ToConstant(instr->InputAt(0)); 976 #ifdef V8_TARGET_ARCH_S390X 977 Address wasm_code = static_cast<Address>(constant.ToInt64()); 978 #else 979 Address wasm_code = static_cast<Address>(constant.ToInt32()); 980 #endif 981 __ Jump(wasm_code, constant.rmode()); 982 } else { 983 __ Jump(i.InputRegister(0)); 984 } 985 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 986 frame_access_state()->ClearSPDelta(); 987 frame_access_state()->SetFrameAccessToDefault(); 988 break; 989 } 990 case kArchTailCallAddress: { 991 CHECK(!instr->InputAt(0)->IsImmediate()); 992 Register reg = i.InputRegister(0); 993 DCHECK_IMPLIES( 994 HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), 995 reg == kJavaScriptCallCodeStartRegister); 996 __ Jump(reg); 997 frame_access_state()->ClearSPDelta(); 998 frame_access_state()->SetFrameAccessToDefault(); 999 break; 1000 } 1001 case kArchCallJSFunction: { 1002 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool( 1003 tasm()); 1004 Register func = i.InputRegister(0); 1005 if (FLAG_debug_code) { 1006 // Check the function's context matches the context argument. 1007 __ LoadP(kScratchReg, 1008 FieldMemOperand(func, JSFunction::kContextOffset)); 1009 __ cmp(cp, kScratchReg); 1010 __ Assert(eq, AbortReason::kWrongFunctionContext); 1011 } 1012 static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch"); 1013 __ LoadP(r5, FieldMemOperand(func, JSFunction::kCodeOffset)); 1014 __ addi(r5, r5, Operand(Code::kHeaderSize - kHeapObjectTag)); 1015 __ Call(r5); 1016 RecordCallPosition(instr); 1017 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1018 frame_access_state()->ClearSPDelta(); 1019 break; 1020 } 1021 case kArchPrepareCallCFunction: { 1022 int const num_parameters = MiscField::decode(instr->opcode()); 1023 __ PrepareCallCFunction(num_parameters, kScratchReg); 1024 // Frame alignment requires using FP-relative frame addressing. 1025 frame_access_state()->SetFrameAccessToFP(); 1026 break; 1027 } 1028 case kArchSaveCallerRegisters: { 1029 fp_mode_ = 1030 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())); 1031 DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs); 1032 // kReturnRegister0 should have been saved before entering the stub. 1033 int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0); 1034 DCHECK_EQ(0, bytes % kPointerSize); 1035 DCHECK_EQ(0, frame_access_state()->sp_delta()); 1036 frame_access_state()->IncreaseSPDelta(bytes / kPointerSize); 1037 DCHECK(!caller_registers_saved_); 1038 caller_registers_saved_ = true; 1039 break; 1040 } 1041 case kArchRestoreCallerRegisters: { 1042 DCHECK(fp_mode_ == 1043 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()))); 1044 DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs); 1045 // Don't overwrite the returned value. 1046 int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0); 1047 frame_access_state()->IncreaseSPDelta(-(bytes / kPointerSize)); 1048 DCHECK_EQ(0, frame_access_state()->sp_delta()); 1049 DCHECK(caller_registers_saved_); 1050 caller_registers_saved_ = false; 1051 break; 1052 } 1053 case kArchPrepareTailCall: 1054 AssemblePrepareTailCall(); 1055 break; 1056 case kArchComment: 1057 #ifdef V8_TARGET_ARCH_PPC64 1058 __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0))); 1059 #else 1060 __ RecordComment(reinterpret_cast<const char*>(i.InputInt32(0))); 1061 #endif 1062 break; 1063 case kArchCallCFunction: { 1064 int const num_parameters = MiscField::decode(instr->opcode()); 1065 if (instr->InputAt(0)->IsImmediate()) { 1066 ExternalReference ref = i.InputExternalReference(0); 1067 __ CallCFunction(ref, num_parameters); 1068 } else { 1069 Register func = i.InputRegister(0); 1070 __ CallCFunction(func, num_parameters); 1071 } 1072 frame_access_state()->SetFrameAccessToDefault(); 1073 // Ideally, we should decrement SP delta to match the change of stack 1074 // pointer in CallCFunction. However, for certain architectures (e.g. 1075 // ARM), there may be more strict alignment requirement, causing old SP 1076 // to be saved on the stack. In those cases, we can not calculate the SP 1077 // delta statically. 1078 frame_access_state()->ClearSPDelta(); 1079 if (caller_registers_saved_) { 1080 // Need to re-sync SP delta introduced in kArchSaveCallerRegisters. 1081 // Here, we assume the sequence to be: 1082 // kArchSaveCallerRegisters; 1083 // kArchCallCFunction; 1084 // kArchRestoreCallerRegisters; 1085 int bytes = 1086 __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0); 1087 frame_access_state()->IncreaseSPDelta(bytes / kPointerSize); 1088 } 1089 break; 1090 } 1091 case kArchJmp: 1092 AssembleArchJump(i.InputRpo(0)); 1093 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1094 break; 1095 case kArchBinarySearchSwitch: 1096 AssembleArchBinarySearchSwitch(instr); 1097 break; 1098 case kArchLookupSwitch: 1099 AssembleArchLookupSwitch(instr); 1100 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1101 break; 1102 case kArchTableSwitch: 1103 AssembleArchTableSwitch(instr); 1104 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1105 break; 1106 case kArchDebugAbort: 1107 DCHECK(i.InputRegister(0) == r4); 1108 if (!frame_access_state()->has_frame()) { 1109 // We don't actually want to generate a pile of code for this, so just 1110 // claim there is a stack frame, without generating one. 1111 FrameScope scope(tasm(), StackFrame::NONE); 1112 __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS), 1113 RelocInfo::CODE_TARGET); 1114 } else { 1115 __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS), 1116 RelocInfo::CODE_TARGET); 1117 } 1118 __ stop("kArchDebugAbort"); 1119 break; 1120 case kArchDebugBreak: 1121 __ stop("kArchDebugBreak"); 1122 break; 1123 case kArchNop: 1124 case kArchThrowTerminator: 1125 // don't emit code for nops. 1126 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1127 break; 1128 case kArchDeoptimize: { 1129 int deopt_state_id = 1130 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); 1131 CodeGenResult result = 1132 AssembleDeoptimizerCall(deopt_state_id, current_source_position_); 1133 if (result != kSuccess) return result; 1134 break; 1135 } 1136 case kArchRet: 1137 AssembleReturn(instr->InputAt(0)); 1138 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1139 break; 1140 case kArchStackPointer: 1141 __ mr(i.OutputRegister(), sp); 1142 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1143 break; 1144 case kArchFramePointer: 1145 __ mr(i.OutputRegister(), fp); 1146 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1147 break; 1148 case kArchParentFramePointer: 1149 if (frame_access_state()->has_frame()) { 1150 __ LoadP(i.OutputRegister(), MemOperand(fp, 0)); 1151 } else { 1152 __ mr(i.OutputRegister(), fp); 1153 } 1154 break; 1155 case kArchTruncateDoubleToI: 1156 __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(), 1157 i.InputDoubleRegister(0), DetermineStubCallMode()); 1158 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1159 break; 1160 case kArchStoreWithWriteBarrier: { 1161 RecordWriteMode mode = 1162 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode())); 1163 Register object = i.InputRegister(0); 1164 Register value = i.InputRegister(2); 1165 Register scratch0 = i.TempRegister(0); 1166 Register scratch1 = i.TempRegister(1); 1167 OutOfLineRecordWrite* ool; 1168 1169 AddressingMode addressing_mode = 1170 AddressingModeField::decode(instr->opcode()); 1171 if (addressing_mode == kMode_MRI) { 1172 int32_t offset = i.InputInt32(1); 1173 ool = new (zone()) OutOfLineRecordWrite(this, object, offset, value, 1174 scratch0, scratch1, mode); 1175 __ StoreP(value, MemOperand(object, offset)); 1176 } else { 1177 DCHECK_EQ(kMode_MRR, addressing_mode); 1178 Register offset(i.InputRegister(1)); 1179 ool = new (zone()) OutOfLineRecordWrite(this, object, offset, value, 1180 scratch0, scratch1, mode); 1181 __ StorePX(value, MemOperand(object, offset)); 1182 } 1183 __ CheckPageFlag(object, scratch0, 1184 MemoryChunk::kPointersFromHereAreInterestingMask, ne, 1185 ool->entry()); 1186 __ bind(ool->exit()); 1187 break; 1188 } 1189 case kArchStackSlot: { 1190 FrameOffset offset = 1191 frame_access_state()->GetFrameOffset(i.InputInt32(0)); 1192 __ addi(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp, 1193 Operand(offset.offset())); 1194 break; 1195 } 1196 case kArchWordPoisonOnSpeculation: 1197 __ and_(i.OutputRegister(), i.InputRegister(0), 1198 kSpeculationPoisonRegister); 1199 break; 1200 case kPPC_And: 1201 if (HasRegisterInput(instr, 1)) { 1202 __ and_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1203 i.OutputRCBit()); 1204 } else { 1205 __ andi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1)); 1206 } 1207 break; 1208 case kPPC_AndComplement: 1209 __ andc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1210 i.OutputRCBit()); 1211 break; 1212 case kPPC_Or: 1213 if (HasRegisterInput(instr, 1)) { 1214 __ orx(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1215 i.OutputRCBit()); 1216 } else { 1217 __ ori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1)); 1218 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1219 } 1220 break; 1221 case kPPC_OrComplement: 1222 __ orc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1223 i.OutputRCBit()); 1224 break; 1225 case kPPC_Xor: 1226 if (HasRegisterInput(instr, 1)) { 1227 __ xor_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1228 i.OutputRCBit()); 1229 } else { 1230 __ xori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1)); 1231 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1232 } 1233 break; 1234 case kPPC_ShiftLeft32: 1235 ASSEMBLE_BINOP_RC(slw, slwi); 1236 break; 1237 #if V8_TARGET_ARCH_PPC64 1238 case kPPC_ShiftLeft64: 1239 ASSEMBLE_BINOP_RC(sld, sldi); 1240 break; 1241 #endif 1242 case kPPC_ShiftRight32: 1243 ASSEMBLE_BINOP_RC(srw, srwi); 1244 break; 1245 #if V8_TARGET_ARCH_PPC64 1246 case kPPC_ShiftRight64: 1247 ASSEMBLE_BINOP_RC(srd, srdi); 1248 break; 1249 #endif 1250 case kPPC_ShiftRightAlg32: 1251 ASSEMBLE_BINOP_INT_RC(sraw, srawi); 1252 break; 1253 #if V8_TARGET_ARCH_PPC64 1254 case kPPC_ShiftRightAlg64: 1255 ASSEMBLE_BINOP_INT_RC(srad, sradi); 1256 break; 1257 #endif 1258 #if !V8_TARGET_ARCH_PPC64 1259 case kPPC_AddPair: 1260 // i.InputRegister(0) ... left low word. 1261 // i.InputRegister(1) ... left high word. 1262 // i.InputRegister(2) ... right low word. 1263 // i.InputRegister(3) ... right high word. 1264 __ addc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2)); 1265 __ adde(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3)); 1266 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1267 break; 1268 case kPPC_SubPair: 1269 // i.InputRegister(0) ... left low word. 1270 // i.InputRegister(1) ... left high word. 1271 // i.InputRegister(2) ... right low word. 1272 // i.InputRegister(3) ... right high word. 1273 __ subc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2)); 1274 __ sube(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3)); 1275 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1276 break; 1277 case kPPC_MulPair: 1278 // i.InputRegister(0) ... left low word. 1279 // i.InputRegister(1) ... left high word. 1280 // i.InputRegister(2) ... right low word. 1281 // i.InputRegister(3) ... right high word. 1282 __ mullw(i.TempRegister(0), i.InputRegister(0), i.InputRegister(3)); 1283 __ mullw(i.TempRegister(1), i.InputRegister(2), i.InputRegister(1)); 1284 __ add(i.TempRegister(0), i.TempRegister(0), i.TempRegister(1)); 1285 __ mullw(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2)); 1286 __ mulhwu(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(2)); 1287 __ add(i.OutputRegister(1), i.OutputRegister(1), i.TempRegister(0)); 1288 break; 1289 case kPPC_ShiftLeftPair: { 1290 Register second_output = 1291 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1292 if (instr->InputAt(2)->IsImmediate()) { 1293 __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1294 i.InputRegister(1), i.InputInt32(2)); 1295 } else { 1296 __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1297 i.InputRegister(1), kScratchReg, i.InputRegister(2)); 1298 } 1299 break; 1300 } 1301 case kPPC_ShiftRightPair: { 1302 Register second_output = 1303 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1304 if (instr->InputAt(2)->IsImmediate()) { 1305 __ ShiftRightPair(i.OutputRegister(0), second_output, 1306 i.InputRegister(0), i.InputRegister(1), 1307 i.InputInt32(2)); 1308 } else { 1309 __ ShiftRightPair(i.OutputRegister(0), second_output, 1310 i.InputRegister(0), i.InputRegister(1), kScratchReg, 1311 i.InputRegister(2)); 1312 } 1313 break; 1314 } 1315 case kPPC_ShiftRightAlgPair: { 1316 Register second_output = 1317 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1318 if (instr->InputAt(2)->IsImmediate()) { 1319 __ ShiftRightAlgPair(i.OutputRegister(0), second_output, 1320 i.InputRegister(0), i.InputRegister(1), 1321 i.InputInt32(2)); 1322 } else { 1323 __ ShiftRightAlgPair(i.OutputRegister(0), second_output, 1324 i.InputRegister(0), i.InputRegister(1), 1325 kScratchReg, i.InputRegister(2)); 1326 } 1327 break; 1328 } 1329 #endif 1330 case kPPC_RotRight32: 1331 if (HasRegisterInput(instr, 1)) { 1332 __ subfic(kScratchReg, i.InputRegister(1), Operand(32)); 1333 __ rotlw(i.OutputRegister(), i.InputRegister(0), kScratchReg, 1334 i.OutputRCBit()); 1335 } else { 1336 int sh = i.InputInt32(1); 1337 __ rotrwi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit()); 1338 } 1339 break; 1340 #if V8_TARGET_ARCH_PPC64 1341 case kPPC_RotRight64: 1342 if (HasRegisterInput(instr, 1)) { 1343 __ subfic(kScratchReg, i.InputRegister(1), Operand(64)); 1344 __ rotld(i.OutputRegister(), i.InputRegister(0), kScratchReg, 1345 i.OutputRCBit()); 1346 } else { 1347 int sh = i.InputInt32(1); 1348 __ rotrdi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit()); 1349 } 1350 break; 1351 #endif 1352 case kPPC_Not: 1353 __ notx(i.OutputRegister(), i.InputRegister(0), i.OutputRCBit()); 1354 break; 1355 case kPPC_RotLeftAndMask32: 1356 __ rlwinm(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1), 1357 31 - i.InputInt32(2), 31 - i.InputInt32(3), i.OutputRCBit()); 1358 break; 1359 #if V8_TARGET_ARCH_PPC64 1360 case kPPC_RotLeftAndClear64: 1361 __ rldic(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1), 1362 63 - i.InputInt32(2), i.OutputRCBit()); 1363 break; 1364 case kPPC_RotLeftAndClearLeft64: 1365 __ rldicl(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1), 1366 63 - i.InputInt32(2), i.OutputRCBit()); 1367 break; 1368 case kPPC_RotLeftAndClearRight64: 1369 __ rldicr(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1), 1370 63 - i.InputInt32(2), i.OutputRCBit()); 1371 break; 1372 #endif 1373 case kPPC_Add32: 1374 #if V8_TARGET_ARCH_PPC64 1375 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { 1376 ASSEMBLE_ADD_WITH_OVERFLOW(); 1377 } else { 1378 #endif 1379 if (HasRegisterInput(instr, 1)) { 1380 __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1381 LeaveOE, i.OutputRCBit()); 1382 } else { 1383 __ addi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1)); 1384 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1385 } 1386 __ extsw(i.OutputRegister(), i.OutputRegister()); 1387 #if V8_TARGET_ARCH_PPC64 1388 } 1389 #endif 1390 break; 1391 #if V8_TARGET_ARCH_PPC64 1392 case kPPC_Add64: 1393 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { 1394 ASSEMBLE_ADD_WITH_OVERFLOW(); 1395 } else { 1396 if (HasRegisterInput(instr, 1)) { 1397 __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1398 LeaveOE, i.OutputRCBit()); 1399 } else { 1400 __ addi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1)); 1401 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1402 } 1403 } 1404 break; 1405 #endif 1406 case kPPC_AddWithOverflow32: 1407 ASSEMBLE_ADD_WITH_OVERFLOW32(); 1408 break; 1409 case kPPC_AddDouble: 1410 ASSEMBLE_FLOAT_BINOP_RC(fadd, MiscField::decode(instr->opcode())); 1411 break; 1412 case kPPC_Sub: 1413 #if V8_TARGET_ARCH_PPC64 1414 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { 1415 ASSEMBLE_SUB_WITH_OVERFLOW(); 1416 } else { 1417 #endif 1418 if (HasRegisterInput(instr, 1)) { 1419 __ sub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1420 LeaveOE, i.OutputRCBit()); 1421 } else { 1422 if (is_int16(i.InputImmediate(1).immediate())) { 1423 __ subi(i.OutputRegister(), i.InputRegister(0), 1424 i.InputImmediate(1)); 1425 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1426 } else { 1427 __ mov(kScratchReg, i.InputImmediate(1)); 1428 __ sub(i.OutputRegister(), i.InputRegister(0), kScratchReg, LeaveOE, 1429 i.OutputRCBit()); 1430 } 1431 } 1432 #if V8_TARGET_ARCH_PPC64 1433 } 1434 #endif 1435 break; 1436 case kPPC_SubWithOverflow32: 1437 ASSEMBLE_SUB_WITH_OVERFLOW32(); 1438 break; 1439 case kPPC_SubDouble: 1440 ASSEMBLE_FLOAT_BINOP_RC(fsub, MiscField::decode(instr->opcode())); 1441 break; 1442 case kPPC_Mul32: 1443 __ mullw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1444 LeaveOE, i.OutputRCBit()); 1445 break; 1446 #if V8_TARGET_ARCH_PPC64 1447 case kPPC_Mul64: 1448 __ mulld(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1449 LeaveOE, i.OutputRCBit()); 1450 break; 1451 #endif 1452 1453 case kPPC_Mul32WithHigh32: 1454 if (i.OutputRegister(0) == i.InputRegister(0) || 1455 i.OutputRegister(0) == i.InputRegister(1) || 1456 i.OutputRegister(1) == i.InputRegister(0) || 1457 i.OutputRegister(1) == i.InputRegister(1)) { 1458 __ mullw(kScratchReg, 1459 i.InputRegister(0), i.InputRegister(1)); // low 1460 __ mulhw(i.OutputRegister(1), 1461 i.InputRegister(0), i.InputRegister(1)); // high 1462 __ mr(i.OutputRegister(0), kScratchReg); 1463 } else { 1464 __ mullw(i.OutputRegister(0), 1465 i.InputRegister(0), i.InputRegister(1)); // low 1466 __ mulhw(i.OutputRegister(1), 1467 i.InputRegister(0), i.InputRegister(1)); // high 1468 } 1469 break; 1470 case kPPC_MulHigh32: 1471 __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1472 i.OutputRCBit()); 1473 break; 1474 case kPPC_MulHighU32: 1475 __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1476 i.OutputRCBit()); 1477 break; 1478 case kPPC_MulDouble: 1479 ASSEMBLE_FLOAT_BINOP_RC(fmul, MiscField::decode(instr->opcode())); 1480 break; 1481 case kPPC_Div32: 1482 __ divw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1483 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1484 break; 1485 #if V8_TARGET_ARCH_PPC64 1486 case kPPC_Div64: 1487 __ divd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1488 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1489 break; 1490 #endif 1491 case kPPC_DivU32: 1492 __ divwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1493 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1494 break; 1495 #if V8_TARGET_ARCH_PPC64 1496 case kPPC_DivU64: 1497 __ divdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1498 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1499 break; 1500 #endif 1501 case kPPC_DivDouble: 1502 ASSEMBLE_FLOAT_BINOP_RC(fdiv, MiscField::decode(instr->opcode())); 1503 break; 1504 case kPPC_Mod32: 1505 if (CpuFeatures::IsSupported(MODULO)) { 1506 __ modsw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1507 } else { 1508 ASSEMBLE_MODULO(divw, mullw); 1509 } 1510 break; 1511 #if V8_TARGET_ARCH_PPC64 1512 case kPPC_Mod64: 1513 if (CpuFeatures::IsSupported(MODULO)) { 1514 __ modsd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1515 } else { 1516 ASSEMBLE_MODULO(divd, mulld); 1517 } 1518 break; 1519 #endif 1520 case kPPC_ModU32: 1521 if (CpuFeatures::IsSupported(MODULO)) { 1522 __ moduw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1523 } else { 1524 ASSEMBLE_MODULO(divwu, mullw); 1525 } 1526 break; 1527 #if V8_TARGET_ARCH_PPC64 1528 case kPPC_ModU64: 1529 if (CpuFeatures::IsSupported(MODULO)) { 1530 __ modud(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1531 } else { 1532 ASSEMBLE_MODULO(divdu, mulld); 1533 } 1534 break; 1535 #endif 1536 case kPPC_ModDouble: 1537 // TODO(bmeurer): We should really get rid of this special instruction, 1538 // and generate a CallAddress instruction instead. 1539 ASSEMBLE_FLOAT_MODULO(); 1540 break; 1541 case kIeee754Float64Acos: 1542 ASSEMBLE_IEEE754_UNOP(acos); 1543 break; 1544 case kIeee754Float64Acosh: 1545 ASSEMBLE_IEEE754_UNOP(acosh); 1546 break; 1547 case kIeee754Float64Asin: 1548 ASSEMBLE_IEEE754_UNOP(asin); 1549 break; 1550 case kIeee754Float64Asinh: 1551 ASSEMBLE_IEEE754_UNOP(asinh); 1552 break; 1553 case kIeee754Float64Atan: 1554 ASSEMBLE_IEEE754_UNOP(atan); 1555 break; 1556 case kIeee754Float64Atan2: 1557 ASSEMBLE_IEEE754_BINOP(atan2); 1558 break; 1559 case kIeee754Float64Atanh: 1560 ASSEMBLE_IEEE754_UNOP(atanh); 1561 break; 1562 case kIeee754Float64Tan: 1563 ASSEMBLE_IEEE754_UNOP(tan); 1564 break; 1565 case kIeee754Float64Tanh: 1566 ASSEMBLE_IEEE754_UNOP(tanh); 1567 break; 1568 case kIeee754Float64Cbrt: 1569 ASSEMBLE_IEEE754_UNOP(cbrt); 1570 break; 1571 case kIeee754Float64Sin: 1572 ASSEMBLE_IEEE754_UNOP(sin); 1573 break; 1574 case kIeee754Float64Sinh: 1575 ASSEMBLE_IEEE754_UNOP(sinh); 1576 break; 1577 case kIeee754Float64Cos: 1578 ASSEMBLE_IEEE754_UNOP(cos); 1579 break; 1580 case kIeee754Float64Cosh: 1581 ASSEMBLE_IEEE754_UNOP(cosh); 1582 break; 1583 case kIeee754Float64Exp: 1584 ASSEMBLE_IEEE754_UNOP(exp); 1585 break; 1586 case kIeee754Float64Expm1: 1587 ASSEMBLE_IEEE754_UNOP(expm1); 1588 break; 1589 case kIeee754Float64Log: 1590 ASSEMBLE_IEEE754_UNOP(log); 1591 break; 1592 case kIeee754Float64Log1p: 1593 ASSEMBLE_IEEE754_UNOP(log1p); 1594 break; 1595 case kIeee754Float64Log2: 1596 ASSEMBLE_IEEE754_UNOP(log2); 1597 break; 1598 case kIeee754Float64Log10: 1599 ASSEMBLE_IEEE754_UNOP(log10); 1600 break; 1601 case kIeee754Float64Pow: { 1602 __ Call(BUILTIN_CODE(isolate(), MathPowInternal), RelocInfo::CODE_TARGET); 1603 __ Move(d1, d3); 1604 break; 1605 } 1606 case kPPC_Neg: 1607 __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit()); 1608 break; 1609 case kPPC_MaxDouble: 1610 ASSEMBLE_FLOAT_MAX(); 1611 break; 1612 case kPPC_MinDouble: 1613 ASSEMBLE_FLOAT_MIN(); 1614 break; 1615 case kPPC_AbsDouble: 1616 ASSEMBLE_FLOAT_UNOP_RC(fabs, 0); 1617 break; 1618 case kPPC_SqrtDouble: 1619 ASSEMBLE_FLOAT_UNOP_RC(fsqrt, MiscField::decode(instr->opcode())); 1620 break; 1621 case kPPC_FloorDouble: 1622 ASSEMBLE_FLOAT_UNOP_RC(frim, MiscField::decode(instr->opcode())); 1623 break; 1624 case kPPC_CeilDouble: 1625 ASSEMBLE_FLOAT_UNOP_RC(frip, MiscField::decode(instr->opcode())); 1626 break; 1627 case kPPC_TruncateDouble: 1628 ASSEMBLE_FLOAT_UNOP_RC(friz, MiscField::decode(instr->opcode())); 1629 break; 1630 case kPPC_RoundDouble: 1631 ASSEMBLE_FLOAT_UNOP_RC(frin, MiscField::decode(instr->opcode())); 1632 break; 1633 case kPPC_NegDouble: 1634 ASSEMBLE_FLOAT_UNOP_RC(fneg, 0); 1635 break; 1636 case kPPC_Cntlz32: 1637 __ cntlzw(i.OutputRegister(), i.InputRegister(0)); 1638 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1639 break; 1640 #if V8_TARGET_ARCH_PPC64 1641 case kPPC_Cntlz64: 1642 __ cntlzd(i.OutputRegister(), i.InputRegister(0)); 1643 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1644 break; 1645 #endif 1646 case kPPC_Popcnt32: 1647 __ popcntw(i.OutputRegister(), i.InputRegister(0)); 1648 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1649 break; 1650 #if V8_TARGET_ARCH_PPC64 1651 case kPPC_Popcnt64: 1652 __ popcntd(i.OutputRegister(), i.InputRegister(0)); 1653 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1654 break; 1655 #endif 1656 case kPPC_Cmp32: 1657 ASSEMBLE_COMPARE(cmpw, cmplw); 1658 break; 1659 #if V8_TARGET_ARCH_PPC64 1660 case kPPC_Cmp64: 1661 ASSEMBLE_COMPARE(cmp, cmpl); 1662 break; 1663 #endif 1664 case kPPC_CmpDouble: 1665 ASSEMBLE_FLOAT_COMPARE(fcmpu); 1666 break; 1667 case kPPC_Tst32: 1668 if (HasRegisterInput(instr, 1)) { 1669 __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit()); 1670 } else { 1671 __ andi(r0, i.InputRegister(0), i.InputImmediate(1)); 1672 } 1673 #if V8_TARGET_ARCH_PPC64 1674 __ extsw(r0, r0, i.OutputRCBit()); 1675 #endif 1676 DCHECK_EQ(SetRC, i.OutputRCBit()); 1677 break; 1678 #if V8_TARGET_ARCH_PPC64 1679 case kPPC_Tst64: 1680 if (HasRegisterInput(instr, 1)) { 1681 __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit()); 1682 } else { 1683 __ andi(r0, i.InputRegister(0), i.InputImmediate(1)); 1684 } 1685 DCHECK_EQ(SetRC, i.OutputRCBit()); 1686 break; 1687 #endif 1688 case kPPC_Float64SilenceNaN: { 1689 DoubleRegister value = i.InputDoubleRegister(0); 1690 DoubleRegister result = i.OutputDoubleRegister(); 1691 __ CanonicalizeNaN(result, value); 1692 break; 1693 } 1694 case kPPC_Push: 1695 if (instr->InputAt(0)->IsFPRegister()) { 1696 LocationOperand* op = LocationOperand::cast(instr->InputAt(0)); 1697 if (op->representation() == MachineRepresentation::kFloat64) { 1698 __ StoreDoubleU(i.InputDoubleRegister(0), 1699 MemOperand(sp, -kDoubleSize), r0); 1700 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1701 } else { 1702 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1703 __ StoreSingleU(i.InputDoubleRegister(0), 1704 MemOperand(sp, -kPointerSize), r0); 1705 frame_access_state()->IncreaseSPDelta(1); 1706 } 1707 } else { 1708 __ StorePU(i.InputRegister(0), MemOperand(sp, -kPointerSize), r0); 1709 frame_access_state()->IncreaseSPDelta(1); 1710 } 1711 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1712 break; 1713 case kPPC_PushFrame: { 1714 int num_slots = i.InputInt32(1); 1715 if (instr->InputAt(0)->IsFPRegister()) { 1716 LocationOperand* op = LocationOperand::cast(instr->InputAt(0)); 1717 if (op->representation() == MachineRepresentation::kFloat64) { 1718 __ StoreDoubleU(i.InputDoubleRegister(0), 1719 MemOperand(sp, -num_slots * kPointerSize), r0); 1720 } else { 1721 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1722 __ StoreSingleU(i.InputDoubleRegister(0), 1723 MemOperand(sp, -num_slots * kPointerSize), r0); 1724 } 1725 } else { 1726 __ StorePU(i.InputRegister(0), 1727 MemOperand(sp, -num_slots * kPointerSize), r0); 1728 } 1729 break; 1730 } 1731 case kPPC_StoreToStackSlot: { 1732 int slot = i.InputInt32(1); 1733 if (instr->InputAt(0)->IsFPRegister()) { 1734 LocationOperand* op = LocationOperand::cast(instr->InputAt(0)); 1735 if (op->representation() == MachineRepresentation::kFloat64) { 1736 __ StoreDouble(i.InputDoubleRegister(0), 1737 MemOperand(sp, slot * kPointerSize), r0); 1738 } else { 1739 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1740 __ StoreSingle(i.InputDoubleRegister(0), 1741 MemOperand(sp, slot * kPointerSize), r0); 1742 } 1743 } else { 1744 __ StoreP(i.InputRegister(0), MemOperand(sp, slot * kPointerSize), r0); 1745 } 1746 break; 1747 } 1748 case kPPC_ExtendSignWord8: 1749 __ extsb(i.OutputRegister(), i.InputRegister(0)); 1750 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1751 break; 1752 case kPPC_ExtendSignWord16: 1753 __ extsh(i.OutputRegister(), i.InputRegister(0)); 1754 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1755 break; 1756 #if V8_TARGET_ARCH_PPC64 1757 case kPPC_ExtendSignWord32: 1758 __ extsw(i.OutputRegister(), i.InputRegister(0)); 1759 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1760 break; 1761 case kPPC_Uint32ToUint64: 1762 // Zero extend 1763 __ clrldi(i.OutputRegister(), i.InputRegister(0), Operand(32)); 1764 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1765 break; 1766 case kPPC_Int64ToInt32: 1767 __ extsw(i.OutputRegister(), i.InputRegister(0)); 1768 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1769 break; 1770 case kPPC_Int64ToFloat32: 1771 __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister()); 1772 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1773 break; 1774 case kPPC_Int64ToDouble: 1775 __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister()); 1776 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1777 break; 1778 case kPPC_Uint64ToFloat32: 1779 __ ConvertUnsignedInt64ToFloat(i.InputRegister(0), 1780 i.OutputDoubleRegister()); 1781 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1782 break; 1783 case kPPC_Uint64ToDouble: 1784 __ ConvertUnsignedInt64ToDouble(i.InputRegister(0), 1785 i.OutputDoubleRegister()); 1786 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1787 break; 1788 #endif 1789 case kPPC_Int32ToFloat32: 1790 __ ConvertIntToFloat(i.InputRegister(0), i.OutputDoubleRegister()); 1791 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1792 break; 1793 case kPPC_Int32ToDouble: 1794 __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister()); 1795 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1796 break; 1797 case kPPC_Uint32ToFloat32: 1798 __ ConvertUnsignedIntToFloat(i.InputRegister(0), 1799 i.OutputDoubleRegister()); 1800 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1801 break; 1802 case kPPC_Uint32ToDouble: 1803 __ ConvertUnsignedIntToDouble(i.InputRegister(0), 1804 i.OutputDoubleRegister()); 1805 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1806 break; 1807 case kPPC_DoubleToInt32: 1808 case kPPC_DoubleToUint32: 1809 case kPPC_DoubleToInt64: { 1810 #if V8_TARGET_ARCH_PPC64 1811 bool check_conversion = 1812 (opcode == kPPC_DoubleToInt64 && i.OutputCount() > 1); 1813 if (check_conversion) { 1814 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit 1815 } 1816 #endif 1817 __ ConvertDoubleToInt64(i.InputDoubleRegister(0), 1818 #if !V8_TARGET_ARCH_PPC64 1819 kScratchReg, 1820 #endif 1821 i.OutputRegister(0), kScratchDoubleReg); 1822 #if V8_TARGET_ARCH_PPC64 1823 if (check_conversion) { 1824 // Set 2nd output to zero if conversion fails. 1825 CRegister cr = cr7; 1826 int crbit = v8::internal::Assembler::encode_crbit( 1827 cr, static_cast<CRBit>(VXCVI % CRWIDTH)); 1828 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7 1829 if (CpuFeatures::IsSupported(ISELECT)) { 1830 __ li(i.OutputRegister(1), Operand(1)); 1831 __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit); 1832 } else { 1833 __ li(i.OutputRegister(1), Operand::Zero()); 1834 __ bc(v8::internal::kInstrSize * 2, BT, crbit); 1835 __ li(i.OutputRegister(1), Operand(1)); 1836 } 1837 } 1838 #endif 1839 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1840 break; 1841 } 1842 #if V8_TARGET_ARCH_PPC64 1843 case kPPC_DoubleToUint64: { 1844 bool check_conversion = (i.OutputCount() > 1); 1845 if (check_conversion) { 1846 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit 1847 } 1848 __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0), 1849 i.OutputRegister(0), kScratchDoubleReg); 1850 if (check_conversion) { 1851 // Set 2nd output to zero if conversion fails. 1852 CRegister cr = cr7; 1853 int crbit = v8::internal::Assembler::encode_crbit( 1854 cr, static_cast<CRBit>(VXCVI % CRWIDTH)); 1855 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7 1856 if (CpuFeatures::IsSupported(ISELECT)) { 1857 __ li(i.OutputRegister(1), Operand(1)); 1858 __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit); 1859 } else { 1860 __ li(i.OutputRegister(1), Operand::Zero()); 1861 __ bc(v8::internal::kInstrSize * 2, BT, crbit); 1862 __ li(i.OutputRegister(1), Operand(1)); 1863 } 1864 } 1865 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1866 break; 1867 } 1868 #endif 1869 case kPPC_DoubleToFloat32: 1870 ASSEMBLE_FLOAT_UNOP_RC(frsp, 0); 1871 break; 1872 case kPPC_Float32ToDouble: 1873 // Nothing to do. 1874 __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1875 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1876 break; 1877 case kPPC_DoubleExtractLowWord32: 1878 __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0)); 1879 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1880 break; 1881 case kPPC_DoubleExtractHighWord32: 1882 __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0)); 1883 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1884 break; 1885 case kPPC_DoubleInsertLowWord32: 1886 __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0); 1887 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1888 break; 1889 case kPPC_DoubleInsertHighWord32: 1890 __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0); 1891 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1892 break; 1893 case kPPC_DoubleConstruct: 1894 #if V8_TARGET_ARCH_PPC64 1895 __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(), 1896 i.InputRegister(0), i.InputRegister(1), r0); 1897 #else 1898 __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0), 1899 i.InputRegister(1)); 1900 #endif 1901 DCHECK_EQ(LeaveRC, i.OutputRCBit()); 1902 break; 1903 case kPPC_BitcastFloat32ToInt32: 1904 __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0)); 1905 break; 1906 case kPPC_BitcastInt32ToFloat32: 1907 __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0)); 1908 break; 1909 #if V8_TARGET_ARCH_PPC64 1910 case kPPC_BitcastDoubleToInt64: 1911 __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0)); 1912 break; 1913 case kPPC_BitcastInt64ToDouble: 1914 __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0)); 1915 break; 1916 #endif 1917 case kPPC_LoadWordU8: 1918 ASSEMBLE_LOAD_INTEGER(lbz, lbzx); 1919 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1920 break; 1921 case kPPC_LoadWordS8: 1922 ASSEMBLE_LOAD_INTEGER(lbz, lbzx); 1923 __ extsb(i.OutputRegister(), i.OutputRegister()); 1924 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1925 break; 1926 case kPPC_LoadWordU16: 1927 ASSEMBLE_LOAD_INTEGER(lhz, lhzx); 1928 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1929 break; 1930 case kPPC_LoadWordS16: 1931 ASSEMBLE_LOAD_INTEGER(lha, lhax); 1932 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1933 break; 1934 case kPPC_LoadWordU32: 1935 ASSEMBLE_LOAD_INTEGER(lwz, lwzx); 1936 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1937 break; 1938 case kPPC_LoadWordS32: 1939 ASSEMBLE_LOAD_INTEGER(lwa, lwax); 1940 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1941 break; 1942 #if V8_TARGET_ARCH_PPC64 1943 case kPPC_LoadWord64: 1944 ASSEMBLE_LOAD_INTEGER(ld, ldx); 1945 EmitWordLoadPoisoningIfNeeded(this, instr, i); 1946 break; 1947 #endif 1948 case kPPC_LoadFloat32: 1949 ASSEMBLE_LOAD_FLOAT(lfs, lfsx); 1950 break; 1951 case kPPC_LoadDouble: 1952 ASSEMBLE_LOAD_FLOAT(lfd, lfdx); 1953 break; 1954 case kPPC_StoreWord8: 1955 ASSEMBLE_STORE_INTEGER(stb, stbx); 1956 break; 1957 case kPPC_StoreWord16: 1958 ASSEMBLE_STORE_INTEGER(sth, sthx); 1959 break; 1960 case kPPC_StoreWord32: 1961 ASSEMBLE_STORE_INTEGER(stw, stwx); 1962 break; 1963 #if V8_TARGET_ARCH_PPC64 1964 case kPPC_StoreWord64: 1965 ASSEMBLE_STORE_INTEGER(std, stdx); 1966 break; 1967 #endif 1968 case kPPC_StoreFloat32: 1969 ASSEMBLE_STORE_FLOAT32(); 1970 break; 1971 case kPPC_StoreDouble: 1972 ASSEMBLE_STORE_DOUBLE(); 1973 break; 1974 case kWord32AtomicLoadInt8: 1975 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbz, lbzx); 1976 __ extsb(i.OutputRegister(), i.OutputRegister()); 1977 break; 1978 case kWord32AtomicLoadUint8: 1979 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbz, lbzx); 1980 break; 1981 case kWord32AtomicLoadInt16: 1982 ASSEMBLE_ATOMIC_LOAD_INTEGER(lha, lhax); 1983 break; 1984 case kWord32AtomicLoadUint16: 1985 ASSEMBLE_ATOMIC_LOAD_INTEGER(lhz, lhzx); 1986 break; 1987 case kWord32AtomicLoadWord32: 1988 ASSEMBLE_ATOMIC_LOAD_INTEGER(lwz, lwzx); 1989 break; 1990 1991 case kWord32AtomicStoreWord8: 1992 ASSEMBLE_ATOMIC_STORE_INTEGER(stb, stbx); 1993 break; 1994 case kWord32AtomicStoreWord16: 1995 ASSEMBLE_ATOMIC_STORE_INTEGER(sth, sthx); 1996 break; 1997 case kWord32AtomicStoreWord32: 1998 ASSEMBLE_ATOMIC_STORE_INTEGER(stw, stwx); 1999 break; 2000 case kWord32AtomicExchangeInt8: 2001 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lbarx, stbcx); 2002 __ extsb(i.OutputRegister(0), i.OutputRegister(0)); 2003 break; 2004 case kWord32AtomicExchangeUint8: 2005 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lbarx, stbcx); 2006 break; 2007 case kWord32AtomicExchangeInt16: 2008 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lharx, sthcx); 2009 __ extsh(i.OutputRegister(0), i.OutputRegister(0)); 2010 break; 2011 case kWord32AtomicExchangeUint16: 2012 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lharx, sthcx); 2013 break; 2014 case kWord32AtomicExchangeWord32: 2015 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lwarx, stwcx); 2016 break; 2017 2018 case kWord32AtomicCompareExchangeInt8: 2019 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lbarx, stbcx, extsb); 2020 break; 2021 case kWord32AtomicCompareExchangeUint8: 2022 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lbarx, stbcx); 2023 break; 2024 case kWord32AtomicCompareExchangeInt16: 2025 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lharx, sthcx, extsh); 2026 break; 2027 case kWord32AtomicCompareExchangeUint16: 2028 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lharx, sthcx); 2029 break; 2030 case kWord32AtomicCompareExchangeWord32: 2031 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmpw, lwarx, stwcx); 2032 break; 2033 2034 #define ATOMIC_BINOP_CASE(op, inst) \ 2035 case kWord32Atomic##op##Int8: \ 2036 ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lbarx, stbcx, extsb); \ 2037 break; \ 2038 case kWord32Atomic##op##Uint8: \ 2039 ASSEMBLE_ATOMIC_BINOP(inst, lbarx, stbcx); \ 2040 break; \ 2041 case kWord32Atomic##op##Int16: \ 2042 ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lharx, sthcx, extsh); \ 2043 break; \ 2044 case kWord32Atomic##op##Uint16: \ 2045 ASSEMBLE_ATOMIC_BINOP(inst, lharx, sthcx); \ 2046 break; \ 2047 case kWord32Atomic##op##Word32: \ 2048 ASSEMBLE_ATOMIC_BINOP(inst, lwarx, stwcx); \ 2049 break; 2050 ATOMIC_BINOP_CASE(Add, add) 2051 ATOMIC_BINOP_CASE(Sub, sub) 2052 ATOMIC_BINOP_CASE(And, and_) 2053 ATOMIC_BINOP_CASE(Or, orx) 2054 ATOMIC_BINOP_CASE(Xor, xor_) 2055 #undef ATOMIC_BINOP_CASE 2056 2057 case kPPC_ByteRev32: { 2058 Register input = i.InputRegister(0); 2059 Register output = i.OutputRegister(); 2060 Register temp1 = r0; 2061 __ rotlwi(temp1, input, 8); 2062 __ rlwimi(temp1, input, 24, 0, 7); 2063 __ rlwimi(temp1, input, 24, 16, 23); 2064 __ extsw(output, temp1); 2065 break; 2066 } 2067 #ifdef V8_TARGET_ARCH_PPC64 2068 case kPPC_ByteRev64: { 2069 Register input = i.InputRegister(0); 2070 Register output = i.OutputRegister(); 2071 Register temp1 = r0; 2072 Register temp2 = kScratchReg; 2073 Register temp3 = i.TempRegister(0); 2074 __ rldicl(temp1, input, 32, 32); 2075 __ rotlwi(temp2, input, 8); 2076 __ rlwimi(temp2, input, 24, 0, 7); 2077 __ rotlwi(temp3, temp1, 8); 2078 __ rlwimi(temp2, input, 24, 16, 23); 2079 __ rlwimi(temp3, temp1, 24, 0, 7); 2080 __ rlwimi(temp3, temp1, 24, 16, 23); 2081 __ rldicr(temp2, temp2, 32, 31); 2082 __ orx(output, temp2, temp3); 2083 break; 2084 } 2085 #endif // V8_TARGET_ARCH_PPC64 2086 default: 2087 UNREACHABLE(); 2088 break; 2089 } 2090 return kSuccess; 2091 } // NOLINT(readability/fn_size) 2092 2093 2094 // Assembles branches after an instruction. 2095 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { 2096 PPCOperandConverter i(this, instr); 2097 Label* tlabel = branch->true_label; 2098 Label* flabel = branch->false_label; 2099 ArchOpcode op = instr->arch_opcode(); 2100 FlagsCondition condition = branch->condition; 2101 CRegister cr = cr0; 2102 2103 Condition cond = FlagsConditionToCondition(condition, op); 2104 if (op == kPPC_CmpDouble) { 2105 // check for unordered if necessary 2106 if (cond == le) { 2107 __ bunordered(flabel, cr); 2108 // Unnecessary for eq/lt since only FU bit will be set. 2109 } else if (cond == gt) { 2110 __ bunordered(tlabel, cr); 2111 // Unnecessary for ne/ge since only FU bit will be set. 2112 } 2113 } 2114 __ b(cond, tlabel, cr); 2115 if (!branch->fallthru) __ b(flabel); // no fallthru to flabel. 2116 } 2117 2118 void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition, 2119 Instruction* instr) { 2120 // TODO(John) Handle float comparisons (kUnordered[Not]Equal). 2121 if (condition == kUnorderedEqual || condition == kUnorderedNotEqual) { 2122 return; 2123 } 2124 2125 ArchOpcode op = instr->arch_opcode(); 2126 condition = NegateFlagsCondition(condition); 2127 __ li(kScratchReg, Operand::Zero()); 2128 __ isel(FlagsConditionToCondition(condition, op), kSpeculationPoisonRegister, 2129 kScratchReg, kSpeculationPoisonRegister, cr0); 2130 } 2131 2132 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr, 2133 BranchInfo* branch) { 2134 AssembleArchBranch(instr, branch); 2135 } 2136 2137 void CodeGenerator::AssembleArchJump(RpoNumber target) { 2138 if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target)); 2139 } 2140 2141 void CodeGenerator::AssembleArchTrap(Instruction* instr, 2142 FlagsCondition condition) { 2143 class OutOfLineTrap final : public OutOfLineCode { 2144 public: 2145 OutOfLineTrap(CodeGenerator* gen, Instruction* instr) 2146 : OutOfLineCode(gen), instr_(instr), gen_(gen) {} 2147 2148 void Generate() final { 2149 PPCOperandConverter i(gen_, instr_); 2150 TrapId trap_id = 2151 static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1)); 2152 GenerateCallToTrap(trap_id); 2153 } 2154 2155 private: 2156 void GenerateCallToTrap(TrapId trap_id) { 2157 if (trap_id == TrapId::kInvalid) { 2158 // We cannot test calls to the runtime in cctest/test-run-wasm. 2159 // Therefore we emit a call to C here instead of a call to the runtime. 2160 // We use the context register as the scratch register, because we do 2161 // not have a context here. 2162 __ PrepareCallCFunction(0, 0, cp); 2163 __ CallCFunction( 2164 ExternalReference::wasm_call_trap_callback_for_testing(), 0); 2165 __ LeaveFrame(StackFrame::WASM_COMPILED); 2166 auto call_descriptor = gen_->linkage()->GetIncomingDescriptor(); 2167 int pop_count = 2168 static_cast<int>(call_descriptor->StackParameterCount()); 2169 __ Drop(pop_count); 2170 __ Ret(); 2171 } else { 2172 gen_->AssembleSourcePosition(instr_); 2173 // A direct call to a wasm runtime stub defined in this module. 2174 // Just encode the stub index. This will be patched at relocation. 2175 __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL); 2176 ReferenceMap* reference_map = 2177 new (gen_->zone()) ReferenceMap(gen_->zone()); 2178 gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, 2179 Safepoint::kNoLazyDeopt); 2180 if (FLAG_debug_code) { 2181 __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromWasmTrap)); 2182 } 2183 } 2184 } 2185 2186 Instruction* instr_; 2187 CodeGenerator* gen_; 2188 }; 2189 auto ool = new (zone()) OutOfLineTrap(this, instr); 2190 Label* tlabel = ool->entry(); 2191 Label end; 2192 2193 ArchOpcode op = instr->arch_opcode(); 2194 CRegister cr = cr0; 2195 Condition cond = FlagsConditionToCondition(condition, op); 2196 if (op == kPPC_CmpDouble) { 2197 // check for unordered if necessary 2198 if (cond == le) { 2199 __ bunordered(&end, cr); 2200 // Unnecessary for eq/lt since only FU bit will be set. 2201 } else if (cond == gt) { 2202 __ bunordered(tlabel, cr); 2203 // Unnecessary for ne/ge since only FU bit will be set. 2204 } 2205 } 2206 __ b(cond, tlabel, cr); 2207 __ bind(&end); 2208 } 2209 2210 // Assembles boolean materializations after an instruction. 2211 void CodeGenerator::AssembleArchBoolean(Instruction* instr, 2212 FlagsCondition condition) { 2213 PPCOperandConverter i(this, instr); 2214 Label done; 2215 ArchOpcode op = instr->arch_opcode(); 2216 CRegister cr = cr0; 2217 int reg_value = -1; 2218 2219 // Materialize a full 32-bit 1 or 0 value. The result register is always the 2220 // last output of the instruction. 2221 DCHECK_NE(0u, instr->OutputCount()); 2222 Register reg = i.OutputRegister(instr->OutputCount() - 1); 2223 2224 Condition cond = FlagsConditionToCondition(condition, op); 2225 if (op == kPPC_CmpDouble) { 2226 // check for unordered if necessary 2227 if (cond == le) { 2228 reg_value = 0; 2229 __ li(reg, Operand::Zero()); 2230 __ bunordered(&done, cr); 2231 } else if (cond == gt) { 2232 reg_value = 1; 2233 __ li(reg, Operand(1)); 2234 __ bunordered(&done, cr); 2235 } 2236 // Unnecessary for eq/lt & ne/ge since only FU bit will be set. 2237 } 2238 2239 if (CpuFeatures::IsSupported(ISELECT)) { 2240 switch (cond) { 2241 case eq: 2242 case lt: 2243 case gt: 2244 if (reg_value != 1) __ li(reg, Operand(1)); 2245 __ li(kScratchReg, Operand::Zero()); 2246 __ isel(cond, reg, reg, kScratchReg, cr); 2247 break; 2248 case ne: 2249 case ge: 2250 case le: 2251 if (reg_value != 1) __ li(reg, Operand(1)); 2252 // r0 implies logical zero in this form 2253 __ isel(NegateCondition(cond), reg, r0, reg, cr); 2254 break; 2255 default: 2256 UNREACHABLE(); 2257 break; 2258 } 2259 } else { 2260 if (reg_value != 0) __ li(reg, Operand::Zero()); 2261 __ b(NegateCondition(cond), &done, cr); 2262 __ li(reg, Operand(1)); 2263 } 2264 __ bind(&done); 2265 } 2266 2267 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) { 2268 PPCOperandConverter i(this, instr); 2269 Register input = i.InputRegister(0); 2270 std::vector<std::pair<int32_t, Label*>> cases; 2271 for (size_t index = 2; index < instr->InputCount(); index += 2) { 2272 cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))}); 2273 } 2274 AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(), 2275 cases.data() + cases.size()); 2276 } 2277 2278 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { 2279 PPCOperandConverter i(this, instr); 2280 Register input = i.InputRegister(0); 2281 for (size_t index = 2; index < instr->InputCount(); index += 2) { 2282 __ Cmpwi(input, Operand(i.InputInt32(index + 0)), r0); 2283 __ beq(GetLabel(i.InputRpo(index + 1))); 2284 } 2285 AssembleArchJump(i.InputRpo(1)); 2286 } 2287 2288 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { 2289 PPCOperandConverter i(this, instr); 2290 Register input = i.InputRegister(0); 2291 int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2); 2292 Label** cases = zone()->NewArray<Label*>(case_count); 2293 for (int32_t index = 0; index < case_count; ++index) { 2294 cases[index] = GetLabel(i.InputRpo(index + 2)); 2295 } 2296 Label* const table = AddJumpTable(cases, case_count); 2297 __ Cmpli(input, Operand(case_count), r0); 2298 __ bge(GetLabel(i.InputRpo(1))); 2299 __ mov_label_addr(kScratchReg, table); 2300 __ ShiftLeftImm(r0, input, Operand(kPointerSizeLog2)); 2301 __ LoadPX(kScratchReg, MemOperand(kScratchReg, r0)); 2302 __ Jump(kScratchReg); 2303 } 2304 2305 void CodeGenerator::FinishFrame(Frame* frame) { 2306 auto call_descriptor = linkage()->GetIncomingDescriptor(); 2307 const RegList double_saves = call_descriptor->CalleeSavedFPRegisters(); 2308 2309 // Save callee-saved Double registers. 2310 if (double_saves != 0) { 2311 frame->AlignSavedCalleeRegisterSlots(); 2312 DCHECK_EQ(kNumCalleeSavedDoubles, 2313 base::bits::CountPopulation(double_saves)); 2314 frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles * 2315 (kDoubleSize / kPointerSize)); 2316 } 2317 // Save callee-saved registers. 2318 const RegList saves = FLAG_enable_embedded_constant_pool 2319 ? call_descriptor->CalleeSavedRegisters() & 2320 ~kConstantPoolRegister.bit() 2321 : call_descriptor->CalleeSavedRegisters(); 2322 if (saves != 0) { 2323 // register save area does not include the fp or constant pool pointer. 2324 const int num_saves = 2325 kNumCalleeSaved - 1 - (FLAG_enable_embedded_constant_pool ? 1 : 0); 2326 DCHECK(num_saves == base::bits::CountPopulation(saves)); 2327 frame->AllocateSavedCalleeRegisterSlots(num_saves); 2328 } 2329 } 2330 2331 void CodeGenerator::AssembleConstructFrame() { 2332 auto call_descriptor = linkage()->GetIncomingDescriptor(); 2333 if (frame_access_state()->has_frame()) { 2334 if (call_descriptor->IsCFunctionCall()) { 2335 __ function_descriptor(); 2336 __ mflr(r0); 2337 if (FLAG_enable_embedded_constant_pool) { 2338 __ Push(r0, fp, kConstantPoolRegister); 2339 // Adjust FP to point to saved FP. 2340 __ subi(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); 2341 } else { 2342 __ Push(r0, fp); 2343 __ mr(fp, sp); 2344 } 2345 } else if (call_descriptor->IsJSFunctionCall()) { 2346 __ Prologue(); 2347 if (call_descriptor->PushArgumentCount()) { 2348 __ Push(kJavaScriptCallArgCountRegister); 2349 } 2350 } else { 2351 StackFrame::Type type = info()->GetOutputStackFrameType(); 2352 // TODO(mbrandy): Detect cases where ip is the entrypoint (for 2353 // efficient intialization of the constant pool pointer register). 2354 __ StubPrologue(type); 2355 if (call_descriptor->IsWasmFunctionCall()) { 2356 __ Push(kWasmInstanceRegister); 2357 } 2358 } 2359 } 2360 2361 int shrink_slots = frame()->GetTotalFrameSlotCount() - 2362 call_descriptor->CalculateFixedFrameSize(); 2363 if (info()->is_osr()) { 2364 // TurboFan OSR-compiled functions cannot be entered directly. 2365 __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction); 2366 2367 // Unoptimized code jumps directly to this entrypoint while the unoptimized 2368 // frame is still on the stack. Optimized code uses OSR values directly from 2369 // the unoptimized frame. Thus, all that needs to be done is to allocate the 2370 // remaining stack slots. 2371 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 2372 osr_pc_offset_ = __ pc_offset(); 2373 shrink_slots -= osr_helper()->UnoptimizedFrameSlots(); 2374 ResetSpeculationPoison(); 2375 } 2376 2377 const RegList saves_fp = call_descriptor->CalleeSavedFPRegisters(); 2378 const RegList saves = FLAG_enable_embedded_constant_pool 2379 ? call_descriptor->CalleeSavedRegisters() & 2380 ~kConstantPoolRegister.bit() 2381 : call_descriptor->CalleeSavedRegisters(); 2382 2383 if (shrink_slots > 0) { 2384 if (info()->IsWasm() && shrink_slots > 128) { 2385 // For WebAssembly functions with big frames we have to do the stack 2386 // overflow check before we construct the frame. Otherwise we may not 2387 // have enough space on the stack to call the runtime for the stack 2388 // overflow. 2389 Label done; 2390 2391 // If the frame is bigger than the stack, we throw the stack overflow 2392 // exception unconditionally. Thereby we can avoid the integer overflow 2393 // check in the condition code. 2394 if ((shrink_slots * kPointerSize) < (FLAG_stack_size * 1024)) { 2395 Register scratch = ip; 2396 __ LoadP(scratch, FieldMemOperand( 2397 kWasmInstanceRegister, 2398 WasmInstanceObject::kRealStackLimitAddressOffset)); 2399 __ LoadP(scratch, MemOperand(scratch), r0); 2400 __ Add(scratch, scratch, shrink_slots * kPointerSize, r0); 2401 __ cmpl(sp, scratch); 2402 __ bge(&done); 2403 } 2404 2405 __ LoadP(r5, 2406 FieldMemOperand(kWasmInstanceRegister, 2407 WasmInstanceObject::kCEntryStubOffset), 2408 r0); 2409 __ Move(cp, Smi::kZero); 2410 __ CallRuntimeWithCEntry(Runtime::kThrowWasmStackOverflow, r5); 2411 // We come from WebAssembly, there are no references for the GC. 2412 ReferenceMap* reference_map = new (zone()) ReferenceMap(zone()); 2413 RecordSafepoint(reference_map, Safepoint::kSimple, 0, 2414 Safepoint::kNoLazyDeopt); 2415 if (FLAG_debug_code) { 2416 __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromThrow)); 2417 } 2418 2419 __ bind(&done); 2420 } 2421 2422 // Skip callee-saved and return slots, which are pushed below. 2423 shrink_slots -= base::bits::CountPopulation(saves); 2424 shrink_slots -= frame()->GetReturnSlotCount(); 2425 shrink_slots -= 2426 (kDoubleSize / kPointerSize) * base::bits::CountPopulation(saves_fp); 2427 __ Add(sp, sp, -shrink_slots * kPointerSize, r0); 2428 } 2429 2430 // Save callee-saved Double registers. 2431 if (saves_fp != 0) { 2432 __ MultiPushDoubles(saves_fp); 2433 DCHECK_EQ(kNumCalleeSavedDoubles, base::bits::CountPopulation(saves_fp)); 2434 } 2435 2436 // Save callee-saved registers. 2437 if (saves != 0) { 2438 __ MultiPush(saves); 2439 // register save area does not include the fp or constant pool pointer. 2440 } 2441 2442 const int returns = frame()->GetReturnSlotCount(); 2443 if (returns != 0) { 2444 // Create space for returns. 2445 __ Add(sp, sp, -returns * kPointerSize, r0); 2446 } 2447 } 2448 2449 void CodeGenerator::AssembleReturn(InstructionOperand* pop) { 2450 auto call_descriptor = linkage()->GetIncomingDescriptor(); 2451 int pop_count = static_cast<int>(call_descriptor->StackParameterCount()); 2452 2453 const int returns = frame()->GetReturnSlotCount(); 2454 if (returns != 0) { 2455 // Create space for returns. 2456 __ Add(sp, sp, returns * kPointerSize, r0); 2457 } 2458 2459 // Restore registers. 2460 const RegList saves = FLAG_enable_embedded_constant_pool 2461 ? call_descriptor->CalleeSavedRegisters() & 2462 ~kConstantPoolRegister.bit() 2463 : call_descriptor->CalleeSavedRegisters(); 2464 if (saves != 0) { 2465 __ MultiPop(saves); 2466 } 2467 2468 // Restore double registers. 2469 const RegList double_saves = call_descriptor->CalleeSavedFPRegisters(); 2470 if (double_saves != 0) { 2471 __ MultiPopDoubles(double_saves); 2472 } 2473 PPCOperandConverter g(this, nullptr); 2474 2475 if (call_descriptor->IsCFunctionCall()) { 2476 AssembleDeconstructFrame(); 2477 } else if (frame_access_state()->has_frame()) { 2478 // Canonicalize JSFunction return sites for now unless they have an variable 2479 // number of stack slot pops 2480 if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) { 2481 if (return_label_.is_bound()) { 2482 __ b(&return_label_); 2483 return; 2484 } else { 2485 __ bind(&return_label_); 2486 AssembleDeconstructFrame(); 2487 } 2488 } else { 2489 AssembleDeconstructFrame(); 2490 } 2491 } 2492 // Constant pool is unavailable since the frame has been destructed 2493 ConstantPoolUnavailableScope constant_pool_unavailable(tasm()); 2494 if (pop->IsImmediate()) { 2495 DCHECK(Constant::kInt32 == g.ToConstant(pop).type() || 2496 Constant::kInt64 == g.ToConstant(pop).type()); 2497 pop_count += g.ToConstant(pop).ToInt32(); 2498 } else { 2499 __ Drop(g.ToRegister(pop)); 2500 } 2501 __ Drop(pop_count); 2502 __ Ret(); 2503 } 2504 2505 void CodeGenerator::FinishCode() { __ EmitConstantPool(); } 2506 2507 void CodeGenerator::AssembleMove(InstructionOperand* source, 2508 InstructionOperand* destination) { 2509 PPCOperandConverter g(this, nullptr); 2510 // Dispatch on the source and destination operand kinds. Not all 2511 // combinations are possible. 2512 if (source->IsRegister()) { 2513 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2514 Register src = g.ToRegister(source); 2515 if (destination->IsRegister()) { 2516 __ Move(g.ToRegister(destination), src); 2517 } else { 2518 __ StoreP(src, g.ToMemOperand(destination), r0); 2519 } 2520 } else if (source->IsStackSlot()) { 2521 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2522 MemOperand src = g.ToMemOperand(source); 2523 if (destination->IsRegister()) { 2524 __ LoadP(g.ToRegister(destination), src, r0); 2525 } else { 2526 Register temp = kScratchReg; 2527 __ LoadP(temp, src, r0); 2528 __ StoreP(temp, g.ToMemOperand(destination), r0); 2529 } 2530 } else if (source->IsConstant()) { 2531 Constant src = g.ToConstant(source); 2532 if (destination->IsRegister() || destination->IsStackSlot()) { 2533 Register dst = 2534 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; 2535 switch (src.type()) { 2536 case Constant::kInt32: 2537 #if V8_TARGET_ARCH_PPC64 2538 if (false) { 2539 #else 2540 if (RelocInfo::IsWasmReference(src.rmode())) { 2541 #endif 2542 __ mov(dst, Operand(src.ToInt32(), src.rmode())); 2543 } else { 2544 __ mov(dst, Operand(src.ToInt32())); 2545 } 2546 break; 2547 case Constant::kInt64: 2548 #if V8_TARGET_ARCH_PPC64 2549 if (RelocInfo::IsWasmPtrReference(src.rmode())) { 2550 __ mov(dst, Operand(src.ToInt64(), src.rmode())); 2551 } else { 2552 #endif 2553 __ mov(dst, Operand(src.ToInt64())); 2554 #if V8_TARGET_ARCH_PPC64 2555 } 2556 #endif 2557 break; 2558 case Constant::kFloat32: 2559 __ mov(dst, Operand::EmbeddedNumber(src.ToFloat32())); 2560 break; 2561 case Constant::kFloat64: 2562 __ mov(dst, Operand::EmbeddedNumber(src.ToFloat64().value())); 2563 break; 2564 case Constant::kExternalReference: 2565 __ Move(dst, src.ToExternalReference()); 2566 break; 2567 case Constant::kHeapObject: { 2568 Handle<HeapObject> src_object = src.ToHeapObject(); 2569 Heap::RootListIndex index; 2570 if (IsMaterializableFromRoot(src_object, &index)) { 2571 __ LoadRoot(dst, index); 2572 } else { 2573 __ Move(dst, src_object); 2574 } 2575 break; 2576 } 2577 case Constant::kRpoNumber: 2578 UNREACHABLE(); // TODO(dcarney): loading RPO constants on PPC. 2579 break; 2580 } 2581 if (destination->IsStackSlot()) { 2582 __ StoreP(dst, g.ToMemOperand(destination), r0); 2583 } 2584 } else { 2585 DoubleRegister dst = destination->IsFPRegister() 2586 ? g.ToDoubleRegister(destination) 2587 : kScratchDoubleReg; 2588 Double value; 2589 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 2590 // casting double precision snan to single precision 2591 // converts it to qnan on ia32/x64 2592 if (src.type() == Constant::kFloat32) { 2593 uint32_t val = src.ToFloat32AsInt(); 2594 if ((val & 0x7F800000) == 0x7F800000) { 2595 uint64_t dval = static_cast<uint64_t>(val); 2596 dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) | 2597 ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29); 2598 value = Double(dval); 2599 } else { 2600 value = Double(static_cast<double>(src.ToFloat32())); 2601 } 2602 } else { 2603 value = Double(src.ToFloat64()); 2604 } 2605 #else 2606 value = src.type() == Constant::kFloat32 2607 ? Double(static_cast<double>(src.ToFloat32())) 2608 : Double(src.ToFloat64()); 2609 #endif 2610 __ LoadDoubleLiteral(dst, value, kScratchReg); 2611 if (destination->IsDoubleStackSlot()) { 2612 __ StoreDouble(dst, g.ToMemOperand(destination), r0); 2613 } else if (destination->IsFloatStackSlot()) { 2614 __ StoreSingle(dst, g.ToMemOperand(destination), r0); 2615 } 2616 } 2617 } else if (source->IsFPRegister()) { 2618 DoubleRegister src = g.ToDoubleRegister(source); 2619 if (destination->IsFPRegister()) { 2620 DoubleRegister dst = g.ToDoubleRegister(destination); 2621 __ Move(dst, src); 2622 } else { 2623 DCHECK(destination->IsFPStackSlot()); 2624 LocationOperand* op = LocationOperand::cast(source); 2625 if (op->representation() == MachineRepresentation::kFloat64) { 2626 __ StoreDouble(src, g.ToMemOperand(destination), r0); 2627 } else { 2628 __ StoreSingle(src, g.ToMemOperand(destination), r0); 2629 } 2630 } 2631 } else if (source->IsFPStackSlot()) { 2632 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); 2633 MemOperand src = g.ToMemOperand(source); 2634 if (destination->IsFPRegister()) { 2635 LocationOperand* op = LocationOperand::cast(source); 2636 if (op->representation() == MachineRepresentation::kFloat64) { 2637 __ LoadDouble(g.ToDoubleRegister(destination), src, r0); 2638 } else { 2639 __ LoadSingle(g.ToDoubleRegister(destination), src, r0); 2640 } 2641 } else { 2642 LocationOperand* op = LocationOperand::cast(source); 2643 DoubleRegister temp = kScratchDoubleReg; 2644 if (op->representation() == MachineRepresentation::kFloat64) { 2645 __ LoadDouble(temp, src, r0); 2646 __ StoreDouble(temp, g.ToMemOperand(destination), r0); 2647 } else { 2648 __ LoadSingle(temp, src, r0); 2649 __ StoreSingle(temp, g.ToMemOperand(destination), r0); 2650 } 2651 } 2652 } else { 2653 UNREACHABLE(); 2654 } 2655 } 2656 2657 // Swaping contents in source and destination. 2658 // source and destination could be: 2659 // Register, 2660 // FloatRegister, 2661 // DoubleRegister, 2662 // StackSlot, 2663 // FloatStackSlot, 2664 // or DoubleStackSlot 2665 void CodeGenerator::AssembleSwap(InstructionOperand* source, 2666 InstructionOperand* destination) { 2667 PPCOperandConverter g(this, nullptr); 2668 if (source->IsRegister()) { 2669 Register src = g.ToRegister(source); 2670 if (destination->IsRegister()) { 2671 __ SwapP(src, g.ToRegister(destination), kScratchReg); 2672 } else { 2673 DCHECK(destination->IsStackSlot()); 2674 __ SwapP(src, g.ToMemOperand(destination), kScratchReg); 2675 } 2676 } else if (source->IsStackSlot()) { 2677 DCHECK(destination->IsStackSlot()); 2678 __ SwapP(g.ToMemOperand(source), g.ToMemOperand(destination), kScratchReg, 2679 r0); 2680 } else if (source->IsFloatRegister()) { 2681 DoubleRegister src = g.ToDoubleRegister(source); 2682 if (destination->IsFloatRegister()) { 2683 __ SwapFloat32(src, g.ToDoubleRegister(destination), kScratchDoubleReg); 2684 } else { 2685 DCHECK(destination->IsFloatStackSlot()); 2686 __ SwapFloat32(src, g.ToMemOperand(destination), kScratchDoubleReg); 2687 } 2688 } else if (source->IsDoubleRegister()) { 2689 DoubleRegister src = g.ToDoubleRegister(source); 2690 if (destination->IsDoubleRegister()) { 2691 __ SwapDouble(src, g.ToDoubleRegister(destination), kScratchDoubleReg); 2692 } else { 2693 DCHECK(destination->IsDoubleStackSlot()); 2694 __ SwapDouble(src, g.ToMemOperand(destination), kScratchDoubleReg); 2695 } 2696 } else if (source->IsFloatStackSlot()) { 2697 DCHECK(destination->IsFloatStackSlot()); 2698 __ SwapFloat32(g.ToMemOperand(source), g.ToMemOperand(destination), 2699 kScratchDoubleReg, d0); 2700 } else if (source->IsDoubleStackSlot()) { 2701 DCHECK(destination->IsDoubleStackSlot()); 2702 __ SwapDouble(g.ToMemOperand(source), g.ToMemOperand(destination), 2703 kScratchDoubleReg, d0); 2704 } else if (source->IsSimd128Register()) { 2705 UNREACHABLE(); 2706 } else { 2707 UNREACHABLE(); 2708 } 2709 2710 return; 2711 } 2712 2713 2714 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { 2715 for (size_t index = 0; index < target_count; ++index) { 2716 __ emit_label_addr(targets[index]); 2717 } 2718 } 2719 2720 2721 #undef __ 2722 2723 } // namespace compiler 2724 } // namespace internal 2725 } // namespace v8 2726