1// Copyright (c) 1994-2006 Sun Microsystems Inc. 2// All Rights Reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions 6// are met: 7// 8// - Redistributions of source code must retain the above copyright notice, 9// this list of conditions and the following disclaimer. 10// 11// - Redistribution in binary form must reproduce the above copyright 12// notice, this list of conditions and the following disclaimer in the 13// documentation and/or other materials provided with the 14// distribution. 15// 16// - Neither the name of Sun Microsystems or the names of contributors may 17// be used to endorse or promote products derived from this software without 18// specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31// OF THE POSSIBILITY OF SUCH DAMAGE. 32 33// The original source code covered by the above license above has been 34// modified significantly by Google Inc. 35// Copyright 2014 the V8 project authors. All rights reserved. 36 37#include "src/codegen/ppc/assembler-ppc.h" 38 39#if V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 40 41#include "src/base/bits.h" 42#include "src/base/cpu.h" 43#include "src/codegen/macro-assembler.h" 44#include "src/codegen/ppc/assembler-ppc-inl.h" 45#include "src/codegen/string-constants.h" 46#include "src/deoptimizer/deoptimizer.h" 47 48namespace v8 { 49namespace internal { 50 51// Get the CPU features enabled by the build. 52static unsigned CpuFeaturesImpliedByCompiler() { 53 unsigned answer = 0; 54 return answer; 55} 56 57bool CpuFeatures::SupportsWasmSimd128() { 58#if V8_ENABLE_WEBASSEMBLY 59 return CpuFeatures::IsSupported(PPC_9_PLUS); 60#else 61 return false; 62#endif // V8_ENABLE_WEBASSEMBLY 63} 64 65void CpuFeatures::ProbeImpl(bool cross_compile) { 66 supported_ |= CpuFeaturesImpliedByCompiler(); 67 icache_line_size_ = 128; 68 69 // Only use statically determined features for cross compile (snapshot). 70 if (cross_compile) return; 71 72// Probe for additional features at runtime. 73#ifdef USE_SIMULATOR 74 // Simulator 75 supported_ |= (1u << PPC_10_PLUS); 76#else 77 base::CPU cpu; 78 if (cpu.part() == base::CPU::kPPCPower10) { 79// IBMi does not yet support prefixed instructions introduced on Power10. 80// Run on P9 mode until OS adds support. 81#if defined(__PASE__) 82 supported_ |= (1u << PPC_9_PLUS); 83#else 84 supported_ |= (1u << PPC_10_PLUS); 85#endif 86 } else if (cpu.part() == base::CPU::kPPCPower9) { 87 supported_ |= (1u << PPC_9_PLUS); 88 } else if (cpu.part() == base::CPU::kPPCPower8) { 89 supported_ |= (1u << PPC_8_PLUS); 90 } else if (cpu.part() == base::CPU::kPPCPower7) { 91 supported_ |= (1u << PPC_7_PLUS); 92 } else if (cpu.part() == base::CPU::kPPCPower6) { 93 supported_ |= (1u << PPC_6_PLUS); 94 } 95#if V8_OS_LINUX 96 if (cpu.icache_line_size() != base::CPU::kUnknownCacheLineSize) { 97 icache_line_size_ = cpu.icache_line_size(); 98 } 99#endif 100#endif 101 if (supported_ & (1u << PPC_10_PLUS)) supported_ |= (1u << PPC_9_PLUS); 102 if (supported_ & (1u << PPC_9_PLUS)) supported_ |= (1u << PPC_8_PLUS); 103 if (supported_ & (1u << PPC_8_PLUS)) supported_ |= (1u << PPC_7_PLUS); 104 if (supported_ & (1u << PPC_7_PLUS)) supported_ |= (1u << PPC_6_PLUS); 105 106 // Set a static value on whether Simd is supported. 107 // This variable is only used for certain archs to query SupportWasmSimd128() 108 // at runtime in builtins using an extern ref. Other callers should use 109 // CpuFeatures::SupportWasmSimd128(). 110 CpuFeatures::supports_wasm_simd_128_ = CpuFeatures::SupportsWasmSimd128(); 111} 112 113void CpuFeatures::PrintTarget() { 114 const char* ppc_arch = nullptr; 115 116#if V8_TARGET_ARCH_PPC64 117 ppc_arch = "ppc64"; 118#else 119 ppc_arch = "ppc"; 120#endif 121 122 printf("target %s\n", ppc_arch); 123} 124 125void CpuFeatures::PrintFeatures() { 126 printf("PPC_6_PLUS=%d\n", CpuFeatures::IsSupported(PPC_6_PLUS)); 127 printf("PPC_7_PLUS=%d\n", CpuFeatures::IsSupported(PPC_7_PLUS)); 128 printf("PPC_8_PLUS=%d\n", CpuFeatures::IsSupported(PPC_8_PLUS)); 129 printf("PPC_9_PLUS=%d\n", CpuFeatures::IsSupported(PPC_9_PLUS)); 130 printf("PPC_10_PLUS=%d\n", CpuFeatures::IsSupported(PPC_10_PLUS)); 131} 132 133Register ToRegister(int num) { 134 DCHECK(num >= 0 && num < kNumRegisters); 135 const Register kRegisters[] = {r0, sp, r2, r3, r4, r5, r6, r7, 136 r8, r9, r10, r11, ip, r13, r14, r15, 137 r16, r17, r18, r19, r20, r21, r22, r23, 138 r24, r25, r26, r27, r28, r29, r30, fp}; 139 return kRegisters[num]; 140} 141 142// ----------------------------------------------------------------------------- 143// Implementation of RelocInfo 144 145const int RelocInfo::kApplyMask = 146 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 147 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED); 148 149bool RelocInfo::IsCodedSpecially() { 150 // The deserializer needs to know whether a pointer is specially 151 // coded. Being specially coded on PPC means that it is a lis/ori 152 // instruction sequence or is a constant pool entry, and these are 153 // always the case inside code objects. 154 return true; 155} 156 157bool RelocInfo::IsInConstantPool() { 158 if (FLAG_enable_embedded_constant_pool && constant_pool_ != kNullAddress) { 159 return Assembler::IsConstantPoolLoadStart(pc_); 160 } 161 return false; 162} 163 164uint32_t RelocInfo::wasm_call_tag() const { 165 DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL); 166 return static_cast<uint32_t>( 167 Assembler::target_address_at(pc_, constant_pool_)); 168} 169 170// ----------------------------------------------------------------------------- 171// Implementation of Operand and MemOperand 172// See assembler-ppc-inl.h for inlined constructors 173 174Operand::Operand(Handle<HeapObject> handle) { 175 rm_ = no_reg; 176 value_.immediate = static_cast<intptr_t>(handle.address()); 177 rmode_ = RelocInfo::FULL_EMBEDDED_OBJECT; 178} 179 180Operand Operand::EmbeddedNumber(double value) { 181 int32_t smi; 182 if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi)); 183 Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT); 184 result.is_heap_object_request_ = true; 185 result.value_.heap_object_request = HeapObjectRequest(value); 186 return result; 187} 188 189Operand Operand::EmbeddedStringConstant(const StringConstantBase* str) { 190 Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT); 191 result.is_heap_object_request_ = true; 192 result.value_.heap_object_request = HeapObjectRequest(str); 193 return result; 194} 195 196MemOperand::MemOperand(Register rn, int64_t offset) 197 : ra_(rn), offset_(offset), rb_(no_reg) {} 198 199MemOperand::MemOperand(Register ra, Register rb) 200 : ra_(ra), offset_(0), rb_(rb) {} 201 202MemOperand::MemOperand(Register ra, Register rb, int64_t offset) 203 : ra_(ra), offset_(offset), rb_(rb) {} 204 205void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { 206 DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty()); 207 for (auto& request : heap_object_requests_) { 208 Handle<HeapObject> object; 209 switch (request.kind()) { 210 case HeapObjectRequest::kHeapNumber: { 211 object = isolate->factory()->NewHeapNumber<AllocationType::kOld>( 212 request.heap_number()); 213 break; 214 } 215 case HeapObjectRequest::kStringConstant: { 216 const StringConstantBase* str = request.string(); 217 CHECK_NOT_NULL(str); 218 object = str->AllocateStringConstant(isolate); 219 break; 220 } 221 } 222 Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset(); 223 Address constant_pool = kNullAddress; 224 set_target_address_at(pc, constant_pool, object.address(), 225 SKIP_ICACHE_FLUSH); 226 } 227} 228 229// ----------------------------------------------------------------------------- 230// Specific instructions, constants, and masks. 231 232Assembler::Assembler(const AssemblerOptions& options, 233 std::unique_ptr<AssemblerBuffer> buffer) 234 : AssemblerBase(options, std::move(buffer)), 235 scratch_register_list_({ip}), 236 constant_pool_builder_(kLoadPtrMaxReachBits, kLoadDoubleMaxReachBits) { 237 reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_); 238 239 no_trampoline_pool_before_ = 0; 240 trampoline_pool_blocked_nesting_ = 0; 241 constant_pool_entry_sharing_blocked_nesting_ = 0; 242 next_trampoline_check_ = kMaxInt; 243 internal_trampoline_exception_ = false; 244 last_bound_pos_ = 0; 245 optimizable_cmpi_pos_ = -1; 246 trampoline_emitted_ = FLAG_force_long_branches; 247 tracked_branch_count_ = 0; 248 relocations_.reserve(128); 249} 250 251void Assembler::GetCode(Isolate* isolate, CodeDesc* desc, 252 SafepointTableBuilder* safepoint_table_builder, 253 int handler_table_offset) { 254 // As a crutch to avoid having to add manual Align calls wherever we use a 255 // raw workflow to create Code objects (mostly in tests), add another Align 256 // call here. It does no harm - the end of the Code object is aligned to the 257 // (larger) kCodeAlignment anyways. 258 // TODO(jgruber): Consider moving responsibility for proper alignment to 259 // metadata table builders (safepoint, handler, constant pool, code 260 // comments). 261 DataAlign(Code::kMetadataAlignment); 262 263 // Emit constant pool if necessary. 264 int constant_pool_size = EmitConstantPool(); 265 266 EmitRelocations(); 267 268 int code_comments_size = WriteCodeComments(); 269 270 AllocateAndInstallRequestedHeapObjects(isolate); 271 272 // Set up code descriptor. 273 // TODO(jgruber): Reconsider how these offsets and sizes are maintained up to 274 // this point to make CodeDesc initialization less fiddly. 275 276 const int instruction_size = pc_offset(); 277 const int code_comments_offset = instruction_size - code_comments_size; 278 const int constant_pool_offset = code_comments_offset - constant_pool_size; 279 const int handler_table_offset2 = (handler_table_offset == kNoHandlerTable) 280 ? constant_pool_offset 281 : handler_table_offset; 282 const int safepoint_table_offset = 283 (safepoint_table_builder == kNoSafepointTable) 284 ? handler_table_offset2 285 : safepoint_table_builder->safepoint_table_offset(); 286 const int reloc_info_offset = 287 static_cast<int>(reloc_info_writer.pos() - buffer_->start()); 288 CodeDesc::Initialize(desc, this, safepoint_table_offset, 289 handler_table_offset2, constant_pool_offset, 290 code_comments_offset, reloc_info_offset); 291} 292 293void Assembler::Align(int m) { 294 DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m)); 295 DCHECK_EQ(pc_offset() & (kInstrSize - 1), 0); 296 while ((pc_offset() & (m - 1)) != 0) { 297 nop(); 298 } 299} 300 301void Assembler::CodeTargetAlign() { Align(8); } 302 303Condition Assembler::GetCondition(Instr instr) { 304 switch (instr & kCondMask) { 305 case BT: 306 return eq; 307 case BF: 308 return ne; 309 default: 310 UNIMPLEMENTED(); 311 } 312} 313 314bool Assembler::IsLis(Instr instr) { 315 return ((instr & kOpcodeMask) == ADDIS) && GetRA(instr) == r0; 316} 317 318bool Assembler::IsLi(Instr instr) { 319 return ((instr & kOpcodeMask) == ADDI) && GetRA(instr) == r0; 320} 321 322bool Assembler::IsAddic(Instr instr) { return (instr & kOpcodeMask) == ADDIC; } 323 324bool Assembler::IsOri(Instr instr) { return (instr & kOpcodeMask) == ORI; } 325 326bool Assembler::IsBranch(Instr instr) { return ((instr & kOpcodeMask) == BCX); } 327 328Register Assembler::GetRA(Instr instr) { 329 return Register::from_code(Instruction::RAValue(instr)); 330} 331 332Register Assembler::GetRB(Instr instr) { 333 return Register::from_code(Instruction::RBValue(instr)); 334} 335 336#if V8_TARGET_ARCH_PPC64 337// This code assumes a FIXED_SEQUENCE for 64bit loads (lis/ori) 338bool Assembler::Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3, 339 Instr instr4, Instr instr5) { 340 // Check the instructions are indeed a five part load (into r12) 341 // 3d800000 lis r12, 0 342 // 618c0000 ori r12, r12, 0 343 // 798c07c6 rldicr r12, r12, 32, 31 344 // 658c00c3 oris r12, r12, 195 345 // 618ccd40 ori r12, r12, 52544 346 return (((instr1 >> 16) == 0x3D80) && ((instr2 >> 16) == 0x618C) && 347 (instr3 == 0x798C07C6) && ((instr4 >> 16) == 0x658C) && 348 ((instr5 >> 16) == 0x618C)); 349} 350#else 351// This code assumes a FIXED_SEQUENCE for 32bit loads (lis/ori) 352bool Assembler::Is32BitLoadIntoR12(Instr instr1, Instr instr2) { 353 // Check the instruction is indeed a two part load (into r12) 354 // 3d802553 lis r12, 9555 355 // 618c5000 ori r12, r12, 20480 356 return (((instr1 >> 16) == 0x3D80) && ((instr2 >> 16) == 0x618C)); 357} 358#endif 359 360bool Assembler::IsCmpRegister(Instr instr) { 361 return (((instr & kOpcodeMask) == EXT2) && 362 ((EXT2 | (instr & kExt2OpcodeMask)) == CMP)); 363} 364 365bool Assembler::IsRlwinm(Instr instr) { 366 return ((instr & kOpcodeMask) == RLWINMX); 367} 368 369bool Assembler::IsAndi(Instr instr) { return ((instr & kOpcodeMask) == ANDIx); } 370 371#if V8_TARGET_ARCH_PPC64 372bool Assembler::IsRldicl(Instr instr) { 373 return (((instr & kOpcodeMask) == EXT5) && 374 ((EXT5 | (instr & kExt5OpcodeMask)) == RLDICL)); 375} 376#endif 377 378bool Assembler::IsCmpImmediate(Instr instr) { 379 return ((instr & kOpcodeMask) == CMPI); 380} 381 382bool Assembler::IsCrSet(Instr instr) { 383 return (((instr & kOpcodeMask) == EXT1) && 384 ((EXT1 | (instr & kExt1OpcodeMask)) == CREQV)); 385} 386 387Register Assembler::GetCmpImmediateRegister(Instr instr) { 388 DCHECK(IsCmpImmediate(instr)); 389 return GetRA(instr); 390} 391 392int Assembler::GetCmpImmediateRawImmediate(Instr instr) { 393 DCHECK(IsCmpImmediate(instr)); 394 return instr & kOff16Mask; 395} 396 397// Labels refer to positions in the (to be) generated code. 398// There are bound, linked, and unused labels. 399// 400// Bound labels refer to known positions in the already 401// generated code. pos() is the position the label refers to. 402// 403// Linked labels refer to unknown positions in the code 404// to be generated; pos() is the position of the last 405// instruction using the label. 406 407// The link chain is terminated by a negative code position (must be aligned) 408const int kEndOfChain = -4; 409 410// Dummy opcodes for unbound label mov instructions or jump table entries. 411enum { 412 kUnboundMovLabelOffsetOpcode = 0 << 26, 413 kUnboundAddLabelOffsetOpcode = 1 << 26, 414 kUnboundAddLabelLongOffsetOpcode = 2 << 26, 415 kUnboundMovLabelAddrOpcode = 3 << 26, 416 kUnboundJumpTableEntryOpcode = 4 << 26 417}; 418 419int Assembler::target_at(int pos) { 420 Instr instr = instr_at(pos); 421 // check which type of branch this is 16 or 26 bit offset 422 uint32_t opcode = instr & kOpcodeMask; 423 int link; 424 switch (opcode) { 425 case BX: 426 link = SIGN_EXT_IMM26(instr & kImm26Mask); 427 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present 428 break; 429 case BCX: 430 link = SIGN_EXT_IMM16((instr & kImm16Mask)); 431 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present 432 break; 433 case kUnboundMovLabelOffsetOpcode: 434 case kUnboundAddLabelOffsetOpcode: 435 case kUnboundAddLabelLongOffsetOpcode: 436 case kUnboundMovLabelAddrOpcode: 437 case kUnboundJumpTableEntryOpcode: 438 link = SIGN_EXT_IMM26(instr & kImm26Mask); 439 link <<= 2; 440 break; 441 default: 442 DCHECK(false); 443 return -1; 444 } 445 446 if (link == 0) return kEndOfChain; 447 return pos + link; 448} 449 450void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { 451 Instr instr = instr_at(pos); 452 uint32_t opcode = instr & kOpcodeMask; 453 454 if (is_branch != nullptr) { 455 *is_branch = (opcode == BX || opcode == BCX); 456 } 457 458 switch (opcode) { 459 case BX: { 460 int imm26 = target_pos - pos; 461 CHECK(is_int26(imm26) && (imm26 & (kAAMask | kLKMask)) == 0); 462 if (imm26 == kInstrSize && !(instr & kLKMask)) { 463 // Branch to next instr without link. 464 instr = ORI; // nop: ori, 0,0,0 465 } else { 466 instr &= ((~kImm26Mask) | kAAMask | kLKMask); 467 instr |= (imm26 & kImm26Mask); 468 } 469 instr_at_put(pos, instr); 470 break; 471 } 472 case BCX: { 473 int imm16 = target_pos - pos; 474 CHECK(is_int16(imm16) && (imm16 & (kAAMask | kLKMask)) == 0); 475 if (imm16 == kInstrSize && !(instr & kLKMask)) { 476 // Branch to next instr without link. 477 instr = ORI; // nop: ori, 0,0,0 478 } else { 479 instr &= ((~kImm16Mask) | kAAMask | kLKMask); 480 instr |= (imm16 & kImm16Mask); 481 } 482 instr_at_put(pos, instr); 483 break; 484 } 485 case kUnboundMovLabelOffsetOpcode: { 486 // Load the position of the label relative to the generated code object 487 // pointer in a register. 488 Register dst = Register::from_code(instr_at(pos + kInstrSize)); 489 int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag); 490 PatchingAssembler patcher( 491 options(), reinterpret_cast<byte*>(buffer_start_ + pos), 2); 492 patcher.bitwise_mov32(dst, offset); 493 break; 494 } 495 case kUnboundAddLabelLongOffsetOpcode: 496 case kUnboundAddLabelOffsetOpcode: { 497 // dst = base + position + immediate 498 Instr operands = instr_at(pos + kInstrSize); 499 Register dst = Register::from_code((operands >> 27) & 0x1F); 500 Register base = Register::from_code((operands >> 22) & 0x1F); 501 int32_t delta = (opcode == kUnboundAddLabelLongOffsetOpcode) 502 ? static_cast<int32_t>(instr_at(pos + 2 * kInstrSize)) 503 : (SIGN_EXT_IMM22(operands & kImm22Mask)); 504 int32_t offset = target_pos + delta; 505 PatchingAssembler patcher( 506 options(), reinterpret_cast<byte*>(buffer_start_ + pos), 507 2 + static_cast<int32_t>(opcode == kUnboundAddLabelLongOffsetOpcode)); 508 patcher.bitwise_add32(dst, base, offset); 509 if (opcode == kUnboundAddLabelLongOffsetOpcode) patcher.nop(); 510 break; 511 } 512 case kUnboundMovLabelAddrOpcode: { 513 // Load the address of the label in a register. 514 Register dst = Register::from_code(instr_at(pos + kInstrSize)); 515 PatchingAssembler patcher(options(), 516 reinterpret_cast<byte*>(buffer_start_ + pos), 517 kMovInstructionsNoConstantPool); 518 // Keep internal references relative until EmitRelocations. 519 patcher.bitwise_mov(dst, target_pos); 520 break; 521 } 522 case kUnboundJumpTableEntryOpcode: { 523 PatchingAssembler patcher(options(), 524 reinterpret_cast<byte*>(buffer_start_ + pos), 525 kSystemPointerSize / kInstrSize); 526 // Keep internal references relative until EmitRelocations. 527 patcher.dp(target_pos); 528 break; 529 } 530 default: 531 DCHECK(false); 532 break; 533 } 534} 535 536int Assembler::max_reach_from(int pos) { 537 Instr instr = instr_at(pos); 538 uint32_t opcode = instr & kOpcodeMask; 539 540 // check which type of branch this is 16 or 26 bit offset 541 switch (opcode) { 542 case BX: 543 return 26; 544 case BCX: 545 return 16; 546 case kUnboundMovLabelOffsetOpcode: 547 case kUnboundAddLabelOffsetOpcode: 548 case kUnboundMovLabelAddrOpcode: 549 case kUnboundJumpTableEntryOpcode: 550 return 0; // no limit on reach 551 } 552 553 DCHECK(false); 554 return 0; 555} 556 557void Assembler::bind_to(Label* L, int pos) { 558 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position 559 int32_t trampoline_pos = kInvalidSlotPos; 560 bool is_branch = false; 561 while (L->is_linked()) { 562 int fixup_pos = L->pos(); 563 int32_t offset = pos - fixup_pos; 564 int maxReach = max_reach_from(fixup_pos); 565 next(L); // call next before overwriting link with target at fixup_pos 566 if (maxReach && is_intn(offset, maxReach) == false) { 567 if (trampoline_pos == kInvalidSlotPos) { 568 trampoline_pos = get_trampoline_entry(); 569 CHECK_NE(trampoline_pos, kInvalidSlotPos); 570 target_at_put(trampoline_pos, pos); 571 } 572 target_at_put(fixup_pos, trampoline_pos); 573 } else { 574 target_at_put(fixup_pos, pos, &is_branch); 575 } 576 } 577 L->bind_to(pos); 578 579 if (!trampoline_emitted_ && is_branch) { 580 UntrackBranch(); 581 } 582 583 // Keep track of the last bound label so we don't eliminate any instructions 584 // before a bound label. 585 if (pos > last_bound_pos_) last_bound_pos_ = pos; 586} 587 588void Assembler::bind(Label* L) { 589 DCHECK(!L->is_bound()); // label can only be bound once 590 bind_to(L, pc_offset()); 591} 592 593void Assembler::next(Label* L) { 594 DCHECK(L->is_linked()); 595 int link = target_at(L->pos()); 596 if (link == kEndOfChain) { 597 L->Unuse(); 598 } else { 599 DCHECK_GE(link, 0); 600 L->link_to(link); 601 } 602} 603 604bool Assembler::is_near(Label* L, Condition cond) { 605 DCHECK(L->is_bound()); 606 if (L->is_bound() == false) return false; 607 608 int maxReach = ((cond == al) ? 26 : 16); 609 int offset = L->pos() - pc_offset(); 610 611 return is_intn(offset, maxReach); 612} 613 614void Assembler::a_form(Instr instr, DoubleRegister frt, DoubleRegister fra, 615 DoubleRegister frb, RCBit r) { 616 emit(instr | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | r); 617} 618 619void Assembler::d_form(Instr instr, Register rt, Register ra, 620 const intptr_t val, bool signed_disp) { 621 if (signed_disp) { 622 if (!is_int16(val)) { 623 PrintF("val = %" V8PRIdPTR ", 0x%" V8PRIxPTR "\n", val, val); 624 } 625 CHECK(is_int16(val)); 626 } else { 627 if (!is_uint16(val)) { 628 PrintF("val = %" V8PRIdPTR ", 0x%" V8PRIxPTR 629 ", is_unsigned_imm16(val)=%d, kImm16Mask=0x%x\n", 630 val, val, is_uint16(val), kImm16Mask); 631 } 632 CHECK(is_uint16(val)); 633 } 634 emit(instr | rt.code() * B21 | ra.code() * B16 | (kImm16Mask & val)); 635} 636 637void Assembler::xo_form(Instr instr, Register rt, Register ra, Register rb, 638 OEBit o, RCBit r) { 639 emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | o | r); 640} 641 642void Assembler::md_form(Instr instr, Register ra, Register rs, int shift, 643 int maskbit, RCBit r) { 644 int sh0_4 = shift & 0x1F; 645 int sh5 = (shift >> 5) & 0x1; 646 int m0_4 = maskbit & 0x1F; 647 int m5 = (maskbit >> 5) & 0x1; 648 649 emit(instr | rs.code() * B21 | ra.code() * B16 | sh0_4 * B11 | m0_4 * B6 | 650 m5 * B5 | sh5 * B1 | r); 651} 652 653void Assembler::mds_form(Instr instr, Register ra, Register rs, Register rb, 654 int maskbit, RCBit r) { 655 int m0_4 = maskbit & 0x1F; 656 int m5 = (maskbit >> 5) & 0x1; 657 658 emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | m0_4 * B6 | 659 m5 * B5 | r); 660} 661 662// Returns the next free trampoline entry. 663int32_t Assembler::get_trampoline_entry() { 664 int32_t trampoline_entry = kInvalidSlotPos; 665 666 if (!internal_trampoline_exception_) { 667 trampoline_entry = trampoline_.take_slot(); 668 669 if (kInvalidSlotPos == trampoline_entry) { 670 internal_trampoline_exception_ = true; 671 } 672 } 673 return trampoline_entry; 674} 675 676int Assembler::link(Label* L) { 677 int position; 678 if (L->is_bound()) { 679 position = L->pos(); 680 } else { 681 if (L->is_linked()) { 682 position = L->pos(); // L's link 683 } else { 684 // was: target_pos = kEndOfChain; 685 // However, using self to mark the first reference 686 // should avoid most instances of branch offset overflow. See 687 // target_at() for where this is converted back to kEndOfChain. 688 position = pc_offset(); 689 } 690 L->link_to(pc_offset()); 691 } 692 693 return position; 694} 695 696// Branch instructions. 697 698void Assembler::bclr(BOfield bo, int condition_bit, LKBit lk) { 699 emit(EXT1 | bo | condition_bit * B16 | BCLRX | lk); 700} 701 702void Assembler::bcctr(BOfield bo, int condition_bit, LKBit lk) { 703 emit(EXT1 | bo | condition_bit * B16 | BCCTRX | lk); 704} 705 706// Pseudo op - branch to link register 707void Assembler::blr() { bclr(BA, 0, LeaveLK); } 708 709// Pseudo op - branch to count register -- used for "jump" 710void Assembler::bctr() { bcctr(BA, 0, LeaveLK); } 711 712void Assembler::bctrl() { bcctr(BA, 0, SetLK); } 713 714void Assembler::bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk) { 715 int imm16 = branch_offset; 716 CHECK(is_int16(imm16) && (imm16 & (kAAMask | kLKMask)) == 0); 717 emit(BCX | bo | condition_bit * B16 | (imm16 & kImm16Mask) | lk); 718} 719 720void Assembler::b(int branch_offset, LKBit lk) { 721 int imm26 = branch_offset; 722 CHECK(is_int26(imm26) && (imm26 & (kAAMask | kLKMask)) == 0); 723 emit(BX | (imm26 & kImm26Mask) | lk); 724} 725 726void Assembler::xori(Register dst, Register src, const Operand& imm) { 727 d_form(XORI, src, dst, imm.immediate(), false); 728} 729 730void Assembler::xoris(Register ra, Register rs, const Operand& imm) { 731 d_form(XORIS, rs, ra, imm.immediate(), false); 732} 733 734void Assembler::rlwinm(Register ra, Register rs, int sh, int mb, int me, 735 RCBit rc) { 736 sh &= 0x1F; 737 mb &= 0x1F; 738 me &= 0x1F; 739 emit(RLWINMX | rs.code() * B21 | ra.code() * B16 | sh * B11 | mb * B6 | 740 me << 1 | rc); 741} 742 743void Assembler::rlwnm(Register ra, Register rs, Register rb, int mb, int me, 744 RCBit rc) { 745 mb &= 0x1F; 746 me &= 0x1F; 747 emit(RLWNMX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | mb * B6 | 748 me << 1 | rc); 749} 750 751void Assembler::rlwimi(Register ra, Register rs, int sh, int mb, int me, 752 RCBit rc) { 753 sh &= 0x1F; 754 mb &= 0x1F; 755 me &= 0x1F; 756 emit(RLWIMIX | rs.code() * B21 | ra.code() * B16 | sh * B11 | mb * B6 | 757 me << 1 | rc); 758} 759 760void Assembler::slwi(Register dst, Register src, const Operand& val, RCBit rc) { 761 DCHECK((32 > val.immediate()) && (val.immediate() >= 0)); 762 rlwinm(dst, src, val.immediate(), 0, 31 - val.immediate(), rc); 763} 764 765void Assembler::srwi(Register dst, Register src, const Operand& val, RCBit rc) { 766 DCHECK((32 > val.immediate()) && (val.immediate() >= 0)); 767 rlwinm(dst, src, 32 - val.immediate(), val.immediate(), 31, rc); 768} 769 770void Assembler::clrrwi(Register dst, Register src, const Operand& val, 771 RCBit rc) { 772 DCHECK((32 > val.immediate()) && (val.immediate() >= 0)); 773 rlwinm(dst, src, 0, 0, 31 - val.immediate(), rc); 774} 775 776void Assembler::clrlwi(Register dst, Register src, const Operand& val, 777 RCBit rc) { 778 DCHECK((32 > val.immediate()) && (val.immediate() >= 0)); 779 rlwinm(dst, src, 0, val.immediate(), 31, rc); 780} 781 782void Assembler::rotlw(Register ra, Register rs, Register rb, RCBit r) { 783 rlwnm(ra, rs, rb, 0, 31, r); 784} 785 786void Assembler::rotlwi(Register ra, Register rs, int sh, RCBit r) { 787 rlwinm(ra, rs, sh, 0, 31, r); 788} 789 790void Assembler::rotrwi(Register ra, Register rs, int sh, RCBit r) { 791 rlwinm(ra, rs, 32 - sh, 0, 31, r); 792} 793 794void Assembler::subi(Register dst, Register src, const Operand& imm) { 795 addi(dst, src, Operand(-(imm.immediate()))); 796} 797 798void Assembler::addc(Register dst, Register src1, Register src2, OEBit o, 799 RCBit r) { 800 xo_form(EXT2 | ADDCX, dst, src1, src2, o, r); 801} 802 803void Assembler::adde(Register dst, Register src1, Register src2, OEBit o, 804 RCBit r) { 805 xo_form(EXT2 | ADDEX, dst, src1, src2, o, r); 806} 807 808void Assembler::addze(Register dst, Register src1, OEBit o, RCBit r) { 809 // a special xo_form 810 emit(EXT2 | ADDZEX | dst.code() * B21 | src1.code() * B16 | o | r); 811} 812 813void Assembler::sub(Register dst, Register src1, Register src2, OEBit o, 814 RCBit r) { 815 xo_form(EXT2 | SUBFX, dst, src2, src1, o, r); 816} 817 818void Assembler::subc(Register dst, Register src1, Register src2, OEBit o, 819 RCBit r) { 820 xo_form(EXT2 | SUBFCX, dst, src2, src1, o, r); 821} 822 823void Assembler::sube(Register dst, Register src1, Register src2, OEBit o, 824 RCBit r) { 825 xo_form(EXT2 | SUBFEX, dst, src2, src1, o, r); 826} 827 828void Assembler::subfic(Register dst, Register src, const Operand& imm) { 829 d_form(SUBFIC, dst, src, imm.immediate(), true); 830} 831 832void Assembler::add(Register dst, Register src1, Register src2, OEBit o, 833 RCBit r) { 834 xo_form(EXT2 | ADDX, dst, src1, src2, o, r); 835} 836 837// Multiply low word 838void Assembler::mullw(Register dst, Register src1, Register src2, OEBit o, 839 RCBit r) { 840 xo_form(EXT2 | MULLW, dst, src1, src2, o, r); 841} 842 843void Assembler::mulli(Register dst, Register src, const Operand& imm) { 844 d_form(MULLI, dst, src, imm.immediate(), true); 845} 846 847// Multiply hi word 848void Assembler::mulhw(Register dst, Register src1, Register src2, RCBit r) { 849 xo_form(EXT2 | MULHWX, dst, src1, src2, LeaveOE, r); 850} 851 852// Multiply hi word unsigned 853void Assembler::mulhwu(Register dst, Register src1, Register src2, RCBit r) { 854 xo_form(EXT2 | MULHWUX, dst, src1, src2, LeaveOE, r); 855} 856 857// Divide word 858void Assembler::divw(Register dst, Register src1, Register src2, OEBit o, 859 RCBit r) { 860 xo_form(EXT2 | DIVW, dst, src1, src2, o, r); 861} 862 863// Divide word unsigned 864void Assembler::divwu(Register dst, Register src1, Register src2, OEBit o, 865 RCBit r) { 866 xo_form(EXT2 | DIVWU, dst, src1, src2, o, r); 867} 868 869void Assembler::addi(Register dst, Register src, const Operand& imm) { 870 DCHECK(src != r0); // use li instead to show intent 871 d_form(ADDI, dst, src, imm.immediate(), true); 872} 873 874void Assembler::addis(Register dst, Register src, const Operand& imm) { 875 DCHECK(src != r0); // use lis instead to show intent 876 d_form(ADDIS, dst, src, imm.immediate(), true); 877} 878 879void Assembler::addic(Register dst, Register src, const Operand& imm) { 880 d_form(ADDIC, dst, src, imm.immediate(), true); 881} 882 883void Assembler::andi(Register ra, Register rs, const Operand& imm) { 884 d_form(ANDIx, rs, ra, imm.immediate(), false); 885} 886 887void Assembler::andis(Register ra, Register rs, const Operand& imm) { 888 d_form(ANDISx, rs, ra, imm.immediate(), false); 889} 890 891void Assembler::ori(Register ra, Register rs, const Operand& imm) { 892 d_form(ORI, rs, ra, imm.immediate(), false); 893} 894 895void Assembler::oris(Register dst, Register src, const Operand& imm) { 896 d_form(ORIS, src, dst, imm.immediate(), false); 897} 898 899void Assembler::cmpi(Register src1, const Operand& src2, CRegister cr) { 900 intptr_t imm16 = src2.immediate(); 901#if V8_TARGET_ARCH_PPC64 902 int L = 1; 903#else 904 int L = 0; 905#endif 906 DCHECK(is_int16(imm16)); 907 DCHECK(cr.code() >= 0 && cr.code() <= 7); 908 imm16 &= kImm16Mask; 909 emit(CMPI | cr.code() * B23 | L * B21 | src1.code() * B16 | imm16); 910} 911 912void Assembler::cmpli(Register src1, const Operand& src2, CRegister cr) { 913 uintptr_t uimm16 = src2.immediate(); 914#if V8_TARGET_ARCH_PPC64 915 int L = 1; 916#else 917 int L = 0; 918#endif 919 DCHECK(is_uint16(uimm16)); 920 DCHECK(cr.code() >= 0 && cr.code() <= 7); 921 uimm16 &= kImm16Mask; 922 emit(CMPLI | cr.code() * B23 | L * B21 | src1.code() * B16 | uimm16); 923} 924 925void Assembler::cmpwi(Register src1, const Operand& src2, CRegister cr) { 926 intptr_t imm16 = src2.immediate(); 927 int L = 0; 928 int pos = pc_offset(); 929 DCHECK(is_int16(imm16)); 930 DCHECK(cr.code() >= 0 && cr.code() <= 7); 931 imm16 &= kImm16Mask; 932 933 // For cmpwi against 0, save postition and cr for later examination 934 // of potential optimization. 935 if (imm16 == 0 && pos > 0 && last_bound_pos_ != pos) { 936 optimizable_cmpi_pos_ = pos; 937 cmpi_cr_ = cr; 938 } 939 emit(CMPI | cr.code() * B23 | L * B21 | src1.code() * B16 | imm16); 940} 941 942void Assembler::cmplwi(Register src1, const Operand& src2, CRegister cr) { 943 uintptr_t uimm16 = src2.immediate(); 944 int L = 0; 945 DCHECK(is_uint16(uimm16)); 946 DCHECK(cr.code() >= 0 && cr.code() <= 7); 947 uimm16 &= kImm16Mask; 948 emit(CMPLI | cr.code() * B23 | L * B21 | src1.code() * B16 | uimm16); 949} 950 951void Assembler::isel(Register rt, Register ra, Register rb, int cb) { 952 emit(EXT2 | ISEL | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | 953 cb * B6); 954} 955 956// Pseudo op - load immediate 957void Assembler::li(Register dst, const Operand& imm) { 958 d_form(ADDI, dst, r0, imm.immediate(), true); 959} 960 961void Assembler::lis(Register dst, const Operand& imm) { 962 d_form(ADDIS, dst, r0, imm.immediate(), true); 963} 964 965// Pseudo op - move register 966void Assembler::mr(Register dst, Register src) { 967 // actually or(dst, src, src) 968 orx(dst, src, src); 969} 970 971void Assembler::lbz(Register dst, const MemOperand& src) { 972 DCHECK(src.ra_ != r0); 973 d_form(LBZ, dst, src.ra(), src.offset(), true); 974} 975 976void Assembler::lhz(Register dst, const MemOperand& src) { 977 DCHECK(src.ra_ != r0); 978 d_form(LHZ, dst, src.ra(), src.offset(), true); 979} 980 981void Assembler::lwz(Register dst, const MemOperand& src) { 982 DCHECK(src.ra_ != r0); 983 d_form(LWZ, dst, src.ra(), src.offset(), true); 984} 985 986void Assembler::lwzu(Register dst, const MemOperand& src) { 987 DCHECK(src.ra_ != r0); 988 d_form(LWZU, dst, src.ra(), src.offset(), true); 989} 990 991void Assembler::lha(Register dst, const MemOperand& src) { 992 DCHECK(src.ra_ != r0); 993 d_form(LHA, dst, src.ra(), src.offset(), true); 994} 995 996void Assembler::lwa(Register dst, const MemOperand& src) { 997#if V8_TARGET_ARCH_PPC64 998 int offset = src.offset(); 999 DCHECK(src.ra_ != r0); 1000 CHECK(!(offset & 3) && is_int16(offset)); 1001 offset = kImm16Mask & offset; 1002 emit(LD | dst.code() * B21 | src.ra().code() * B16 | offset | 2); 1003#else 1004 lwz(dst, src); 1005#endif 1006} 1007 1008void Assembler::stb(Register dst, const MemOperand& src) { 1009 DCHECK(src.ra_ != r0); 1010 d_form(STB, dst, src.ra(), src.offset(), true); 1011} 1012 1013void Assembler::sth(Register dst, const MemOperand& src) { 1014 DCHECK(src.ra_ != r0); 1015 d_form(STH, dst, src.ra(), src.offset(), true); 1016} 1017 1018void Assembler::stw(Register dst, const MemOperand& src) { 1019 DCHECK(src.ra_ != r0); 1020 d_form(STW, dst, src.ra(), src.offset(), true); 1021} 1022 1023void Assembler::stwu(Register dst, const MemOperand& src) { 1024 DCHECK(src.ra_ != r0); 1025 d_form(STWU, dst, src.ra(), src.offset(), true); 1026} 1027 1028void Assembler::neg(Register rt, Register ra, OEBit o, RCBit r) { 1029 emit(EXT2 | NEGX | rt.code() * B21 | ra.code() * B16 | o | r); 1030} 1031 1032#if V8_TARGET_ARCH_PPC64 1033// 64bit specific instructions 1034void Assembler::ld(Register rd, const MemOperand& src) { 1035 int offset = src.offset(); 1036 DCHECK(src.ra_ != r0); 1037 CHECK(!(offset & 3) && is_int16(offset)); 1038 offset = kImm16Mask & offset; 1039 emit(LD | rd.code() * B21 | src.ra().code() * B16 | offset); 1040} 1041 1042void Assembler::ldu(Register rd, const MemOperand& src) { 1043 int offset = src.offset(); 1044 DCHECK(src.ra_ != r0); 1045 CHECK(!(offset & 3) && is_int16(offset)); 1046 offset = kImm16Mask & offset; 1047 emit(LD | rd.code() * B21 | src.ra().code() * B16 | offset | 1); 1048} 1049 1050void Assembler::std(Register rs, const MemOperand& src) { 1051 int offset = src.offset(); 1052 DCHECK(src.ra_ != r0); 1053 CHECK(!(offset & 3) && is_int16(offset)); 1054 offset = kImm16Mask & offset; 1055 emit(STD | rs.code() * B21 | src.ra().code() * B16 | offset); 1056} 1057 1058void Assembler::stdu(Register rs, const MemOperand& src) { 1059 int offset = src.offset(); 1060 DCHECK(src.ra_ != r0); 1061 CHECK(!(offset & 3) && is_int16(offset)); 1062 offset = kImm16Mask & offset; 1063 emit(STD | rs.code() * B21 | src.ra().code() * B16 | offset | 1); 1064} 1065 1066void Assembler::rldic(Register ra, Register rs, int sh, int mb, RCBit r) { 1067 md_form(EXT5 | RLDIC, ra, rs, sh, mb, r); 1068} 1069 1070void Assembler::rldicl(Register ra, Register rs, int sh, int mb, RCBit r) { 1071 md_form(EXT5 | RLDICL, ra, rs, sh, mb, r); 1072} 1073 1074void Assembler::rldcl(Register ra, Register rs, Register rb, int mb, RCBit r) { 1075 mds_form(EXT5 | RLDCL, ra, rs, rb, mb, r); 1076} 1077 1078void Assembler::rldicr(Register ra, Register rs, int sh, int me, RCBit r) { 1079 md_form(EXT5 | RLDICR, ra, rs, sh, me, r); 1080} 1081 1082void Assembler::sldi(Register dst, Register src, const Operand& val, RCBit rc) { 1083 DCHECK((64 > val.immediate()) && (val.immediate() >= 0)); 1084 rldicr(dst, src, val.immediate(), 63 - val.immediate(), rc); 1085} 1086 1087void Assembler::srdi(Register dst, Register src, const Operand& val, RCBit rc) { 1088 DCHECK((64 > val.immediate()) && (val.immediate() >= 0)); 1089 rldicl(dst, src, 64 - val.immediate(), val.immediate(), rc); 1090} 1091 1092void Assembler::clrrdi(Register dst, Register src, const Operand& val, 1093 RCBit rc) { 1094 DCHECK((64 > val.immediate()) && (val.immediate() >= 0)); 1095 rldicr(dst, src, 0, 63 - val.immediate(), rc); 1096} 1097 1098void Assembler::clrldi(Register dst, Register src, const Operand& val, 1099 RCBit rc) { 1100 DCHECK((64 > val.immediate()) && (val.immediate() >= 0)); 1101 rldicl(dst, src, 0, val.immediate(), rc); 1102} 1103 1104void Assembler::rldimi(Register ra, Register rs, int sh, int mb, RCBit r) { 1105 md_form(EXT5 | RLDIMI, ra, rs, sh, mb, r); 1106} 1107 1108void Assembler::sradi(Register ra, Register rs, int sh, RCBit r) { 1109 int sh0_4 = sh & 0x1F; 1110 int sh5 = (sh >> 5) & 0x1; 1111 1112 emit(EXT2 | SRADIX | rs.code() * B21 | ra.code() * B16 | sh0_4 * B11 | 1113 sh5 * B1 | r); 1114} 1115 1116void Assembler::rotld(Register ra, Register rs, Register rb, RCBit r) { 1117 rldcl(ra, rs, rb, 0, r); 1118} 1119 1120void Assembler::rotldi(Register ra, Register rs, int sh, RCBit r) { 1121 rldicl(ra, rs, sh, 0, r); 1122} 1123 1124void Assembler::rotrdi(Register ra, Register rs, int sh, RCBit r) { 1125 rldicl(ra, rs, 64 - sh, 0, r); 1126} 1127 1128void Assembler::mulld(Register dst, Register src1, Register src2, OEBit o, 1129 RCBit r) { 1130 xo_form(EXT2 | MULLD, dst, src1, src2, o, r); 1131} 1132 1133void Assembler::divd(Register dst, Register src1, Register src2, OEBit o, 1134 RCBit r) { 1135 xo_form(EXT2 | DIVD, dst, src1, src2, o, r); 1136} 1137 1138void Assembler::divdu(Register dst, Register src1, Register src2, OEBit o, 1139 RCBit r) { 1140 xo_form(EXT2 | DIVDU, dst, src1, src2, o, r); 1141} 1142#endif 1143 1144// Prefixed instructions. 1145#define GENERATE_PREFIX_SUFFIX_BITS(immediate, prefix, suffix) \ 1146 CHECK(is_int34(immediate)); \ 1147 int32_t prefix = \ 1148 SIGN_EXT_IMM18((immediate >> 16) & kImm18Mask); /* 18 bits.*/ \ 1149 int16_t suffix = immediate & kImm16Mask; /* 16 bits.*/ \ 1150 DCHECK(is_int18(prefix)); 1151 1152void Assembler::paddi(Register dst, Register src, const Operand& imm) { 1153 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); 1154 DCHECK(src != r0); // use pli instead to show intent. 1155 intptr_t immediate = imm.immediate(); 1156 GENERATE_PREFIX_SUFFIX_BITS(immediate, hi, lo) 1157 BlockTrampolinePoolScope block_trampoline_pool(this); 1158 pload_store_mls(Operand(hi)); 1159 addi(dst, src, Operand(lo)); 1160} 1161 1162void Assembler::pli(Register dst, const Operand& imm) { 1163 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); 1164 intptr_t immediate = imm.immediate(); 1165 GENERATE_PREFIX_SUFFIX_BITS(immediate, hi, lo) 1166 BlockTrampolinePoolScope block_trampoline_pool(this); 1167 pload_store_mls(Operand(hi)); 1168 li(dst, Operand(lo)); 1169} 1170 1171void Assembler::psubi(Register dst, Register src, const Operand& imm) { 1172 paddi(dst, src, Operand(-(imm.immediate()))); 1173} 1174 1175void Assembler::plbz(Register dst, const MemOperand& src) { 1176 DCHECK(src.ra_ != r0); 1177 int64_t offset = src.offset(); 1178 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1179 BlockTrampolinePoolScope block_trampoline_pool(this); 1180 pload_store_mls(Operand(hi)); 1181 lbz(dst, MemOperand(src.ra(), lo)); 1182} 1183 1184void Assembler::plhz(Register dst, const MemOperand& src) { 1185 DCHECK(src.ra_ != r0); 1186 int64_t offset = src.offset(); 1187 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1188 BlockTrampolinePoolScope block_trampoline_pool(this); 1189 pload_store_mls(Operand(hi)); 1190 lhz(dst, MemOperand(src.ra(), lo)); 1191} 1192 1193void Assembler::plha(Register dst, const MemOperand& src) { 1194 DCHECK(src.ra_ != r0); 1195 int64_t offset = src.offset(); 1196 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1197 BlockTrampolinePoolScope block_trampoline_pool(this); 1198 pload_store_mls(Operand(hi)); 1199 lha(dst, MemOperand(src.ra(), lo)); 1200} 1201 1202void Assembler::plwz(Register dst, const MemOperand& src) { 1203 DCHECK(src.ra_ != r0); 1204 int64_t offset = src.offset(); 1205 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1206 BlockTrampolinePoolScope block_trampoline_pool(this); 1207 pload_store_mls(Operand(hi)); 1208 lwz(dst, MemOperand(src.ra(), lo)); 1209} 1210 1211void Assembler::plwa(Register dst, const MemOperand& src) { 1212 DCHECK(src.ra_ != r0); 1213 int64_t offset = src.offset(); 1214 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1215 BlockTrampolinePoolScope block_trampoline_pool(this); 1216 pload_store_8ls(Operand(hi)); 1217 emit(PPLWA | dst.code() * B21 | src.ra().code() * B16 | (lo & kImm16Mask)); 1218} 1219 1220void Assembler::pld(Register dst, const MemOperand& src) { 1221 DCHECK(src.ra_ != r0); 1222 int64_t offset = src.offset(); 1223 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1224 BlockTrampolinePoolScope block_trampoline_pool(this); 1225 pload_store_8ls(Operand(hi)); 1226 emit(PPLD | dst.code() * B21 | src.ra().code() * B16 | (lo & kImm16Mask)); 1227} 1228 1229void Assembler::plfs(DoubleRegister dst, const MemOperand& src) { 1230 DCHECK(src.ra_ != r0); 1231 int64_t offset = src.offset(); 1232 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1233 BlockTrampolinePoolScope block_trampoline_pool(this); 1234 pload_store_mls(Operand(hi)); 1235 lfs(dst, MemOperand(src.ra(), lo)); 1236} 1237 1238void Assembler::plfd(DoubleRegister dst, const MemOperand& src) { 1239 DCHECK(src.ra_ != r0); 1240 int64_t offset = src.offset(); 1241 GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo) 1242 BlockTrampolinePoolScope block_trampoline_pool(this); 1243 pload_store_mls(Operand(hi)); 1244 lfd(dst, MemOperand(src.ra(), lo)); 1245} 1246#undef GENERATE_PREFIX_SUFFIX_BITS 1247 1248int Assembler::instructions_required_for_mov(Register dst, 1249 const Operand& src) const { 1250 bool canOptimize = 1251 !(src.must_output_reloc_info(this) || is_trampoline_pool_blocked()); 1252 if (use_constant_pool_for_mov(dst, src, canOptimize)) { 1253 if (ConstantPoolAccessIsInOverflow()) { 1254 return kMovInstructionsConstantPool + 1; 1255 } 1256 return kMovInstructionsConstantPool; 1257 } 1258 DCHECK(!canOptimize); 1259 return kMovInstructionsNoConstantPool; 1260} 1261 1262bool Assembler::use_constant_pool_for_mov(Register dst, const Operand& src, 1263 bool canOptimize) const { 1264 if (!FLAG_enable_embedded_constant_pool || !is_constant_pool_available()) { 1265 // If there is no constant pool available, we must use a mov 1266 // immediate sequence. 1267 return false; 1268 } 1269 intptr_t value = src.immediate(); 1270#if V8_TARGET_ARCH_PPC64 1271 bool allowOverflow = !((canOptimize && is_int32(value)) || dst == r0); 1272#else 1273 bool allowOverflow = !(canOptimize || dst == r0); 1274#endif 1275 if (canOptimize && 1276 (is_int16(value) || 1277 (CpuFeatures::IsSupported(PPC_10_PLUS) && is_int34(value)))) { 1278 // Prefer a single-instruction load-immediate. 1279 return false; 1280 } 1281 if (!allowOverflow && ConstantPoolAccessIsInOverflow()) { 1282 // Prefer non-relocatable two-instruction bitwise-mov32 over 1283 // overflow sequence. 1284 return false; 1285 } 1286 1287 return true; 1288} 1289 1290void Assembler::EnsureSpaceFor(int space_needed) { 1291 if (buffer_space() <= (kGap + space_needed)) { 1292 GrowBuffer(space_needed); 1293 } 1294} 1295 1296bool Operand::must_output_reloc_info(const Assembler* assembler) const { 1297 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { 1298 if (assembler != nullptr && assembler->predictable_code_size()) return true; 1299 return assembler->options().record_reloc_info_for_serialization; 1300 } else if (RelocInfo::IsNoInfo(rmode_)) { 1301 return false; 1302 } 1303 return true; 1304} 1305 1306// Primarily used for loading constants 1307// This should really move to be in macro-assembler as it 1308// is really a pseudo instruction 1309// Some usages of this intend for a FIXED_SEQUENCE to be used 1310// Todo - break this dependency so we can optimize mov() in general 1311// and only use the generic version when we require a fixed sequence 1312void Assembler::mov(Register dst, const Operand& src) { 1313 intptr_t value; 1314 if (src.IsHeapObjectRequest()) { 1315 RequestHeapObject(src.heap_object_request()); 1316 value = 0; 1317 } else { 1318 value = src.immediate(); 1319 } 1320 bool relocatable = src.must_output_reloc_info(this); 1321 bool canOptimize; 1322 1323 canOptimize = 1324 !(relocatable || 1325 (is_trampoline_pool_blocked() && 1326 (!is_int16(value) || 1327 !(CpuFeatures::IsSupported(PPC_10_PLUS) && is_int34(value))))); 1328 1329 if (!src.IsHeapObjectRequest() && 1330 use_constant_pool_for_mov(dst, src, canOptimize)) { 1331 DCHECK(is_constant_pool_available()); 1332 if (relocatable) { 1333 RecordRelocInfo(src.rmode_); 1334 } 1335 ConstantPoolEntry::Access access = ConstantPoolAddEntry(src.rmode_, value); 1336#if V8_TARGET_ARCH_PPC64 1337 if (access == ConstantPoolEntry::OVERFLOWED) { 1338 addis(dst, kConstantPoolRegister, Operand::Zero()); 1339 ld(dst, MemOperand(dst, 0)); 1340 } else { 1341 ld(dst, MemOperand(kConstantPoolRegister, 0)); 1342 } 1343#else 1344 if (access == ConstantPoolEntry::OVERFLOWED) { 1345 addis(dst, kConstantPoolRegister, Operand::Zero()); 1346 lwz(dst, MemOperand(dst, 0)); 1347 } else { 1348 lwz(dst, MemOperand(kConstantPoolRegister, 0)); 1349 } 1350#endif 1351 return; 1352 } 1353 1354 if (canOptimize) { 1355 if (is_int16(value)) { 1356 li(dst, Operand(value)); 1357 } else if (CpuFeatures::IsSupported(PPC_10_PLUS) && is_int34(value)) { 1358 pli(dst, Operand(value)); 1359 } else { 1360 uint16_t u16; 1361#if V8_TARGET_ARCH_PPC64 1362 if (is_int32(value)) { 1363#endif 1364 lis(dst, Operand(value >> 16)); 1365#if V8_TARGET_ARCH_PPC64 1366 } else { 1367 if (is_int48(value)) { 1368 li(dst, Operand(value >> 32)); 1369 } else { 1370 lis(dst, Operand(value >> 48)); 1371 u16 = ((value >> 32) & 0xFFFF); 1372 if (u16) { 1373 ori(dst, dst, Operand(u16)); 1374 } 1375 } 1376 sldi(dst, dst, Operand(32)); 1377 u16 = ((value >> 16) & 0xFFFF); 1378 if (u16) { 1379 oris(dst, dst, Operand(u16)); 1380 } 1381 } 1382#endif 1383 u16 = (value & 0xFFFF); 1384 if (u16) { 1385 ori(dst, dst, Operand(u16)); 1386 } 1387 } 1388 return; 1389 } 1390 1391 DCHECK(!canOptimize); 1392 if (relocatable) { 1393 RecordRelocInfo(src.rmode_); 1394 } 1395 bitwise_mov(dst, value); 1396} 1397 1398void Assembler::bitwise_mov(Register dst, intptr_t value) { 1399 BlockTrampolinePoolScope block_trampoline_pool(this); 1400#if V8_TARGET_ARCH_PPC64 1401 int32_t hi_32 = static_cast<int32_t>(value >> 32); 1402 int32_t lo_32 = static_cast<int32_t>(value); 1403 int hi_word = static_cast<int>(hi_32 >> 16); 1404 int lo_word = static_cast<int>(hi_32 & 0xFFFF); 1405 lis(dst, Operand(SIGN_EXT_IMM16(hi_word))); 1406 ori(dst, dst, Operand(lo_word)); 1407 sldi(dst, dst, Operand(32)); 1408 hi_word = static_cast<int>(((lo_32 >> 16) & 0xFFFF)); 1409 lo_word = static_cast<int>(lo_32 & 0xFFFF); 1410 oris(dst, dst, Operand(hi_word)); 1411 ori(dst, dst, Operand(lo_word)); 1412#else 1413 int hi_word = static_cast<int>(value >> 16); 1414 int lo_word = static_cast<int>(value & 0xFFFF); 1415 lis(dst, Operand(SIGN_EXT_IMM16(hi_word))); 1416 ori(dst, dst, Operand(lo_word)); 1417#endif 1418} 1419 1420void Assembler::bitwise_mov32(Register dst, int32_t value) { 1421 BlockTrampolinePoolScope block_trampoline_pool(this); 1422 int hi_word = static_cast<int>(value >> 16); 1423 int lo_word = static_cast<int>(value & 0xFFFF); 1424 lis(dst, Operand(SIGN_EXT_IMM16(hi_word))); 1425 ori(dst, dst, Operand(lo_word)); 1426} 1427 1428void Assembler::bitwise_add32(Register dst, Register src, int32_t value) { 1429 BlockTrampolinePoolScope block_trampoline_pool(this); 1430 if (is_int16(value)) { 1431 addi(dst, src, Operand(value)); 1432 nop(); 1433 } else { 1434 int hi_word = static_cast<int>(value >> 16); 1435 int lo_word = static_cast<int>(value & 0xFFFF); 1436 if (lo_word & 0x8000) hi_word++; 1437 addis(dst, src, Operand(SIGN_EXT_IMM16(hi_word))); 1438 addic(dst, dst, Operand(SIGN_EXT_IMM16(lo_word))); 1439 } 1440} 1441 1442void Assembler::patch_wasm_cpi_return_address(Register dst, int pc_offset, 1443 int return_address_offset) { 1444 DCHECK(is_int16(return_address_offset)); 1445 Assembler patching_assembler( 1446 AssemblerOptions{}, 1447 ExternalAssemblerBuffer(buffer_start_ + pc_offset, kInstrSize + kGap)); 1448 patching_assembler.addi(dst, dst, Operand(return_address_offset)); 1449} 1450 1451void Assembler::mov_label_offset(Register dst, Label* label) { 1452 int position = link(label); 1453 if (label->is_bound()) { 1454 // Load the position of the label relative to the generated code object. 1455 mov(dst, Operand(position + Code::kHeaderSize - kHeapObjectTag)); 1456 } else { 1457 // Encode internal reference to unbound label. We use a dummy opcode 1458 // such that it won't collide with any opcode that might appear in the 1459 // label's chain. Encode the destination register in the 2nd instruction. 1460 int link = position - pc_offset(); 1461 DCHECK_EQ(0, link & 3); 1462 link >>= 2; 1463 DCHECK(is_int26(link)); 1464 1465 // When the label is bound, these instructions will be patched 1466 // with a 2 instruction mov sequence that will load the 1467 // destination register with the position of the label from the 1468 // beginning of the code. 1469 // 1470 // target_at extracts the link and target_at_put patches the instructions. 1471 BlockTrampolinePoolScope block_trampoline_pool(this); 1472 emit(kUnboundMovLabelOffsetOpcode | (link & kImm26Mask)); 1473 emit(dst.code()); 1474 } 1475} 1476 1477void Assembler::add_label_offset(Register dst, Register base, Label* label, 1478 int delta) { 1479 int position = link(label); 1480 if (label->is_bound()) { 1481 // dst = base + position + delta 1482 position += delta; 1483 bitwise_add32(dst, base, position); 1484 } else { 1485 // Encode internal reference to unbound label. We use a dummy opcode 1486 // such that it won't collide with any opcode that might appear in the 1487 // label's chain. Encode the operands in the 2nd instruction. 1488 int link = position - pc_offset(); 1489 DCHECK_EQ(0, link & 3); 1490 link >>= 2; 1491 DCHECK(is_int26(link)); 1492 BlockTrampolinePoolScope block_trampoline_pool(this); 1493 1494 emit((is_int22(delta) ? kUnboundAddLabelOffsetOpcode 1495 : kUnboundAddLabelLongOffsetOpcode) | 1496 (link & kImm26Mask)); 1497 emit(dst.code() * B27 | base.code() * B22 | (delta & kImm22Mask)); 1498 1499 if (!is_int22(delta)) { 1500 emit(delta); 1501 } 1502 } 1503} 1504 1505void Assembler::mov_label_addr(Register dst, Label* label) { 1506 CheckBuffer(); 1507 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); 1508 int position = link(label); 1509 if (label->is_bound()) { 1510 // Keep internal references relative until EmitRelocations. 1511 bitwise_mov(dst, position); 1512 } else { 1513 // Encode internal reference to unbound label. We use a dummy opcode 1514 // such that it won't collide with any opcode that might appear in the 1515 // label's chain. Encode the destination register in the 2nd instruction. 1516 int link = position - pc_offset(); 1517 DCHECK_EQ(0, link & 3); 1518 link >>= 2; 1519 DCHECK(is_int26(link)); 1520 1521 // When the label is bound, these instructions will be patched 1522 // with a multi-instruction mov sequence that will load the 1523 // destination register with the address of the label. 1524 // 1525 // target_at extracts the link and target_at_put patches the instructions. 1526 BlockTrampolinePoolScope block_trampoline_pool(this); 1527 emit(kUnboundMovLabelAddrOpcode | (link & kImm26Mask)); 1528 emit(dst.code()); 1529 DCHECK_GE(kMovInstructionsNoConstantPool, 2); 1530 for (int i = 0; i < kMovInstructionsNoConstantPool - 2; i++) nop(); 1531 } 1532} 1533 1534void Assembler::emit_label_addr(Label* label) { 1535 CheckBuffer(); 1536 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); 1537 int position = link(label); 1538 if (label->is_bound()) { 1539 // Keep internal references relative until EmitRelocations. 1540 dp(position); 1541 } else { 1542 // Encode internal reference to unbound label. We use a dummy opcode 1543 // such that it won't collide with any opcode that might appear in the 1544 // label's chain. 1545 int link = position - pc_offset(); 1546 DCHECK_EQ(0, link & 3); 1547 link >>= 2; 1548 DCHECK(is_int26(link)); 1549 1550 // When the label is bound, the instruction(s) will be patched 1551 // as a jump table entry containing the label address. target_at extracts 1552 // the link and target_at_put patches the instruction(s). 1553 BlockTrampolinePoolScope block_trampoline_pool(this); 1554 emit(kUnboundJumpTableEntryOpcode | (link & kImm26Mask)); 1555#if V8_TARGET_ARCH_PPC64 1556 nop(); 1557#endif 1558 } 1559} 1560 1561// Special register instructions 1562void Assembler::crxor(int bt, int ba, int bb) { 1563 emit(EXT1 | CRXOR | bt * B21 | ba * B16 | bb * B11); 1564} 1565 1566void Assembler::creqv(int bt, int ba, int bb) { 1567 emit(EXT1 | CREQV | bt * B21 | ba * B16 | bb * B11); 1568} 1569 1570void Assembler::mflr(Register dst) { 1571 emit(EXT2 | MFSPR | dst.code() * B21 | 256 << 11); // Ignore RC bit 1572} 1573 1574void Assembler::mtlr(Register src) { 1575 emit(EXT2 | MTSPR | src.code() * B21 | 256 << 11); // Ignore RC bit 1576} 1577 1578void Assembler::mtctr(Register src) { 1579 emit(EXT2 | MTSPR | src.code() * B21 | 288 << 11); // Ignore RC bit 1580} 1581 1582void Assembler::mtxer(Register src) { 1583 emit(EXT2 | MTSPR | src.code() * B21 | 32 << 11); 1584} 1585 1586void Assembler::mcrfs(CRegister cr, FPSCRBit bit) { 1587 DCHECK_LT(static_cast<int>(bit), 32); 1588 int bf = cr.code(); 1589 int bfa = bit / CRWIDTH; 1590 emit(EXT4 | MCRFS | bf * B23 | bfa * B18); 1591} 1592 1593void Assembler::mfcr(Register dst) { emit(EXT2 | MFCR | dst.code() * B21); } 1594 1595void Assembler::mtcrf(Register src, uint8_t FXM) { 1596 emit(MTCRF | src.code() * B21 | FXM * B12); 1597} 1598#if V8_TARGET_ARCH_PPC64 1599void Assembler::mffprd(Register dst, DoubleRegister src) { 1600 emit(EXT2 | MFVSRD | src.code() * B21 | dst.code() * B16); 1601} 1602 1603void Assembler::mffprwz(Register dst, DoubleRegister src) { 1604 emit(EXT2 | MFVSRWZ | src.code() * B21 | dst.code() * B16); 1605} 1606 1607void Assembler::mtfprd(DoubleRegister dst, Register src) { 1608 emit(EXT2 | MTVSRD | dst.code() * B21 | src.code() * B16); 1609} 1610 1611void Assembler::mtfprwz(DoubleRegister dst, Register src) { 1612 emit(EXT2 | MTVSRWZ | dst.code() * B21 | src.code() * B16); 1613} 1614 1615void Assembler::mtfprwa(DoubleRegister dst, Register src) { 1616 emit(EXT2 | MTVSRWA | dst.code() * B21 | src.code() * B16); 1617} 1618#endif 1619 1620// Exception-generating instructions and debugging support. 1621// Stops with a non-negative code less than kNumOfWatchedStops support 1622// enabling/disabling and a counter feature. See simulator-ppc.h . 1623void Assembler::stop(Condition cond, int32_t code, CRegister cr) { 1624 if (cond != al) { 1625 Label skip; 1626 b(NegateCondition(cond), &skip, cr); 1627 bkpt(0); 1628 bind(&skip); 1629 } else { 1630 bkpt(0); 1631 } 1632} 1633 1634void Assembler::bkpt(uint32_t imm16) { emit(0x7D821008); } 1635 1636void Assembler::dcbf(Register ra, Register rb) { 1637 emit(EXT2 | DCBF | ra.code() * B16 | rb.code() * B11); 1638} 1639 1640void Assembler::sync() { emit(EXT2 | SYNC); } 1641 1642void Assembler::lwsync() { emit(EXT2 | SYNC | 1 * B21); } 1643 1644void Assembler::icbi(Register ra, Register rb) { 1645 emit(EXT2 | ICBI | ra.code() * B16 | rb.code() * B11); 1646} 1647 1648void Assembler::isync() { emit(EXT1 | ISYNC); } 1649 1650// Floating point support 1651 1652void Assembler::lfd(const DoubleRegister frt, const MemOperand& src) { 1653 int offset = src.offset(); 1654 Register ra = src.ra(); 1655 DCHECK(ra != r0); 1656 CHECK(is_int16(offset)); 1657 int imm16 = offset & kImm16Mask; 1658 // could be x_form instruction with some casting magic 1659 emit(LFD | frt.code() * B21 | ra.code() * B16 | imm16); 1660} 1661 1662void Assembler::lfdu(const DoubleRegister frt, const MemOperand& src) { 1663 int offset = src.offset(); 1664 Register ra = src.ra(); 1665 DCHECK(ra != r0); 1666 CHECK(is_int16(offset)); 1667 int imm16 = offset & kImm16Mask; 1668 // could be x_form instruction with some casting magic 1669 emit(LFDU | frt.code() * B21 | ra.code() * B16 | imm16); 1670} 1671 1672void Assembler::lfs(const DoubleRegister frt, const MemOperand& src) { 1673 int offset = src.offset(); 1674 Register ra = src.ra(); 1675 CHECK(is_int16(offset)); 1676 DCHECK(ra != r0); 1677 int imm16 = offset & kImm16Mask; 1678 // could be x_form instruction with some casting magic 1679 emit(LFS | frt.code() * B21 | ra.code() * B16 | imm16); 1680} 1681 1682void Assembler::lfsu(const DoubleRegister frt, const MemOperand& src) { 1683 int offset = src.offset(); 1684 Register ra = src.ra(); 1685 CHECK(is_int16(offset)); 1686 DCHECK(ra != r0); 1687 int imm16 = offset & kImm16Mask; 1688 // could be x_form instruction with some casting magic 1689 emit(LFSU | frt.code() * B21 | ra.code() * B16 | imm16); 1690} 1691 1692void Assembler::stfd(const DoubleRegister frs, const MemOperand& src) { 1693 int offset = src.offset(); 1694 Register ra = src.ra(); 1695 CHECK(is_int16(offset)); 1696 DCHECK(ra != r0); 1697 int imm16 = offset & kImm16Mask; 1698 // could be x_form instruction with some casting magic 1699 emit(STFD | frs.code() * B21 | ra.code() * B16 | imm16); 1700} 1701 1702void Assembler::stfdu(const DoubleRegister frs, const MemOperand& src) { 1703 int offset = src.offset(); 1704 Register ra = src.ra(); 1705 CHECK(is_int16(offset)); 1706 DCHECK(ra != r0); 1707 int imm16 = offset & kImm16Mask; 1708 // could be x_form instruction with some casting magic 1709 emit(STFDU | frs.code() * B21 | ra.code() * B16 | imm16); 1710} 1711 1712void Assembler::stfs(const DoubleRegister frs, const MemOperand& src) { 1713 int offset = src.offset(); 1714 Register ra = src.ra(); 1715 CHECK(is_int16(offset)); 1716 DCHECK(ra != r0); 1717 int imm16 = offset & kImm16Mask; 1718 // could be x_form instruction with some casting magic 1719 emit(STFS | frs.code() * B21 | ra.code() * B16 | imm16); 1720} 1721 1722void Assembler::stfsu(const DoubleRegister frs, const MemOperand& src) { 1723 int offset = src.offset(); 1724 Register ra = src.ra(); 1725 CHECK(is_int16(offset)); 1726 DCHECK(ra != r0); 1727 int imm16 = offset & kImm16Mask; 1728 // could be x_form instruction with some casting magic 1729 emit(STFSU | frs.code() * B21 | ra.code() * B16 | imm16); 1730} 1731 1732void Assembler::fsub(const DoubleRegister frt, const DoubleRegister fra, 1733 const DoubleRegister frb, RCBit rc) { 1734 a_form(EXT4 | FSUB, frt, fra, frb, rc); 1735} 1736 1737void Assembler::fadd(const DoubleRegister frt, const DoubleRegister fra, 1738 const DoubleRegister frb, RCBit rc) { 1739 a_form(EXT4 | FADD, frt, fra, frb, rc); 1740} 1741 1742void Assembler::fmul(const DoubleRegister frt, const DoubleRegister fra, 1743 const DoubleRegister frc, RCBit rc) { 1744 emit(EXT4 | FMUL | frt.code() * B21 | fra.code() * B16 | frc.code() * B6 | 1745 rc); 1746} 1747 1748void Assembler::fcpsgn(const DoubleRegister frt, const DoubleRegister fra, 1749 const DoubleRegister frb, RCBit rc) { 1750 emit(EXT4 | FCPSGN | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | 1751 rc); 1752} 1753 1754void Assembler::fdiv(const DoubleRegister frt, const DoubleRegister fra, 1755 const DoubleRegister frb, RCBit rc) { 1756 a_form(EXT4 | FDIV, frt, fra, frb, rc); 1757} 1758 1759void Assembler::fcmpu(const DoubleRegister fra, const DoubleRegister frb, 1760 CRegister cr) { 1761 DCHECK(cr.code() >= 0 && cr.code() <= 7); 1762 emit(EXT4 | FCMPU | cr.code() * B23 | fra.code() * B16 | frb.code() * B11); 1763} 1764 1765void Assembler::fmr(const DoubleRegister frt, const DoubleRegister frb, 1766 RCBit rc) { 1767 emit(EXT4 | FMR | frt.code() * B21 | frb.code() * B11 | rc); 1768} 1769 1770void Assembler::fctiwz(const DoubleRegister frt, const DoubleRegister frb) { 1771 emit(EXT4 | FCTIWZ | frt.code() * B21 | frb.code() * B11); 1772} 1773 1774void Assembler::fctiw(const DoubleRegister frt, const DoubleRegister frb) { 1775 emit(EXT4 | FCTIW | frt.code() * B21 | frb.code() * B11); 1776} 1777 1778void Assembler::fctiwuz(const DoubleRegister frt, const DoubleRegister frb) { 1779 emit(EXT4 | FCTIWUZ | frt.code() * B21 | frb.code() * B11); 1780} 1781 1782void Assembler::frin(const DoubleRegister frt, const DoubleRegister frb, 1783 RCBit rc) { 1784 emit(EXT4 | FRIN | frt.code() * B21 | frb.code() * B11 | rc); 1785} 1786 1787void Assembler::friz(const DoubleRegister frt, const DoubleRegister frb, 1788 RCBit rc) { 1789 emit(EXT4 | FRIZ | frt.code() * B21 | frb.code() * B11 | rc); 1790} 1791 1792void Assembler::frip(const DoubleRegister frt, const DoubleRegister frb, 1793 RCBit rc) { 1794 emit(EXT4 | FRIP | frt.code() * B21 | frb.code() * B11 | rc); 1795} 1796 1797void Assembler::frim(const DoubleRegister frt, const DoubleRegister frb, 1798 RCBit rc) { 1799 emit(EXT4 | FRIM | frt.code() * B21 | frb.code() * B11 | rc); 1800} 1801 1802void Assembler::frsp(const DoubleRegister frt, const DoubleRegister frb, 1803 RCBit rc) { 1804 emit(EXT4 | FRSP | frt.code() * B21 | frb.code() * B11 | rc); 1805} 1806 1807void Assembler::fcfid(const DoubleRegister frt, const DoubleRegister frb, 1808 RCBit rc) { 1809 emit(EXT4 | FCFID | frt.code() * B21 | frb.code() * B11 | rc); 1810} 1811 1812void Assembler::fcfidu(const DoubleRegister frt, const DoubleRegister frb, 1813 RCBit rc) { 1814 emit(EXT4 | FCFIDU | frt.code() * B21 | frb.code() * B11 | rc); 1815} 1816 1817void Assembler::fcfidus(const DoubleRegister frt, const DoubleRegister frb, 1818 RCBit rc) { 1819 emit(EXT3 | FCFIDUS | frt.code() * B21 | frb.code() * B11 | rc); 1820} 1821 1822void Assembler::fcfids(const DoubleRegister frt, const DoubleRegister frb, 1823 RCBit rc) { 1824 emit(EXT3 | FCFIDS | frt.code() * B21 | frb.code() * B11 | rc); 1825} 1826 1827void Assembler::fctid(const DoubleRegister frt, const DoubleRegister frb, 1828 RCBit rc) { 1829 emit(EXT4 | FCTID | frt.code() * B21 | frb.code() * B11 | rc); 1830} 1831 1832void Assembler::fctidz(const DoubleRegister frt, const DoubleRegister frb, 1833 RCBit rc) { 1834 emit(EXT4 | FCTIDZ | frt.code() * B21 | frb.code() * B11 | rc); 1835} 1836 1837void Assembler::fctidu(const DoubleRegister frt, const DoubleRegister frb, 1838 RCBit rc) { 1839 emit(EXT4 | FCTIDU | frt.code() * B21 | frb.code() * B11 | rc); 1840} 1841 1842void Assembler::fctiduz(const DoubleRegister frt, const DoubleRegister frb, 1843 RCBit rc) { 1844 emit(EXT4 | FCTIDUZ | frt.code() * B21 | frb.code() * B11 | rc); 1845} 1846 1847void Assembler::fsel(const DoubleRegister frt, const DoubleRegister fra, 1848 const DoubleRegister frc, const DoubleRegister frb, 1849 RCBit rc) { 1850 emit(EXT4 | FSEL | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | 1851 frc.code() * B6 | rc); 1852} 1853 1854void Assembler::fneg(const DoubleRegister frt, const DoubleRegister frb, 1855 RCBit rc) { 1856 emit(EXT4 | FNEG | frt.code() * B21 | frb.code() * B11 | rc); 1857} 1858 1859void Assembler::mtfsb0(FPSCRBit bit, RCBit rc) { 1860 DCHECK_LT(static_cast<int>(bit), 32); 1861 int bt = bit; 1862 emit(EXT4 | MTFSB0 | bt * B21 | rc); 1863} 1864 1865void Assembler::mtfsb1(FPSCRBit bit, RCBit rc) { 1866 DCHECK_LT(static_cast<int>(bit), 32); 1867 int bt = bit; 1868 emit(EXT4 | MTFSB1 | bt * B21 | rc); 1869} 1870 1871void Assembler::mtfsfi(int bf, int immediate, RCBit rc) { 1872 emit(EXT4 | MTFSFI | bf * B23 | immediate * B12 | rc); 1873} 1874 1875void Assembler::mffs(const DoubleRegister frt, RCBit rc) { 1876 emit(EXT4 | MFFS | frt.code() * B21 | rc); 1877} 1878 1879void Assembler::mtfsf(const DoubleRegister frb, bool L, int FLM, bool W, 1880 RCBit rc) { 1881 emit(EXT4 | MTFSF | frb.code() * B11 | W * B16 | FLM * B17 | L * B25 | rc); 1882} 1883 1884void Assembler::fsqrt(const DoubleRegister frt, const DoubleRegister frb, 1885 RCBit rc) { 1886 emit(EXT4 | FSQRT | frt.code() * B21 | frb.code() * B11 | rc); 1887} 1888 1889void Assembler::fabs(const DoubleRegister frt, const DoubleRegister frb, 1890 RCBit rc) { 1891 emit(EXT4 | FABS | frt.code() * B21 | frb.code() * B11 | rc); 1892} 1893 1894void Assembler::fmadd(const DoubleRegister frt, const DoubleRegister fra, 1895 const DoubleRegister frc, const DoubleRegister frb, 1896 RCBit rc) { 1897 emit(EXT4 | FMADD | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | 1898 frc.code() * B6 | rc); 1899} 1900 1901void Assembler::fmsub(const DoubleRegister frt, const DoubleRegister fra, 1902 const DoubleRegister frc, const DoubleRegister frb, 1903 RCBit rc) { 1904 emit(EXT4 | FMSUB | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | 1905 frc.code() * B6 | rc); 1906} 1907 1908// Vector instructions 1909void Assembler::mfvsrd(const Register ra, const Simd128Register rs) { 1910 int SX = 1; 1911 emit(MFVSRD | rs.code() * B21 | ra.code() * B16 | SX); 1912} 1913 1914void Assembler::mfvsrwz(const Register ra, const Simd128Register rs) { 1915 int SX = 1; 1916 emit(MFVSRWZ | rs.code() * B21 | ra.code() * B16 | SX); 1917} 1918 1919void Assembler::mtvsrd(const Simd128Register rt, const Register ra) { 1920 int TX = 1; 1921 emit(MTVSRD | rt.code() * B21 | ra.code() * B16 | TX); 1922} 1923 1924void Assembler::mtvsrdd(const Simd128Register rt, const Register ra, 1925 const Register rb) { 1926 int TX = 1; 1927 emit(MTVSRDD | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | TX); 1928} 1929 1930void Assembler::lxvd(const Simd128Register rt, const MemOperand& src) { 1931 CHECK(src.rb().is_valid()); 1932 int TX = 1; 1933 emit(LXVD | rt.code() * B21 | src.ra().code() * B16 | src.rb().code() * B11 | 1934 TX); 1935} 1936 1937void Assembler::lxvx(const Simd128Register rt, const MemOperand& src) { 1938 CHECK(src.rb().is_valid()); 1939 int TX = 1; 1940 emit(LXVX | rt.code() * B21 | src.ra().code() * B16 | src.rb().code() * B11 | 1941 TX); 1942} 1943 1944void Assembler::lxsdx(const Simd128Register rt, const MemOperand& src) { 1945 CHECK(src.rb().is_valid()); 1946 int TX = 1; 1947 emit(LXSDX | rt.code() * B21 | src.ra().code() * B16 | src.rb().code() * B11 | 1948 TX); 1949} 1950 1951void Assembler::lxsibzx(const Simd128Register rt, const MemOperand& src) { 1952 CHECK(src.rb().is_valid()); 1953 int TX = 1; 1954 emit(LXSIBZX | rt.code() * B21 | src.ra().code() * B16 | 1955 src.rb().code() * B11 | TX); 1956} 1957 1958void Assembler::lxsihzx(const Simd128Register rt, const MemOperand& src) { 1959 CHECK(src.rb().is_valid()); 1960 int TX = 1; 1961 emit(LXSIHZX | rt.code() * B21 | src.ra().code() * B16 | 1962 src.rb().code() * B11 | TX); 1963} 1964 1965void Assembler::lxsiwzx(const Simd128Register rt, const MemOperand& src) { 1966 CHECK(src.rb().is_valid()); 1967 int TX = 1; 1968 emit(LXSIWZX | rt.code() * B21 | src.ra().code() * B16 | 1969 src.rb().code() * B11 | TX); 1970} 1971 1972void Assembler::stxsdx(const Simd128Register rs, const MemOperand& dst) { 1973 CHECK(dst.rb().is_valid()); 1974 int SX = 1; 1975 emit(STXSDX | rs.code() * B21 | dst.ra().code() * B16 | 1976 dst.rb().code() * B11 | SX); 1977} 1978 1979void Assembler::stxsibx(const Simd128Register rs, const MemOperand& dst) { 1980 CHECK(dst.rb().is_valid()); 1981 int SX = 1; 1982 emit(STXSIBX | rs.code() * B21 | dst.ra().code() * B16 | 1983 dst.rb().code() * B11 | SX); 1984} 1985 1986void Assembler::stxsihx(const Simd128Register rs, const MemOperand& dst) { 1987 CHECK(dst.rb().is_valid()); 1988 int SX = 1; 1989 emit(STXSIHX | rs.code() * B21 | dst.ra().code() * B16 | 1990 dst.rb().code() * B11 | SX); 1991} 1992 1993void Assembler::stxsiwx(const Simd128Register rs, const MemOperand& dst) { 1994 CHECK(dst.rb().is_valid()); 1995 int SX = 1; 1996 emit(STXSIWX | rs.code() * B21 | dst.ra().code() * B16 | 1997 dst.rb().code() * B11 | SX); 1998} 1999 2000void Assembler::stxvd(const Simd128Register rt, const MemOperand& dst) { 2001 CHECK(dst.rb().is_valid()); 2002 int SX = 1; 2003 emit(STXVD | rt.code() * B21 | dst.ra().code() * B16 | dst.rb().code() * B11 | 2004 SX); 2005} 2006 2007void Assembler::stxvx(const Simd128Register rt, const MemOperand& dst) { 2008 CHECK(dst.rb().is_valid()); 2009 int SX = 1; 2010 emit(STXVX | rt.code() * B21 | dst.ra().code() * B16 | dst.rb().code() * B11 | 2011 SX); 2012} 2013 2014void Assembler::xxspltib(const Simd128Register rt, const Operand& imm) { 2015 int TX = 1; 2016 CHECK(is_uint8(imm.immediate())); 2017 emit(XXSPLTIB | (rt.code() & 0x1F) * B21 | (imm.immediate() & 0xFF) * B11 | 2018 TX); 2019} 2020 2021// Pseudo instructions. 2022void Assembler::nop(int type) { 2023 Register reg = r0; 2024 switch (type) { 2025 case NON_MARKING_NOP: 2026 reg = r0; 2027 break; 2028 case GROUP_ENDING_NOP: 2029 reg = r2; 2030 break; 2031 case DEBUG_BREAK_NOP: 2032 reg = r3; 2033 break; 2034 default: 2035 UNIMPLEMENTED(); 2036 } 2037 2038 ori(reg, reg, Operand::Zero()); 2039} 2040 2041bool Assembler::IsNop(Instr instr, int type) { 2042 int reg = 0; 2043 switch (type) { 2044 case NON_MARKING_NOP: 2045 reg = 0; 2046 break; 2047 case GROUP_ENDING_NOP: 2048 reg = 2; 2049 break; 2050 case DEBUG_BREAK_NOP: 2051 reg = 3; 2052 break; 2053 default: 2054 UNIMPLEMENTED(); 2055 } 2056 return instr == (ORI | reg * B21 | reg * B16); 2057} 2058 2059void Assembler::GrowBuffer(int needed) { 2060 DCHECK_EQ(buffer_start_, buffer_->start()); 2061 2062 // Compute new buffer size. 2063 int old_size = buffer_->size(); 2064 int new_size = std::min(2 * old_size, old_size + 1 * MB); 2065 int space = buffer_space() + (new_size - old_size); 2066 new_size += (space < needed) ? needed - space : 0; 2067 2068 // Some internal data structures overflow for very large buffers, 2069 // they must ensure that kMaximalBufferSize is not too large. 2070 if (new_size > kMaximalBufferSize) { 2071 V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer"); 2072 } 2073 2074 // Set up new buffer. 2075 std::unique_ptr<AssemblerBuffer> new_buffer = buffer_->Grow(new_size); 2076 DCHECK_EQ(new_size, new_buffer->size()); 2077 byte* new_start = new_buffer->start(); 2078 2079 // Copy the data. 2080 intptr_t pc_delta = new_start - buffer_start_; 2081 intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size); 2082 size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos(); 2083 MemMove(new_start, buffer_start_, pc_offset()); 2084 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), 2085 reloc_size); 2086 2087 // Switch buffers. 2088 buffer_ = std::move(new_buffer); 2089 buffer_start_ = new_start; 2090 pc_ += pc_delta; 2091 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 2092 reloc_info_writer.last_pc() + pc_delta); 2093 2094 // None of our relocation types are pc relative pointing outside the code 2095 // buffer nor pc absolute pointing inside the code buffer, so there is no need 2096 // to relocate any emitted relocation entries. 2097} 2098 2099void Assembler::db(uint8_t data) { 2100 CheckBuffer(); 2101 *reinterpret_cast<uint8_t*>(pc_) = data; 2102 pc_ += sizeof(uint8_t); 2103} 2104 2105void Assembler::dd(uint32_t data, RelocInfo::Mode rmode) { 2106 CheckBuffer(); 2107 if (!RelocInfo::IsNoInfo(rmode)) { 2108 DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) || 2109 RelocInfo::IsLiteralConstant(rmode)); 2110 RecordRelocInfo(rmode); 2111 } 2112 *reinterpret_cast<uint32_t*>(pc_) = data; 2113 pc_ += sizeof(uint32_t); 2114} 2115 2116void Assembler::dq(uint64_t value, RelocInfo::Mode rmode) { 2117 CheckBuffer(); 2118 if (!RelocInfo::IsNoInfo(rmode)) { 2119 DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) || 2120 RelocInfo::IsLiteralConstant(rmode)); 2121 RecordRelocInfo(rmode); 2122 } 2123 *reinterpret_cast<uint64_t*>(pc_) = value; 2124 pc_ += sizeof(uint64_t); 2125} 2126 2127void Assembler::dp(uintptr_t data, RelocInfo::Mode rmode) { 2128 CheckBuffer(); 2129 if (!RelocInfo::IsNoInfo(rmode)) { 2130 DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) || 2131 RelocInfo::IsLiteralConstant(rmode)); 2132 RecordRelocInfo(rmode); 2133 } 2134 *reinterpret_cast<uintptr_t*>(pc_) = data; 2135 pc_ += sizeof(uintptr_t); 2136} 2137 2138void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 2139 if (!ShouldRecordRelocInfo(rmode)) return; 2140 DeferredRelocInfo rinfo(pc_offset(), rmode, data); 2141 relocations_.push_back(rinfo); 2142} 2143 2144void Assembler::EmitRelocations() { 2145 EnsureSpaceFor(relocations_.size() * kMaxRelocSize); 2146 2147 for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin(); 2148 it != relocations_.end(); it++) { 2149 RelocInfo::Mode rmode = it->rmode(); 2150 Address pc = reinterpret_cast<Address>(buffer_start_) + it->position(); 2151 RelocInfo rinfo(pc, rmode, it->data(), Code()); 2152 2153 // Fix up internal references now that they are guaranteed to be bound. 2154 if (RelocInfo::IsInternalReference(rmode)) { 2155 // Jump table entry 2156 intptr_t pos = static_cast<intptr_t>(Memory<Address>(pc)); 2157 Memory<Address>(pc) = reinterpret_cast<Address>(buffer_start_) + pos; 2158 } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) { 2159 // mov sequence 2160 intptr_t pos = static_cast<intptr_t>(target_address_at(pc, kNullAddress)); 2161 set_target_address_at(pc, 0, 2162 reinterpret_cast<Address>(buffer_start_) + pos, 2163 SKIP_ICACHE_FLUSH); 2164 } 2165 2166 reloc_info_writer.Write(&rinfo); 2167 } 2168} 2169 2170void Assembler::BlockTrampolinePoolFor(int instructions) { 2171 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); 2172} 2173 2174void Assembler::CheckTrampolinePool() { 2175 // Some small sequences of instructions must not be broken up by the 2176 // insertion of a trampoline pool; such sequences are protected by setting 2177 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, 2178 // which are both checked here. Also, recursive calls to CheckTrampolinePool 2179 // are blocked by trampoline_pool_blocked_nesting_. 2180 if (trampoline_pool_blocked_nesting_ > 0) return; 2181 if (pc_offset() < no_trampoline_pool_before_) { 2182 next_trampoline_check_ = no_trampoline_pool_before_; 2183 return; 2184 } 2185 2186 DCHECK(!trampoline_emitted_); 2187 if (tracked_branch_count_ > 0) { 2188 int size = tracked_branch_count_ * kInstrSize; 2189 2190 // As we are only going to emit trampoline once, we need to prevent any 2191 // further emission. 2192 trampoline_emitted_ = true; 2193 next_trampoline_check_ = kMaxInt; 2194 2195 // First we emit jump, then we emit trampoline pool. 2196 b(size + kInstrSize, LeaveLK); 2197 for (int i = size; i > 0; i -= kInstrSize) { 2198 b(i, LeaveLK); 2199 } 2200 2201 trampoline_ = Trampoline(pc_offset() - size, tracked_branch_count_); 2202 } 2203} 2204 2205PatchingAssembler::PatchingAssembler(const AssemblerOptions& options, 2206 byte* address, int instructions) 2207 : Assembler(options, ExternalAssemblerBuffer( 2208 address, instructions * kInstrSize + kGap)) { 2209 DCHECK_EQ(reloc_info_writer.pos(), buffer_start_ + buffer_->size()); 2210} 2211 2212PatchingAssembler::~PatchingAssembler() { 2213 // Check that the code was patched as expected. 2214 DCHECK_EQ(pc_, buffer_start_ + buffer_->size() - kGap); 2215 DCHECK_EQ(reloc_info_writer.pos(), buffer_start_ + buffer_->size()); 2216} 2217 2218UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler) 2219 : assembler_(assembler), 2220 old_available_(*assembler->GetScratchRegisterList()) {} 2221 2222UseScratchRegisterScope::~UseScratchRegisterScope() { 2223 *assembler_->GetScratchRegisterList() = old_available_; 2224} 2225 2226Register UseScratchRegisterScope::Acquire() { 2227 RegList* available = assembler_->GetScratchRegisterList(); 2228 DCHECK_NOT_NULL(available); 2229 return available->PopFirst(); 2230} 2231 2232} // namespace internal 2233} // namespace v8 2234 2235#endif // V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 2236