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 2011 the V8 project authors. All rights reserved. 36 37#include "v8.h" 38 39#if defined(V8_TARGET_ARCH_ARM) 40 41#include "arm/assembler-arm-inl.h" 42#include "serialize.h" 43 44namespace v8 { 45namespace internal { 46 47#ifdef DEBUG 48bool CpuFeatures::initialized_ = false; 49#endif 50unsigned CpuFeatures::supported_ = 0; 51unsigned CpuFeatures::found_by_runtime_probing_ = 0; 52 53 54// Get the CPU features enabled by the build. For cross compilation the 55// preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP_INSTRUCTIONS 56// can be defined to enable ARMv7 and VFPv3 instructions when building the 57// snapshot. 58static uint64_t CpuFeaturesImpliedByCompiler() { 59 uint64_t answer = 0; 60#ifdef CAN_USE_ARMV7_INSTRUCTIONS 61 answer |= 1u << ARMv7; 62#endif // def CAN_USE_ARMV7_INSTRUCTIONS 63#ifdef CAN_USE_VFP_INSTRUCTIONS 64 answer |= 1u << VFP3 | 1u << ARMv7; 65#endif // def CAN_USE_VFP_INSTRUCTIONS 66 67#ifdef __arm__ 68 // If the compiler is allowed to use VFP then we can use VFP too in our code 69 // generation even when generating snapshots. ARMv7 and hardware floating 70 // point support implies VFPv3, see ARM DDI 0406B, page A1-6. 71#if defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) \ 72 && !defined(__SOFTFP__) 73 answer |= 1u << VFP3 | 1u << ARMv7; 74#endif // defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) 75 // && !defined(__SOFTFP__) 76#endif // def __arm__ 77 78 return answer; 79} 80 81 82void CpuFeatures::Probe() { 83 unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() | 84 CpuFeaturesImpliedByCompiler()); 85 ASSERT(supported_ == 0 || supported_ == standard_features); 86#ifdef DEBUG 87 initialized_ = true; 88#endif 89 90 // Get the features implied by the OS and the compiler settings. This is the 91 // minimal set of features which is also alowed for generated code in the 92 // snapshot. 93 supported_ |= standard_features; 94 95 if (Serializer::enabled()) { 96 // No probing for features if we might serialize (generate snapshot). 97 return; 98 } 99 100#ifndef __arm__ 101 // For the simulator=arm build, use VFP when FLAG_enable_vfp3 is 102 // enabled. VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6. 103 if (FLAG_enable_vfp3) { 104 supported_ |= 1u << VFP3 | 1u << ARMv7; 105 } 106 // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled 107 if (FLAG_enable_armv7) { 108 supported_ |= 1u << ARMv7; 109 } 110#else // def __arm__ 111 // Probe for additional features not already known to be available. 112 if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) { 113 // This implementation also sets the VFP flags if runtime 114 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI 115 // 0406B, page A1-6. 116 supported_ |= 1u << VFP3 | 1u << ARMv7; 117 found_by_runtime_probing_ |= 1u << VFP3 | 1u << ARMv7; 118 } 119 120 if (!IsSupported(ARMv7) && OS::ArmCpuHasFeature(ARMv7)) { 121 supported_ |= 1u << ARMv7; 122 found_by_runtime_probing_ |= 1u << ARMv7; 123 } 124#endif 125} 126 127 128// ----------------------------------------------------------------------------- 129// Implementation of RelocInfo 130 131const int RelocInfo::kApplyMask = 0; 132 133 134bool RelocInfo::IsCodedSpecially() { 135 // The deserializer needs to know whether a pointer is specially coded. Being 136 // specially coded on ARM means that it is a movw/movt instruction. We don't 137 // generate those yet. 138 return false; 139} 140 141 142void RelocInfo::PatchCode(byte* instructions, int instruction_count) { 143 // Patch the code at the current address with the supplied instructions. 144 Instr* pc = reinterpret_cast<Instr*>(pc_); 145 Instr* instr = reinterpret_cast<Instr*>(instructions); 146 for (int i = 0; i < instruction_count; i++) { 147 *(pc + i) = *(instr + i); 148 } 149 150 // Indicate that code has changed. 151 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize); 152} 153 154 155// Patch the code at the current PC with a call to the target address. 156// Additional guard instructions can be added if required. 157void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { 158 // Patch the code at the current address with a call to the target. 159 UNIMPLEMENTED(); 160} 161 162 163// ----------------------------------------------------------------------------- 164// Implementation of Operand and MemOperand 165// See assembler-arm-inl.h for inlined constructors 166 167Operand::Operand(Handle<Object> handle) { 168 rm_ = no_reg; 169 // Verify all Objects referred by code are NOT in new space. 170 Object* obj = *handle; 171 ASSERT(!HEAP->InNewSpace(obj)); 172 if (obj->IsHeapObject()) { 173 imm32_ = reinterpret_cast<intptr_t>(handle.location()); 174 rmode_ = RelocInfo::EMBEDDED_OBJECT; 175 } else { 176 // no relocation needed 177 imm32_ = reinterpret_cast<intptr_t>(obj); 178 rmode_ = RelocInfo::NONE; 179 } 180} 181 182 183Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) { 184 ASSERT(is_uint5(shift_imm)); 185 ASSERT(shift_op != ROR || shift_imm != 0); // use RRX if you mean it 186 rm_ = rm; 187 rs_ = no_reg; 188 shift_op_ = shift_op; 189 shift_imm_ = shift_imm & 31; 190 if (shift_op == RRX) { 191 // encoded as ROR with shift_imm == 0 192 ASSERT(shift_imm == 0); 193 shift_op_ = ROR; 194 shift_imm_ = 0; 195 } 196} 197 198 199Operand::Operand(Register rm, ShiftOp shift_op, Register rs) { 200 ASSERT(shift_op != RRX); 201 rm_ = rm; 202 rs_ = no_reg; 203 shift_op_ = shift_op; 204 rs_ = rs; 205} 206 207 208MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) { 209 rn_ = rn; 210 rm_ = no_reg; 211 offset_ = offset; 212 am_ = am; 213} 214 215MemOperand::MemOperand(Register rn, Register rm, AddrMode am) { 216 rn_ = rn; 217 rm_ = rm; 218 shift_op_ = LSL; 219 shift_imm_ = 0; 220 am_ = am; 221} 222 223 224MemOperand::MemOperand(Register rn, Register rm, 225 ShiftOp shift_op, int shift_imm, AddrMode am) { 226 ASSERT(is_uint5(shift_imm)); 227 rn_ = rn; 228 rm_ = rm; 229 shift_op_ = shift_op; 230 shift_imm_ = shift_imm & 31; 231 am_ = am; 232} 233 234 235// ----------------------------------------------------------------------------- 236// Specific instructions, constants, and masks. 237 238// add(sp, sp, 4) instruction (aka Pop()) 239const Instr kPopInstruction = 240 al | PostIndex | 4 | LeaveCC | I | kRegister_sp_Code * B16 | 241 kRegister_sp_Code * B12; 242// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) 243// register r is not encoded. 244const Instr kPushRegPattern = 245 al | B26 | 4 | NegPreIndex | kRegister_sp_Code * B16; 246// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) 247// register r is not encoded. 248const Instr kPopRegPattern = 249 al | B26 | L | 4 | PostIndex | kRegister_sp_Code * B16; 250// mov lr, pc 251const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12; 252// ldr rd, [pc, #offset] 253const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16; 254const Instr kLdrPCPattern = al | 5 * B24 | L | kRegister_pc_Code * B16; 255// blxcc rm 256const Instr kBlxRegMask = 257 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4; 258const Instr kBlxRegPattern = 259 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX; 260const Instr kBlxIp = al | kBlxRegPattern | ip.code(); 261const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; 262const Instr kMovMvnPattern = 0xd * B21; 263const Instr kMovMvnFlip = B22; 264const Instr kMovLeaveCCMask = 0xdff * B16; 265const Instr kMovLeaveCCPattern = 0x1a0 * B16; 266const Instr kMovwMask = 0xff * B20; 267const Instr kMovwPattern = 0x30 * B20; 268const Instr kMovwLeaveCCFlip = 0x5 * B21; 269const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12; 270const Instr kCmpCmnPattern = 0x15 * B20; 271const Instr kCmpCmnFlip = B21; 272const Instr kAddSubFlip = 0x6 * B21; 273const Instr kAndBicFlip = 0xe * B21; 274 275// A mask for the Rd register for push, pop, ldr, str instructions. 276const Instr kLdrRegFpOffsetPattern = 277 al | B26 | L | Offset | kRegister_fp_Code * B16; 278const Instr kStrRegFpOffsetPattern = 279 al | B26 | Offset | kRegister_fp_Code * B16; 280const Instr kLdrRegFpNegOffsetPattern = 281 al | B26 | L | NegOffset | kRegister_fp_Code * B16; 282const Instr kStrRegFpNegOffsetPattern = 283 al | B26 | NegOffset | kRegister_fp_Code * B16; 284const Instr kLdrStrInstrTypeMask = 0xffff0000; 285const Instr kLdrStrInstrArgumentMask = 0x0000ffff; 286const Instr kLdrStrOffsetMask = 0x00000fff; 287 288 289// Spare buffer. 290static const int kMinimalBufferSize = 4*KB; 291 292 293Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) 294 : AssemblerBase(arg_isolate), 295 positions_recorder_(this), 296 emit_debug_code_(FLAG_debug_code) { 297 if (buffer == NULL) { 298 // Do our own buffer management. 299 if (buffer_size <= kMinimalBufferSize) { 300 buffer_size = kMinimalBufferSize; 301 302 if (isolate()->assembler_spare_buffer() != NULL) { 303 buffer = isolate()->assembler_spare_buffer(); 304 isolate()->set_assembler_spare_buffer(NULL); 305 } 306 } 307 if (buffer == NULL) { 308 buffer_ = NewArray<byte>(buffer_size); 309 } else { 310 buffer_ = static_cast<byte*>(buffer); 311 } 312 buffer_size_ = buffer_size; 313 own_buffer_ = true; 314 315 } else { 316 // Use externally provided buffer instead. 317 ASSERT(buffer_size > 0); 318 buffer_ = static_cast<byte*>(buffer); 319 buffer_size_ = buffer_size; 320 own_buffer_ = false; 321 } 322 323 // Set up buffer pointers. 324 ASSERT(buffer_ != NULL); 325 pc_ = buffer_; 326 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); 327 num_pending_reloc_info_ = 0; 328 next_buffer_check_ = 0; 329 const_pool_blocked_nesting_ = 0; 330 no_const_pool_before_ = 0; 331 first_const_pool_use_ = -1; 332 last_bound_pos_ = 0; 333 ClearRecordedAstId(); 334} 335 336 337Assembler::~Assembler() { 338 ASSERT(const_pool_blocked_nesting_ == 0); 339 if (own_buffer_) { 340 if (isolate()->assembler_spare_buffer() == NULL && 341 buffer_size_ == kMinimalBufferSize) { 342 isolate()->set_assembler_spare_buffer(buffer_); 343 } else { 344 DeleteArray(buffer_); 345 } 346 } 347} 348 349 350void Assembler::GetCode(CodeDesc* desc) { 351 // Emit constant pool if necessary. 352 CheckConstPool(true, false); 353 ASSERT(num_pending_reloc_info_ == 0); 354 355 // Set up code descriptor. 356 desc->buffer = buffer_; 357 desc->buffer_size = buffer_size_; 358 desc->instr_size = pc_offset(); 359 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 360} 361 362 363void Assembler::Align(int m) { 364 ASSERT(m >= 4 && IsPowerOf2(m)); 365 while ((pc_offset() & (m - 1)) != 0) { 366 nop(); 367 } 368} 369 370 371void Assembler::CodeTargetAlign() { 372 // Preferred alignment of jump targets on some ARM chips. 373 Align(8); 374} 375 376 377Condition Assembler::GetCondition(Instr instr) { 378 return Instruction::ConditionField(instr); 379} 380 381 382bool Assembler::IsBranch(Instr instr) { 383 return (instr & (B27 | B25)) == (B27 | B25); 384} 385 386 387int Assembler::GetBranchOffset(Instr instr) { 388 ASSERT(IsBranch(instr)); 389 // Take the jump offset in the lower 24 bits, sign extend it and multiply it 390 // with 4 to get the offset in bytes. 391 return ((instr & kImm24Mask) << 8) >> 6; 392} 393 394 395bool Assembler::IsLdrRegisterImmediate(Instr instr) { 396 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20); 397} 398 399 400int Assembler::GetLdrRegisterImmediateOffset(Instr instr) { 401 ASSERT(IsLdrRegisterImmediate(instr)); 402 bool positive = (instr & B23) == B23; 403 int offset = instr & kOff12Mask; // Zero extended offset. 404 return positive ? offset : -offset; 405} 406 407 408Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) { 409 ASSERT(IsLdrRegisterImmediate(instr)); 410 bool positive = offset >= 0; 411 if (!positive) offset = -offset; 412 ASSERT(is_uint12(offset)); 413 // Set bit indicating whether the offset should be added. 414 instr = (instr & ~B23) | (positive ? B23 : 0); 415 // Set the actual offset. 416 return (instr & ~kOff12Mask) | offset; 417} 418 419 420bool Assembler::IsStrRegisterImmediate(Instr instr) { 421 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26; 422} 423 424 425Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) { 426 ASSERT(IsStrRegisterImmediate(instr)); 427 bool positive = offset >= 0; 428 if (!positive) offset = -offset; 429 ASSERT(is_uint12(offset)); 430 // Set bit indicating whether the offset should be added. 431 instr = (instr & ~B23) | (positive ? B23 : 0); 432 // Set the actual offset. 433 return (instr & ~kOff12Mask) | offset; 434} 435 436 437bool Assembler::IsAddRegisterImmediate(Instr instr) { 438 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23); 439} 440 441 442Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) { 443 ASSERT(IsAddRegisterImmediate(instr)); 444 ASSERT(offset >= 0); 445 ASSERT(is_uint12(offset)); 446 // Set the offset. 447 return (instr & ~kOff12Mask) | offset; 448} 449 450 451Register Assembler::GetRd(Instr instr) { 452 Register reg; 453 reg.code_ = Instruction::RdValue(instr); 454 return reg; 455} 456 457 458Register Assembler::GetRn(Instr instr) { 459 Register reg; 460 reg.code_ = Instruction::RnValue(instr); 461 return reg; 462} 463 464 465Register Assembler::GetRm(Instr instr) { 466 Register reg; 467 reg.code_ = Instruction::RmValue(instr); 468 return reg; 469} 470 471 472bool Assembler::IsPush(Instr instr) { 473 return ((instr & ~kRdMask) == kPushRegPattern); 474} 475 476 477bool Assembler::IsPop(Instr instr) { 478 return ((instr & ~kRdMask) == kPopRegPattern); 479} 480 481 482bool Assembler::IsStrRegFpOffset(Instr instr) { 483 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern); 484} 485 486 487bool Assembler::IsLdrRegFpOffset(Instr instr) { 488 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern); 489} 490 491 492bool Assembler::IsStrRegFpNegOffset(Instr instr) { 493 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern); 494} 495 496 497bool Assembler::IsLdrRegFpNegOffset(Instr instr) { 498 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern); 499} 500 501 502bool Assembler::IsLdrPcImmediateOffset(Instr instr) { 503 // Check the instruction is indeed a 504 // ldr<cond> <Rd>, [pc +/- offset_12]. 505 return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000; 506} 507 508 509bool Assembler::IsTstImmediate(Instr instr) { 510 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 511 (I | TST | S); 512} 513 514 515bool Assembler::IsCmpRegister(Instr instr) { 516 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) == 517 (CMP | S); 518} 519 520 521bool Assembler::IsCmpImmediate(Instr instr) { 522 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 523 (I | CMP | S); 524} 525 526 527Register Assembler::GetCmpImmediateRegister(Instr instr) { 528 ASSERT(IsCmpImmediate(instr)); 529 return GetRn(instr); 530} 531 532 533int Assembler::GetCmpImmediateRawImmediate(Instr instr) { 534 ASSERT(IsCmpImmediate(instr)); 535 return instr & kOff12Mask; 536} 537 538// Labels refer to positions in the (to be) generated code. 539// There are bound, linked, and unused labels. 540// 541// Bound labels refer to known positions in the already 542// generated code. pos() is the position the label refers to. 543// 544// Linked labels refer to unknown positions in the code 545// to be generated; pos() is the position of the last 546// instruction using the label. 547 548 549// The link chain is terminated by a negative code position (must be aligned) 550const int kEndOfChain = -4; 551 552 553int Assembler::target_at(int pos) { 554 Instr instr = instr_at(pos); 555 if ((instr & ~kImm24Mask) == 0) { 556 // Emitted label constant, not part of a branch. 557 return instr - (Code::kHeaderSize - kHeapObjectTag); 558 } 559 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 560 int imm26 = ((instr & kImm24Mask) << 8) >> 6; 561 if ((Instruction::ConditionField(instr) == kSpecialCondition) && 562 ((instr & B24) != 0)) { 563 // blx uses bit 24 to encode bit 2 of imm26 564 imm26 += 2; 565 } 566 return pos + kPcLoadDelta + imm26; 567} 568 569 570void Assembler::target_at_put(int pos, int target_pos) { 571 Instr instr = instr_at(pos); 572 if ((instr & ~kImm24Mask) == 0) { 573 ASSERT(target_pos == kEndOfChain || target_pos >= 0); 574 // Emitted label constant, not part of a branch. 575 // Make label relative to Code* of generated Code object. 576 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); 577 return; 578 } 579 int imm26 = target_pos - (pos + kPcLoadDelta); 580 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 581 if (Instruction::ConditionField(instr) == kSpecialCondition) { 582 // blx uses bit 24 to encode bit 2 of imm26 583 ASSERT((imm26 & 1) == 0); 584 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24; 585 } else { 586 ASSERT((imm26 & 3) == 0); 587 instr &= ~kImm24Mask; 588 } 589 int imm24 = imm26 >> 2; 590 ASSERT(is_int24(imm24)); 591 instr_at_put(pos, instr | (imm24 & kImm24Mask)); 592} 593 594 595void Assembler::print(Label* L) { 596 if (L->is_unused()) { 597 PrintF("unused label\n"); 598 } else if (L->is_bound()) { 599 PrintF("bound label to %d\n", L->pos()); 600 } else if (L->is_linked()) { 601 Label l = *L; 602 PrintF("unbound label"); 603 while (l.is_linked()) { 604 PrintF("@ %d ", l.pos()); 605 Instr instr = instr_at(l.pos()); 606 if ((instr & ~kImm24Mask) == 0) { 607 PrintF("value\n"); 608 } else { 609 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx 610 Condition cond = Instruction::ConditionField(instr); 611 const char* b; 612 const char* c; 613 if (cond == kSpecialCondition) { 614 b = "blx"; 615 c = ""; 616 } else { 617 if ((instr & B24) != 0) 618 b = "bl"; 619 else 620 b = "b"; 621 622 switch (cond) { 623 case eq: c = "eq"; break; 624 case ne: c = "ne"; break; 625 case hs: c = "hs"; break; 626 case lo: c = "lo"; break; 627 case mi: c = "mi"; break; 628 case pl: c = "pl"; break; 629 case vs: c = "vs"; break; 630 case vc: c = "vc"; break; 631 case hi: c = "hi"; break; 632 case ls: c = "ls"; break; 633 case ge: c = "ge"; break; 634 case lt: c = "lt"; break; 635 case gt: c = "gt"; break; 636 case le: c = "le"; break; 637 case al: c = ""; break; 638 default: 639 c = ""; 640 UNREACHABLE(); 641 } 642 } 643 PrintF("%s%s\n", b, c); 644 } 645 next(&l); 646 } 647 } else { 648 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); 649 } 650} 651 652 653void Assembler::bind_to(Label* L, int pos) { 654 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position 655 while (L->is_linked()) { 656 int fixup_pos = L->pos(); 657 next(L); // call next before overwriting link with target at fixup_pos 658 target_at_put(fixup_pos, pos); 659 } 660 L->bind_to(pos); 661 662 // Keep track of the last bound label so we don't eliminate any instructions 663 // before a bound label. 664 if (pos > last_bound_pos_) 665 last_bound_pos_ = pos; 666} 667 668 669void Assembler::link_to(Label* L, Label* appendix) { 670 if (appendix->is_linked()) { 671 if (L->is_linked()) { 672 // Append appendix to L's list. 673 int fixup_pos; 674 int link = L->pos(); 675 do { 676 fixup_pos = link; 677 link = target_at(fixup_pos); 678 } while (link > 0); 679 ASSERT(link == kEndOfChain); 680 target_at_put(fixup_pos, appendix->pos()); 681 } else { 682 // L is empty, simply use appendix. 683 *L = *appendix; 684 } 685 } 686 appendix->Unuse(); // appendix should not be used anymore 687} 688 689 690void Assembler::bind(Label* L) { 691 ASSERT(!L->is_bound()); // label can only be bound once 692 bind_to(L, pc_offset()); 693} 694 695 696void Assembler::next(Label* L) { 697 ASSERT(L->is_linked()); 698 int link = target_at(L->pos()); 699 if (link == kEndOfChain) { 700 L->Unuse(); 701 } else { 702 ASSERT(link >= 0); 703 L->link_to(link); 704 } 705} 706 707 708static Instr EncodeMovwImmediate(uint32_t immediate) { 709 ASSERT(immediate < 0x10000); 710 return ((immediate & 0xf000) << 4) | (immediate & 0xfff); 711} 712 713 714// Low-level code emission routines depending on the addressing mode. 715// If this returns true then you have to use the rotate_imm and immed_8 716// that it returns, because it may have already changed the instruction 717// to match them! 718static bool fits_shifter(uint32_t imm32, 719 uint32_t* rotate_imm, 720 uint32_t* immed_8, 721 Instr* instr) { 722 // imm32 must be unsigned. 723 for (int rot = 0; rot < 16; rot++) { 724 uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot)); 725 if ((imm8 <= 0xff)) { 726 *rotate_imm = rot; 727 *immed_8 = imm8; 728 return true; 729 } 730 } 731 // If the opcode is one with a complementary version and the complementary 732 // immediate fits, change the opcode. 733 if (instr != NULL) { 734 if ((*instr & kMovMvnMask) == kMovMvnPattern) { 735 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 736 *instr ^= kMovMvnFlip; 737 return true; 738 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) { 739 if (CpuFeatures::IsSupported(ARMv7)) { 740 if (imm32 < 0x10000) { 741 *instr ^= kMovwLeaveCCFlip; 742 *instr |= EncodeMovwImmediate(imm32); 743 *rotate_imm = *immed_8 = 0; // Not used for movw. 744 return true; 745 } 746 } 747 } 748 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) { 749 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) { 750 *instr ^= kCmpCmnFlip; 751 return true; 752 } 753 } else { 754 Instr alu_insn = (*instr & kALUMask); 755 if (alu_insn == ADD || 756 alu_insn == SUB) { 757 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) { 758 *instr ^= kAddSubFlip; 759 return true; 760 } 761 } else if (alu_insn == AND || 762 alu_insn == BIC) { 763 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 764 *instr ^= kAndBicFlip; 765 return true; 766 } 767 } 768 } 769 } 770 return false; 771} 772 773 774// We have to use the temporary register for things that can be relocated even 775// if they can be encoded in the ARM's 12 bits of immediate-offset instruction 776// space. There is no guarantee that the relocated location can be similarly 777// encoded. 778bool Operand::must_use_constant_pool() const { 779 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { 780#ifdef DEBUG 781 if (!Serializer::enabled()) { 782 Serializer::TooLateToEnableNow(); 783 } 784#endif // def DEBUG 785 return Serializer::enabled(); 786 } else if (rmode_ == RelocInfo::NONE) { 787 return false; 788 } 789 return true; 790} 791 792 793bool Operand::is_single_instruction(Instr instr) const { 794 if (rm_.is_valid()) return true; 795 uint32_t dummy1, dummy2; 796 if (must_use_constant_pool() || 797 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { 798 // The immediate operand cannot be encoded as a shifter operand, or use of 799 // constant pool is required. For a mov instruction not setting the 800 // condition code additional instruction conventions can be used. 801 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set 802 if (must_use_constant_pool() || 803 !CpuFeatures::IsSupported(ARMv7)) { 804 // mov instruction will be an ldr from constant pool (one instruction). 805 return true; 806 } else { 807 // mov instruction will be a mov or movw followed by movt (two 808 // instructions). 809 return false; 810 } 811 } else { 812 // If this is not a mov or mvn instruction there will always an additional 813 // instructions - either mov or ldr. The mov might actually be two 814 // instructions mov or movw followed by movt so including the actual 815 // instruction two or three instructions will be generated. 816 return false; 817 } 818 } else { 819 // No use of constant pool and the immediate operand can be encoded as a 820 // shifter operand. 821 return true; 822 } 823} 824 825 826void Assembler::addrmod1(Instr instr, 827 Register rn, 828 Register rd, 829 const Operand& x) { 830 CheckBuffer(); 831 ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0); 832 if (!x.rm_.is_valid()) { 833 // Immediate. 834 uint32_t rotate_imm; 835 uint32_t immed_8; 836 if (x.must_use_constant_pool() || 837 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { 838 // The immediate operand cannot be encoded as a shifter operand, so load 839 // it first to register ip and change the original instruction to use ip. 840 // However, if the original instruction is a 'mov rd, x' (not setting the 841 // condition code), then replace it with a 'ldr rd, [pc]'. 842 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed 843 Condition cond = Instruction::ConditionField(instr); 844 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set 845 if (x.must_use_constant_pool() || 846 !CpuFeatures::IsSupported(ARMv7)) { 847 RecordRelocInfo(x.rmode_, x.imm32_); 848 ldr(rd, MemOperand(pc, 0), cond); 849 } else { 850 // Will probably use movw, will certainly not use constant pool. 851 mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond); 852 movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond); 853 } 854 } else { 855 // If this is not a mov or mvn instruction we may still be able to avoid 856 // a constant pool entry by using mvn or movw. 857 if (!x.must_use_constant_pool() && 858 (instr & kMovMvnMask) != kMovMvnPattern) { 859 mov(ip, x, LeaveCC, cond); 860 } else { 861 RecordRelocInfo(x.rmode_, x.imm32_); 862 ldr(ip, MemOperand(pc, 0), cond); 863 } 864 addrmod1(instr, rn, rd, Operand(ip)); 865 } 866 return; 867 } 868 instr |= I | rotate_imm*B8 | immed_8; 869 } else if (!x.rs_.is_valid()) { 870 // Immediate shift. 871 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 872 } else { 873 // Register shift. 874 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); 875 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); 876 } 877 emit(instr | rn.code()*B16 | rd.code()*B12); 878 if (rn.is(pc) || x.rm_.is(pc)) { 879 // Block constant pool emission for one instruction after reading pc. 880 BlockConstPoolFor(1); 881 } 882} 883 884 885void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { 886 ASSERT((instr & ~(kCondMask | B | L)) == B26); 887 int am = x.am_; 888 if (!x.rm_.is_valid()) { 889 // Immediate offset. 890 int offset_12 = x.offset_; 891 if (offset_12 < 0) { 892 offset_12 = -offset_12; 893 am ^= U; 894 } 895 if (!is_uint12(offset_12)) { 896 // Immediate offset cannot be encoded, load it first to register ip 897 // rn (and rd in a load) should never be ip, or will be trashed. 898 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 899 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 900 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_)); 901 return; 902 } 903 ASSERT(offset_12 >= 0); // no masking needed 904 instr |= offset_12; 905 } else { 906 // Register offset (shift_imm_ and shift_op_ are 0) or scaled 907 // register offset the constructors make sure than both shift_imm_ 908 // and shift_op_ are initialized. 909 ASSERT(!x.rm_.is(pc)); 910 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 911 } 912 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 913 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 914} 915 916 917void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { 918 ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7)); 919 ASSERT(x.rn_.is_valid()); 920 int am = x.am_; 921 if (!x.rm_.is_valid()) { 922 // Immediate offset. 923 int offset_8 = x.offset_; 924 if (offset_8 < 0) { 925 offset_8 = -offset_8; 926 am ^= U; 927 } 928 if (!is_uint8(offset_8)) { 929 // Immediate offset cannot be encoded, load it first to register ip 930 // rn (and rd in a load) should never be ip, or will be trashed. 931 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 932 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 933 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 934 return; 935 } 936 ASSERT(offset_8 >= 0); // no masking needed 937 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf); 938 } else if (x.shift_imm_ != 0) { 939 // Scaled register offset not supported, load index first 940 // rn (and rd in a load) should never be ip, or will be trashed. 941 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 942 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC, 943 Instruction::ConditionField(instr)); 944 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 945 return; 946 } else { 947 // Register offset. 948 ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback 949 instr |= x.rm_.code(); 950 } 951 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 952 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 953} 954 955 956void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { 957 ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27); 958 ASSERT(rl != 0); 959 ASSERT(!rn.is(pc)); 960 emit(instr | rn.code()*B16 | rl); 961} 962 963 964void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) { 965 // Unindexed addressing is not encoded by this function. 966 ASSERT_EQ((B27 | B26), 967 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L))); 968 ASSERT(x.rn_.is_valid() && !x.rm_.is_valid()); 969 int am = x.am_; 970 int offset_8 = x.offset_; 971 ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset 972 offset_8 >>= 2; 973 if (offset_8 < 0) { 974 offset_8 = -offset_8; 975 am ^= U; 976 } 977 ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte 978 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 979 980 // Post-indexed addressing requires W == 1; different than in addrmod2/3. 981 if ((am & P) == 0) 982 am |= W; 983 984 ASSERT(offset_8 >= 0); // no masking needed 985 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8); 986} 987 988 989int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { 990 int target_pos; 991 if (L->is_bound()) { 992 target_pos = L->pos(); 993 } else { 994 if (L->is_linked()) { 995 target_pos = L->pos(); // L's link 996 } else { 997 target_pos = kEndOfChain; 998 } 999 L->link_to(pc_offset()); 1000 } 1001 1002 // Block the emission of the constant pool, since the branch instruction must 1003 // be emitted at the pc offset recorded by the label. 1004 BlockConstPoolFor(1); 1005 return target_pos - (pc_offset() + kPcLoadDelta); 1006} 1007 1008 1009void Assembler::label_at_put(Label* L, int at_offset) { 1010 int target_pos; 1011 if (L->is_bound()) { 1012 target_pos = L->pos(); 1013 } else { 1014 if (L->is_linked()) { 1015 target_pos = L->pos(); // L's link 1016 } else { 1017 target_pos = kEndOfChain; 1018 } 1019 L->link_to(at_offset); 1020 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); 1021 } 1022} 1023 1024 1025// Branch instructions. 1026void Assembler::b(int branch_offset, Condition cond) { 1027 ASSERT((branch_offset & 3) == 0); 1028 int imm24 = branch_offset >> 2; 1029 ASSERT(is_int24(imm24)); 1030 emit(cond | B27 | B25 | (imm24 & kImm24Mask)); 1031 1032 if (cond == al) { 1033 // Dead code is a good location to emit the constant pool. 1034 CheckConstPool(false, false); 1035 } 1036} 1037 1038 1039void Assembler::bl(int branch_offset, Condition cond) { 1040 positions_recorder()->WriteRecordedPositions(); 1041 ASSERT((branch_offset & 3) == 0); 1042 int imm24 = branch_offset >> 2; 1043 ASSERT(is_int24(imm24)); 1044 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); 1045} 1046 1047 1048void Assembler::blx(int branch_offset) { // v5 and above 1049 positions_recorder()->WriteRecordedPositions(); 1050 ASSERT((branch_offset & 1) == 0); 1051 int h = ((branch_offset & 2) >> 1)*B24; 1052 int imm24 = branch_offset >> 2; 1053 ASSERT(is_int24(imm24)); 1054 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); 1055} 1056 1057 1058void Assembler::blx(Register target, Condition cond) { // v5 and above 1059 positions_recorder()->WriteRecordedPositions(); 1060 ASSERT(!target.is(pc)); 1061 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code()); 1062} 1063 1064 1065void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t 1066 positions_recorder()->WriteRecordedPositions(); 1067 ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged 1068 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code()); 1069} 1070 1071 1072// Data-processing instructions. 1073 1074void Assembler::and_(Register dst, Register src1, const Operand& src2, 1075 SBit s, Condition cond) { 1076 addrmod1(cond | AND | s, src1, dst, src2); 1077} 1078 1079 1080void Assembler::eor(Register dst, Register src1, const Operand& src2, 1081 SBit s, Condition cond) { 1082 addrmod1(cond | EOR | s, src1, dst, src2); 1083} 1084 1085 1086void Assembler::sub(Register dst, Register src1, const Operand& src2, 1087 SBit s, Condition cond) { 1088 addrmod1(cond | SUB | s, src1, dst, src2); 1089} 1090 1091 1092void Assembler::rsb(Register dst, Register src1, const Operand& src2, 1093 SBit s, Condition cond) { 1094 addrmod1(cond | RSB | s, src1, dst, src2); 1095} 1096 1097 1098void Assembler::add(Register dst, Register src1, const Operand& src2, 1099 SBit s, Condition cond) { 1100 addrmod1(cond | ADD | s, src1, dst, src2); 1101} 1102 1103 1104void Assembler::adc(Register dst, Register src1, const Operand& src2, 1105 SBit s, Condition cond) { 1106 addrmod1(cond | ADC | s, src1, dst, src2); 1107} 1108 1109 1110void Assembler::sbc(Register dst, Register src1, const Operand& src2, 1111 SBit s, Condition cond) { 1112 addrmod1(cond | SBC | s, src1, dst, src2); 1113} 1114 1115 1116void Assembler::rsc(Register dst, Register src1, const Operand& src2, 1117 SBit s, Condition cond) { 1118 addrmod1(cond | RSC | s, src1, dst, src2); 1119} 1120 1121 1122void Assembler::tst(Register src1, const Operand& src2, Condition cond) { 1123 addrmod1(cond | TST | S, src1, r0, src2); 1124} 1125 1126 1127void Assembler::teq(Register src1, const Operand& src2, Condition cond) { 1128 addrmod1(cond | TEQ | S, src1, r0, src2); 1129} 1130 1131 1132void Assembler::cmp(Register src1, const Operand& src2, Condition cond) { 1133 addrmod1(cond | CMP | S, src1, r0, src2); 1134} 1135 1136 1137void Assembler::cmp_raw_immediate( 1138 Register src, int raw_immediate, Condition cond) { 1139 ASSERT(is_uint12(raw_immediate)); 1140 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate); 1141} 1142 1143 1144void Assembler::cmn(Register src1, const Operand& src2, Condition cond) { 1145 addrmod1(cond | CMN | S, src1, r0, src2); 1146} 1147 1148 1149void Assembler::orr(Register dst, Register src1, const Operand& src2, 1150 SBit s, Condition cond) { 1151 addrmod1(cond | ORR | s, src1, dst, src2); 1152} 1153 1154 1155void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { 1156 if (dst.is(pc)) { 1157 positions_recorder()->WriteRecordedPositions(); 1158 } 1159 // Don't allow nop instructions in the form mov rn, rn to be generated using 1160 // the mov instruction. They must be generated using nop(int/NopMarkerTypes) 1161 // or MarkCode(int/NopMarkerTypes) pseudo instructions. 1162 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); 1163 addrmod1(cond | MOV | s, r0, dst, src); 1164} 1165 1166 1167void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { 1168 ASSERT(immediate < 0x10000); 1169 mov(reg, Operand(immediate), LeaveCC, cond); 1170} 1171 1172 1173void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { 1174 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); 1175} 1176 1177 1178void Assembler::bic(Register dst, Register src1, const Operand& src2, 1179 SBit s, Condition cond) { 1180 addrmod1(cond | BIC | s, src1, dst, src2); 1181} 1182 1183 1184void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) { 1185 addrmod1(cond | MVN | s, r0, dst, src); 1186} 1187 1188 1189// Multiply instructions. 1190void Assembler::mla(Register dst, Register src1, Register src2, Register srcA, 1191 SBit s, Condition cond) { 1192 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1193 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 | 1194 src2.code()*B8 | B7 | B4 | src1.code()); 1195} 1196 1197 1198void Assembler::mul(Register dst, Register src1, Register src2, 1199 SBit s, Condition cond) { 1200 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1201 // dst goes in bits 16-19 for this instruction! 1202 emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code()); 1203} 1204 1205 1206void Assembler::smlal(Register dstL, 1207 Register dstH, 1208 Register src1, 1209 Register src2, 1210 SBit s, 1211 Condition cond) { 1212 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1213 ASSERT(!dstL.is(dstH)); 1214 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1215 src2.code()*B8 | B7 | B4 | src1.code()); 1216} 1217 1218 1219void Assembler::smull(Register dstL, 1220 Register dstH, 1221 Register src1, 1222 Register src2, 1223 SBit s, 1224 Condition cond) { 1225 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1226 ASSERT(!dstL.is(dstH)); 1227 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 | 1228 src2.code()*B8 | B7 | B4 | src1.code()); 1229} 1230 1231 1232void Assembler::umlal(Register dstL, 1233 Register dstH, 1234 Register src1, 1235 Register src2, 1236 SBit s, 1237 Condition cond) { 1238 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1239 ASSERT(!dstL.is(dstH)); 1240 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1241 src2.code()*B8 | B7 | B4 | src1.code()); 1242} 1243 1244 1245void Assembler::umull(Register dstL, 1246 Register dstH, 1247 Register src1, 1248 Register src2, 1249 SBit s, 1250 Condition cond) { 1251 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1252 ASSERT(!dstL.is(dstH)); 1253 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 | 1254 src2.code()*B8 | B7 | B4 | src1.code()); 1255} 1256 1257 1258// Miscellaneous arithmetic instructions. 1259void Assembler::clz(Register dst, Register src, Condition cond) { 1260 // v5 and above. 1261 ASSERT(!dst.is(pc) && !src.is(pc)); 1262 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 | 1263 15*B8 | CLZ | src.code()); 1264} 1265 1266 1267// Saturating instructions. 1268 1269// Unsigned saturate. 1270void Assembler::usat(Register dst, 1271 int satpos, 1272 const Operand& src, 1273 Condition cond) { 1274 // v6 and above. 1275 ASSERT(CpuFeatures::IsSupported(ARMv7)); 1276 ASSERT(!dst.is(pc) && !src.rm_.is(pc)); 1277 ASSERT((satpos >= 0) && (satpos <= 31)); 1278 ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL)); 1279 ASSERT(src.rs_.is(no_reg)); 1280 1281 int sh = 0; 1282 if (src.shift_op_ == ASR) { 1283 sh = 1; 1284 } 1285 1286 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 | 1287 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code()); 1288} 1289 1290 1291// Bitfield manipulation instructions. 1292 1293// Unsigned bit field extract. 1294// Extracts #width adjacent bits from position #lsb in a register, and 1295// writes them to the low bits of a destination register. 1296// ubfx dst, src, #lsb, #width 1297void Assembler::ubfx(Register dst, 1298 Register src, 1299 int lsb, 1300 int width, 1301 Condition cond) { 1302 // v7 and above. 1303 ASSERT(CpuFeatures::IsSupported(ARMv7)); 1304 ASSERT(!dst.is(pc) && !src.is(pc)); 1305 ASSERT((lsb >= 0) && (lsb <= 31)); 1306 ASSERT((width >= 1) && (width <= (32 - lsb))); 1307 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 | 1308 lsb*B7 | B6 | B4 | src.code()); 1309} 1310 1311 1312// Signed bit field extract. 1313// Extracts #width adjacent bits from position #lsb in a register, and 1314// writes them to the low bits of a destination register. The extracted 1315// value is sign extended to fill the destination register. 1316// sbfx dst, src, #lsb, #width 1317void Assembler::sbfx(Register dst, 1318 Register src, 1319 int lsb, 1320 int width, 1321 Condition cond) { 1322 // v7 and above. 1323 ASSERT(CpuFeatures::IsSupported(ARMv7)); 1324 ASSERT(!dst.is(pc) && !src.is(pc)); 1325 ASSERT((lsb >= 0) && (lsb <= 31)); 1326 ASSERT((width >= 1) && (width <= (32 - lsb))); 1327 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 | 1328 lsb*B7 | B6 | B4 | src.code()); 1329} 1330 1331 1332// Bit field clear. 1333// Sets #width adjacent bits at position #lsb in the destination register 1334// to zero, preserving the value of the other bits. 1335// bfc dst, #lsb, #width 1336void Assembler::bfc(Register dst, int lsb, int width, Condition cond) { 1337 // v7 and above. 1338 ASSERT(CpuFeatures::IsSupported(ARMv7)); 1339 ASSERT(!dst.is(pc)); 1340 ASSERT((lsb >= 0) && (lsb <= 31)); 1341 ASSERT((width >= 1) && (width <= (32 - lsb))); 1342 int msb = lsb + width - 1; 1343 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf); 1344} 1345 1346 1347// Bit field insert. 1348// Inserts #width adjacent bits from the low bits of the source register 1349// into position #lsb of the destination register. 1350// bfi dst, src, #lsb, #width 1351void Assembler::bfi(Register dst, 1352 Register src, 1353 int lsb, 1354 int width, 1355 Condition cond) { 1356 // v7 and above. 1357 ASSERT(CpuFeatures::IsSupported(ARMv7)); 1358 ASSERT(!dst.is(pc) && !src.is(pc)); 1359 ASSERT((lsb >= 0) && (lsb <= 31)); 1360 ASSERT((width >= 1) && (width <= (32 - lsb))); 1361 int msb = lsb + width - 1; 1362 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 1363 src.code()); 1364} 1365 1366 1367// Status register access instructions. 1368void Assembler::mrs(Register dst, SRegister s, Condition cond) { 1369 ASSERT(!dst.is(pc)); 1370 emit(cond | B24 | s | 15*B16 | dst.code()*B12); 1371} 1372 1373 1374void Assembler::msr(SRegisterFieldMask fields, const Operand& src, 1375 Condition cond) { 1376 ASSERT(fields >= B16 && fields < B20); // at least one field set 1377 Instr instr; 1378 if (!src.rm_.is_valid()) { 1379 // Immediate. 1380 uint32_t rotate_imm; 1381 uint32_t immed_8; 1382 if (src.must_use_constant_pool() || 1383 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { 1384 // Immediate operand cannot be encoded, load it first to register ip. 1385 RecordRelocInfo(src.rmode_, src.imm32_); 1386 ldr(ip, MemOperand(pc, 0), cond); 1387 msr(fields, Operand(ip), cond); 1388 return; 1389 } 1390 instr = I | rotate_imm*B8 | immed_8; 1391 } else { 1392 ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed 1393 instr = src.rm_.code(); 1394 } 1395 emit(cond | instr | B24 | B21 | fields | 15*B12); 1396} 1397 1398 1399// Load/Store instructions. 1400void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { 1401 if (dst.is(pc)) { 1402 positions_recorder()->WriteRecordedPositions(); 1403 } 1404 addrmod2(cond | B26 | L, dst, src); 1405} 1406 1407 1408void Assembler::str(Register src, const MemOperand& dst, Condition cond) { 1409 addrmod2(cond | B26, src, dst); 1410} 1411 1412 1413void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) { 1414 addrmod2(cond | B26 | B | L, dst, src); 1415} 1416 1417 1418void Assembler::strb(Register src, const MemOperand& dst, Condition cond) { 1419 addrmod2(cond | B26 | B, src, dst); 1420} 1421 1422 1423void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) { 1424 addrmod3(cond | L | B7 | H | B4, dst, src); 1425} 1426 1427 1428void Assembler::strh(Register src, const MemOperand& dst, Condition cond) { 1429 addrmod3(cond | B7 | H | B4, src, dst); 1430} 1431 1432 1433void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) { 1434 addrmod3(cond | L | B7 | S6 | B4, dst, src); 1435} 1436 1437 1438void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) { 1439 addrmod3(cond | L | B7 | S6 | H | B4, dst, src); 1440} 1441 1442 1443void Assembler::ldrd(Register dst1, Register dst2, 1444 const MemOperand& src, Condition cond) { 1445 ASSERT(CpuFeatures::IsEnabled(ARMv7)); 1446 ASSERT(src.rm().is(no_reg)); 1447 ASSERT(!dst1.is(lr)); // r14. 1448 ASSERT_EQ(0, dst1.code() % 2); 1449 ASSERT_EQ(dst1.code() + 1, dst2.code()); 1450 addrmod3(cond | B7 | B6 | B4, dst1, src); 1451} 1452 1453 1454void Assembler::strd(Register src1, Register src2, 1455 const MemOperand& dst, Condition cond) { 1456 ASSERT(dst.rm().is(no_reg)); 1457 ASSERT(!src1.is(lr)); // r14. 1458 ASSERT_EQ(0, src1.code() % 2); 1459 ASSERT_EQ(src1.code() + 1, src2.code()); 1460 ASSERT(CpuFeatures::IsEnabled(ARMv7)); 1461 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst); 1462} 1463 1464// Load/Store multiple instructions. 1465void Assembler::ldm(BlockAddrMode am, 1466 Register base, 1467 RegList dst, 1468 Condition cond) { 1469 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable. 1470 ASSERT(base.is(sp) || (dst & sp.bit()) == 0); 1471 1472 addrmod4(cond | B27 | am | L, base, dst); 1473 1474 // Emit the constant pool after a function return implemented by ldm ..{..pc}. 1475 if (cond == al && (dst & pc.bit()) != 0) { 1476 // There is a slight chance that the ldm instruction was actually a call, 1477 // in which case it would be wrong to return into the constant pool; we 1478 // recognize this case by checking if the emission of the pool was blocked 1479 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is 1480 // the case, we emit a jump over the pool. 1481 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize); 1482 } 1483} 1484 1485 1486void Assembler::stm(BlockAddrMode am, 1487 Register base, 1488 RegList src, 1489 Condition cond) { 1490 addrmod4(cond | B27 | am, base, src); 1491} 1492 1493 1494// Exception-generating instructions and debugging support. 1495// Stops with a non-negative code less than kNumOfWatchedStops support 1496// enabling/disabling and a counter feature. See simulator-arm.h . 1497void Assembler::stop(const char* msg, Condition cond, int32_t code) { 1498#ifndef __arm__ 1499 ASSERT(code >= kDefaultStopCode); 1500 { 1501 // The Simulator will handle the stop instruction and get the message 1502 // address. It expects to find the address just after the svc instruction. 1503 BlockConstPoolScope block_const_pool(this); 1504 if (code >= 0) { 1505 svc(kStopCode + code, cond); 1506 } else { 1507 svc(kStopCode + kMaxStopCode, cond); 1508 } 1509 emit(reinterpret_cast<Instr>(msg)); 1510 } 1511#else // def __arm__ 1512#ifdef CAN_USE_ARMV5_INSTRUCTIONS 1513 if (cond != al) { 1514 Label skip; 1515 b(&skip, NegateCondition(cond)); 1516 bkpt(0); 1517 bind(&skip); 1518 } else { 1519 bkpt(0); 1520 } 1521#else // ndef CAN_USE_ARMV5_INSTRUCTIONS 1522 svc(0x9f0001, cond); 1523#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS 1524#endif // def __arm__ 1525} 1526 1527 1528void Assembler::bkpt(uint32_t imm16) { // v5 and above 1529 ASSERT(is_uint16(imm16)); 1530 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf)); 1531} 1532 1533 1534void Assembler::svc(uint32_t imm24, Condition cond) { 1535 ASSERT(is_uint24(imm24)); 1536 emit(cond | 15*B24 | imm24); 1537} 1538 1539 1540// Coprocessor instructions. 1541void Assembler::cdp(Coprocessor coproc, 1542 int opcode_1, 1543 CRegister crd, 1544 CRegister crn, 1545 CRegister crm, 1546 int opcode_2, 1547 Condition cond) { 1548 ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2)); 1549 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 | 1550 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code()); 1551} 1552 1553 1554void Assembler::cdp2(Coprocessor coproc, 1555 int opcode_1, 1556 CRegister crd, 1557 CRegister crn, 1558 CRegister crm, 1559 int opcode_2) { // v5 and above 1560 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition); 1561} 1562 1563 1564void Assembler::mcr(Coprocessor coproc, 1565 int opcode_1, 1566 Register rd, 1567 CRegister crn, 1568 CRegister crm, 1569 int opcode_2, 1570 Condition cond) { 1571 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2)); 1572 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 | 1573 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 1574} 1575 1576 1577void Assembler::mcr2(Coprocessor coproc, 1578 int opcode_1, 1579 Register rd, 1580 CRegister crn, 1581 CRegister crm, 1582 int opcode_2) { // v5 and above 1583 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 1584} 1585 1586 1587void Assembler::mrc(Coprocessor coproc, 1588 int opcode_1, 1589 Register rd, 1590 CRegister crn, 1591 CRegister crm, 1592 int opcode_2, 1593 Condition cond) { 1594 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2)); 1595 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 | 1596 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 1597} 1598 1599 1600void Assembler::mrc2(Coprocessor coproc, 1601 int opcode_1, 1602 Register rd, 1603 CRegister crn, 1604 CRegister crm, 1605 int opcode_2) { // v5 and above 1606 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 1607} 1608 1609 1610void Assembler::ldc(Coprocessor coproc, 1611 CRegister crd, 1612 const MemOperand& src, 1613 LFlag l, 1614 Condition cond) { 1615 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src); 1616} 1617 1618 1619void Assembler::ldc(Coprocessor coproc, 1620 CRegister crd, 1621 Register rn, 1622 int option, 1623 LFlag l, 1624 Condition cond) { 1625 // Unindexed addressing. 1626 ASSERT(is_uint8(option)); 1627 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 | 1628 coproc*B8 | (option & 255)); 1629} 1630 1631 1632void Assembler::ldc2(Coprocessor coproc, 1633 CRegister crd, 1634 const MemOperand& src, 1635 LFlag l) { // v5 and above 1636 ldc(coproc, crd, src, l, kSpecialCondition); 1637} 1638 1639 1640void Assembler::ldc2(Coprocessor coproc, 1641 CRegister crd, 1642 Register rn, 1643 int option, 1644 LFlag l) { // v5 and above 1645 ldc(coproc, crd, rn, option, l, kSpecialCondition); 1646} 1647 1648 1649// Support for VFP. 1650 1651void Assembler::vldr(const DwVfpRegister dst, 1652 const Register base, 1653 int offset, 1654 const Condition cond) { 1655 // Ddst = MEM(Rbase + offset). 1656 // Instruction details available in ARM DDI 0406A, A8-628. 1657 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) | 1658 // Vdst(15-12) | 1011(11-8) | offset 1659 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1660 int u = 1; 1661 if (offset < 0) { 1662 offset = -offset; 1663 u = 0; 1664 } 1665 1666 ASSERT(offset >= 0); 1667 if ((offset % 4) == 0 && (offset / 4) < 256) { 1668 emit(cond | u*B23 | 0xD1*B20 | base.code()*B16 | dst.code()*B12 | 1669 0xB*B8 | ((offset / 4) & 255)); 1670 } else { 1671 // Larger offsets must be handled by computing the correct address 1672 // in the ip register. 1673 ASSERT(!base.is(ip)); 1674 if (u == 1) { 1675 add(ip, base, Operand(offset)); 1676 } else { 1677 sub(ip, base, Operand(offset)); 1678 } 1679 emit(cond | 0xD1*B20 | ip.code()*B16 | dst.code()*B12 | 0xB*B8); 1680 } 1681} 1682 1683 1684void Assembler::vldr(const DwVfpRegister dst, 1685 const MemOperand& operand, 1686 const Condition cond) { 1687 ASSERT(!operand.rm().is_valid()); 1688 ASSERT(operand.am_ == Offset); 1689 vldr(dst, operand.rn(), operand.offset(), cond); 1690} 1691 1692 1693void Assembler::vldr(const SwVfpRegister dst, 1694 const Register base, 1695 int offset, 1696 const Condition cond) { 1697 // Sdst = MEM(Rbase + offset). 1698 // Instruction details available in ARM DDI 0406A, A8-628. 1699 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) | 1700 // Vdst(15-12) | 1010(11-8) | offset 1701 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1702 int u = 1; 1703 if (offset < 0) { 1704 offset = -offset; 1705 u = 0; 1706 } 1707 int sd, d; 1708 dst.split_code(&sd, &d); 1709 ASSERT(offset >= 0); 1710 1711 if ((offset % 4) == 0 && (offset / 4) < 256) { 1712 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 | 1713 0xA*B8 | ((offset / 4) & 255)); 1714 } else { 1715 // Larger offsets must be handled by computing the correct address 1716 // in the ip register. 1717 ASSERT(!base.is(ip)); 1718 if (u == 1) { 1719 add(ip, base, Operand(offset)); 1720 } else { 1721 sub(ip, base, Operand(offset)); 1722 } 1723 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 1724 } 1725} 1726 1727 1728void Assembler::vldr(const SwVfpRegister dst, 1729 const MemOperand& operand, 1730 const Condition cond) { 1731 ASSERT(!operand.rm().is_valid()); 1732 ASSERT(operand.am_ == Offset); 1733 vldr(dst, operand.rn(), operand.offset(), cond); 1734} 1735 1736 1737void Assembler::vstr(const DwVfpRegister src, 1738 const Register base, 1739 int offset, 1740 const Condition cond) { 1741 // MEM(Rbase + offset) = Dsrc. 1742 // Instruction details available in ARM DDI 0406A, A8-786. 1743 // cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) | 1744 // Vsrc(15-12) | 1011(11-8) | (offset/4) 1745 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1746 int u = 1; 1747 if (offset < 0) { 1748 offset = -offset; 1749 u = 0; 1750 } 1751 ASSERT(offset >= 0); 1752 if ((offset % 4) == 0 && (offset / 4) < 256) { 1753 emit(cond | u*B23 | 0xD0*B20 | base.code()*B16 | src.code()*B12 | 1754 0xB*B8 | ((offset / 4) & 255)); 1755 } else { 1756 // Larger offsets must be handled by computing the correct address 1757 // in the ip register. 1758 ASSERT(!base.is(ip)); 1759 if (u == 1) { 1760 add(ip, base, Operand(offset)); 1761 } else { 1762 sub(ip, base, Operand(offset)); 1763 } 1764 emit(cond | 0xD0*B20 | ip.code()*B16 | src.code()*B12 | 0xB*B8); 1765 } 1766} 1767 1768 1769void Assembler::vstr(const DwVfpRegister src, 1770 const MemOperand& operand, 1771 const Condition cond) { 1772 ASSERT(!operand.rm().is_valid()); 1773 ASSERT(operand.am_ == Offset); 1774 vstr(src, operand.rn(), operand.offset(), cond); 1775} 1776 1777 1778void Assembler::vstr(const SwVfpRegister src, 1779 const Register base, 1780 int offset, 1781 const Condition cond) { 1782 // MEM(Rbase + offset) = SSrc. 1783 // Instruction details available in ARM DDI 0406A, A8-786. 1784 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) | 1785 // Vdst(15-12) | 1010(11-8) | (offset/4) 1786 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1787 int u = 1; 1788 if (offset < 0) { 1789 offset = -offset; 1790 u = 0; 1791 } 1792 int sd, d; 1793 src.split_code(&sd, &d); 1794 ASSERT(offset >= 0); 1795 if ((offset % 4) == 0 && (offset / 4) < 256) { 1796 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 | 1797 0xA*B8 | ((offset / 4) & 255)); 1798 } else { 1799 // Larger offsets must be handled by computing the correct address 1800 // in the ip register. 1801 ASSERT(!base.is(ip)); 1802 if (u == 1) { 1803 add(ip, base, Operand(offset)); 1804 } else { 1805 sub(ip, base, Operand(offset)); 1806 } 1807 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 1808 } 1809} 1810 1811 1812void Assembler::vstr(const SwVfpRegister src, 1813 const MemOperand& operand, 1814 const Condition cond) { 1815 ASSERT(!operand.rm().is_valid()); 1816 ASSERT(operand.am_ == Offset); 1817 vldr(src, operand.rn(), operand.offset(), cond); 1818} 1819 1820 1821void Assembler::vldm(BlockAddrMode am, 1822 Register base, 1823 DwVfpRegister first, 1824 DwVfpRegister last, 1825 Condition cond) { 1826 // Instruction details available in ARM DDI 0406A, A8-626. 1827 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 1828 // first(15-12) | 1010(11-8) | (count * 2) 1829 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1830 ASSERT_LE(first.code(), last.code()); 1831 ASSERT(am == ia || am == ia_w || am == db_w); 1832 ASSERT(!base.is(pc)); 1833 1834 int sd, d; 1835 first.split_code(&sd, &d); 1836 int count = last.code() - first.code() + 1; 1837 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 1838 0xB*B8 | count*2); 1839} 1840 1841 1842void Assembler::vstm(BlockAddrMode am, 1843 Register base, 1844 DwVfpRegister first, 1845 DwVfpRegister last, 1846 Condition cond) { 1847 // Instruction details available in ARM DDI 0406A, A8-784. 1848 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 1849 // first(15-12) | 1011(11-8) | (count * 2) 1850 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1851 ASSERT_LE(first.code(), last.code()); 1852 ASSERT(am == ia || am == ia_w || am == db_w); 1853 ASSERT(!base.is(pc)); 1854 1855 int sd, d; 1856 first.split_code(&sd, &d); 1857 int count = last.code() - first.code() + 1; 1858 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 1859 0xB*B8 | count*2); 1860} 1861 1862void Assembler::vldm(BlockAddrMode am, 1863 Register base, 1864 SwVfpRegister first, 1865 SwVfpRegister last, 1866 Condition cond) { 1867 // Instruction details available in ARM DDI 0406A, A8-626. 1868 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 1869 // first(15-12) | 1010(11-8) | (count/2) 1870 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1871 ASSERT_LE(first.code(), last.code()); 1872 ASSERT(am == ia || am == ia_w || am == db_w); 1873 ASSERT(!base.is(pc)); 1874 1875 int sd, d; 1876 first.split_code(&sd, &d); 1877 int count = last.code() - first.code() + 1; 1878 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 1879 0xA*B8 | count); 1880} 1881 1882 1883void Assembler::vstm(BlockAddrMode am, 1884 Register base, 1885 SwVfpRegister first, 1886 SwVfpRegister last, 1887 Condition cond) { 1888 // Instruction details available in ARM DDI 0406A, A8-784. 1889 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 1890 // first(15-12) | 1011(11-8) | (count/2) 1891 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1892 ASSERT_LE(first.code(), last.code()); 1893 ASSERT(am == ia || am == ia_w || am == db_w); 1894 ASSERT(!base.is(pc)); 1895 1896 int sd, d; 1897 first.split_code(&sd, &d); 1898 int count = last.code() - first.code() + 1; 1899 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 1900 0xA*B8 | count); 1901} 1902 1903static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) { 1904 uint64_t i; 1905 memcpy(&i, &d, 8); 1906 1907 *lo = i & 0xffffffff; 1908 *hi = i >> 32; 1909} 1910 1911// Only works for little endian floating point formats. 1912// We don't support VFP on the mixed endian floating point platform. 1913static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) { 1914 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1915 1916 // VMOV can accept an immediate of the form: 1917 // 1918 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7 1919 // 1920 // The immediate is encoded using an 8-bit quantity, comprised of two 1921 // 4-bit fields. For an 8-bit immediate of the form: 1922 // 1923 // [abcdefgh] 1924 // 1925 // where a is the MSB and h is the LSB, an immediate 64-bit double can be 1926 // created of the form: 1927 // 1928 // [aBbbbbbb,bbcdefgh,00000000,00000000, 1929 // 00000000,00000000,00000000,00000000] 1930 // 1931 // where B = ~b. 1932 // 1933 1934 uint32_t lo, hi; 1935 DoubleAsTwoUInt32(d, &lo, &hi); 1936 1937 // The most obvious constraint is the long block of zeroes. 1938 if ((lo != 0) || ((hi & 0xffff) != 0)) { 1939 return false; 1940 } 1941 1942 // Bits 62:55 must be all clear or all set. 1943 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) { 1944 return false; 1945 } 1946 1947 // Bit 63 must be NOT bit 62. 1948 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) { 1949 return false; 1950 } 1951 1952 // Create the encoded immediate in the form: 1953 // [00000000,0000abcd,00000000,0000efgh] 1954 *encoding = (hi >> 16) & 0xf; // Low nybble. 1955 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble. 1956 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble. 1957 1958 return true; 1959} 1960 1961 1962void Assembler::vmov(const DwVfpRegister dst, 1963 double imm, 1964 const Condition cond) { 1965 // Dd = immediate 1966 // Instruction details available in ARM DDI 0406B, A8-640. 1967 ASSERT(CpuFeatures::IsEnabled(VFP3)); 1968 1969 uint32_t enc; 1970 if (FitsVMOVDoubleImmediate(imm, &enc)) { 1971 // The double can be encoded in the instruction. 1972 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc); 1973 } else { 1974 // Synthesise the double from ARM immediates. This could be implemented 1975 // using vldr from a constant pool. 1976 uint32_t lo, hi; 1977 DoubleAsTwoUInt32(imm, &lo, &hi); 1978 1979 if (lo == hi) { 1980 // If the lo and hi parts of the double are equal, the literal is easier 1981 // to create. This is the case with 0.0. 1982 mov(ip, Operand(lo)); 1983 vmov(dst, ip, ip); 1984 } else { 1985 // Move the low part of the double into the lower of the corresponsing S 1986 // registers of D register dst. 1987 mov(ip, Operand(lo)); 1988 vmov(dst.low(), ip, cond); 1989 1990 // Move the high part of the double into the higher of the corresponsing S 1991 // registers of D register dst. 1992 mov(ip, Operand(hi)); 1993 vmov(dst.high(), ip, cond); 1994 } 1995 } 1996} 1997 1998 1999void Assembler::vmov(const SwVfpRegister dst, 2000 const SwVfpRegister src, 2001 const Condition cond) { 2002 // Sd = Sm 2003 // Instruction details available in ARM DDI 0406B, A8-642. 2004 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2005 int sd, d, sm, m; 2006 dst.split_code(&sd, &d); 2007 src.split_code(&sm, &m); 2008 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm); 2009} 2010 2011 2012void Assembler::vmov(const DwVfpRegister dst, 2013 const DwVfpRegister src, 2014 const Condition cond) { 2015 // Dd = Dm 2016 // Instruction details available in ARM DDI 0406B, A8-642. 2017 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2018 emit(cond | 0xE*B24 | 0xB*B20 | 2019 dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code()); 2020} 2021 2022 2023void Assembler::vmov(const DwVfpRegister dst, 2024 const Register src1, 2025 const Register src2, 2026 const Condition cond) { 2027 // Dm = <Rt,Rt2>. 2028 // Instruction details available in ARM DDI 0406A, A8-646. 2029 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) | 2030 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2031 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2032 ASSERT(!src1.is(pc) && !src2.is(pc)); 2033 emit(cond | 0xC*B24 | B22 | src2.code()*B16 | 2034 src1.code()*B12 | 0xB*B8 | B4 | dst.code()); 2035} 2036 2037 2038void Assembler::vmov(const Register dst1, 2039 const Register dst2, 2040 const DwVfpRegister src, 2041 const Condition cond) { 2042 // <Rt,Rt2> = Dm. 2043 // Instruction details available in ARM DDI 0406A, A8-646. 2044 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) | 2045 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2046 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2047 ASSERT(!dst1.is(pc) && !dst2.is(pc)); 2048 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 | 2049 dst1.code()*B12 | 0xB*B8 | B4 | src.code()); 2050} 2051 2052 2053void Assembler::vmov(const SwVfpRegister dst, 2054 const Register src, 2055 const Condition cond) { 2056 // Sn = Rt. 2057 // Instruction details available in ARM DDI 0406A, A8-642. 2058 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) | 2059 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2060 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2061 ASSERT(!src.is(pc)); 2062 int sn, n; 2063 dst.split_code(&sn, &n); 2064 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4); 2065} 2066 2067 2068void Assembler::vmov(const Register dst, 2069 const SwVfpRegister src, 2070 const Condition cond) { 2071 // Rt = Sn. 2072 // Instruction details available in ARM DDI 0406A, A8-642. 2073 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) | 2074 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2075 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2076 ASSERT(!dst.is(pc)); 2077 int sn, n; 2078 src.split_code(&sn, &n); 2079 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4); 2080} 2081 2082 2083// Type of data to read from or write to VFP register. 2084// Used as specifier in generic vcvt instruction. 2085enum VFPType { S32, U32, F32, F64 }; 2086 2087 2088static bool IsSignedVFPType(VFPType type) { 2089 switch (type) { 2090 case S32: 2091 return true; 2092 case U32: 2093 return false; 2094 default: 2095 UNREACHABLE(); 2096 return false; 2097 } 2098} 2099 2100 2101static bool IsIntegerVFPType(VFPType type) { 2102 switch (type) { 2103 case S32: 2104 case U32: 2105 return true; 2106 case F32: 2107 case F64: 2108 return false; 2109 default: 2110 UNREACHABLE(); 2111 return false; 2112 } 2113} 2114 2115 2116static bool IsDoubleVFPType(VFPType type) { 2117 switch (type) { 2118 case F32: 2119 return false; 2120 case F64: 2121 return true; 2122 default: 2123 UNREACHABLE(); 2124 return false; 2125 } 2126} 2127 2128 2129// Split five bit reg_code based on size of reg_type. 2130// 32-bit register codes are Vm:M 2131// 64-bit register codes are M:Vm 2132// where Vm is four bits, and M is a single bit. 2133static void SplitRegCode(VFPType reg_type, 2134 int reg_code, 2135 int* vm, 2136 int* m) { 2137 ASSERT((reg_code >= 0) && (reg_code <= 31)); 2138 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) { 2139 // 32 bit type. 2140 *m = reg_code & 0x1; 2141 *vm = reg_code >> 1; 2142 } else { 2143 // 64 bit type. 2144 *m = (reg_code & 0x10) >> 4; 2145 *vm = reg_code & 0x0F; 2146 } 2147} 2148 2149 2150// Encode vcvt.src_type.dst_type instruction. 2151static Instr EncodeVCVT(const VFPType dst_type, 2152 const int dst_code, 2153 const VFPType src_type, 2154 const int src_code, 2155 VFPConversionMode mode, 2156 const Condition cond) { 2157 ASSERT(src_type != dst_type); 2158 int D, Vd, M, Vm; 2159 SplitRegCode(src_type, src_code, &Vm, &M); 2160 SplitRegCode(dst_type, dst_code, &Vd, &D); 2161 2162 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) { 2163 // Conversion between IEEE floating point and 32-bit integer. 2164 // Instruction details available in ARM DDI 0406B, A8.6.295. 2165 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) | 2166 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2167 ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type)); 2168 2169 int sz, opc2, op; 2170 2171 if (IsIntegerVFPType(dst_type)) { 2172 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4; 2173 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 2174 op = mode; 2175 } else { 2176 ASSERT(IsIntegerVFPType(src_type)); 2177 opc2 = 0x0; 2178 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0; 2179 op = IsSignedVFPType(src_type) ? 0x1 : 0x0; 2180 } 2181 2182 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 | 2183 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm); 2184 } else { 2185 // Conversion between IEEE double and single precision. 2186 // Instruction details available in ARM DDI 0406B, A8.6.298. 2187 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) | 2188 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2189 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 2190 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 | 2191 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm); 2192 } 2193} 2194 2195 2196void Assembler::vcvt_f64_s32(const DwVfpRegister dst, 2197 const SwVfpRegister src, 2198 VFPConversionMode mode, 2199 const Condition cond) { 2200 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2201 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond)); 2202} 2203 2204 2205void Assembler::vcvt_f32_s32(const SwVfpRegister dst, 2206 const SwVfpRegister src, 2207 VFPConversionMode mode, 2208 const Condition cond) { 2209 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2210 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond)); 2211} 2212 2213 2214void Assembler::vcvt_f64_u32(const DwVfpRegister dst, 2215 const SwVfpRegister src, 2216 VFPConversionMode mode, 2217 const Condition cond) { 2218 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2219 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond)); 2220} 2221 2222 2223void Assembler::vcvt_s32_f64(const SwVfpRegister dst, 2224 const DwVfpRegister src, 2225 VFPConversionMode mode, 2226 const Condition cond) { 2227 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2228 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond)); 2229} 2230 2231 2232void Assembler::vcvt_u32_f64(const SwVfpRegister dst, 2233 const DwVfpRegister src, 2234 VFPConversionMode mode, 2235 const Condition cond) { 2236 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2237 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond)); 2238} 2239 2240 2241void Assembler::vcvt_f64_f32(const DwVfpRegister dst, 2242 const SwVfpRegister src, 2243 VFPConversionMode mode, 2244 const Condition cond) { 2245 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2246 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond)); 2247} 2248 2249 2250void Assembler::vcvt_f32_f64(const SwVfpRegister dst, 2251 const DwVfpRegister src, 2252 VFPConversionMode mode, 2253 const Condition cond) { 2254 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2255 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond)); 2256} 2257 2258 2259void Assembler::vneg(const DwVfpRegister dst, 2260 const DwVfpRegister src, 2261 const Condition cond) { 2262 emit(cond | 0xE*B24 | 0xB*B20 | B16 | dst.code()*B12 | 2263 0x5*B9 | B8 | B6 | src.code()); 2264} 2265 2266 2267void Assembler::vabs(const DwVfpRegister dst, 2268 const DwVfpRegister src, 2269 const Condition cond) { 2270 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 2271 0x5*B9 | B8 | 0x3*B6 | src.code()); 2272} 2273 2274 2275void Assembler::vadd(const DwVfpRegister dst, 2276 const DwVfpRegister src1, 2277 const DwVfpRegister src2, 2278 const Condition cond) { 2279 // Dd = vadd(Dn, Dm) double precision floating point addition. 2280 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 2281 // Instruction details available in ARM DDI 0406A, A8-536. 2282 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) | 2283 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0) 2284 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2285 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 | 2286 dst.code()*B12 | 0x5*B9 | B8 | src2.code()); 2287} 2288 2289 2290void Assembler::vsub(const DwVfpRegister dst, 2291 const DwVfpRegister src1, 2292 const DwVfpRegister src2, 2293 const Condition cond) { 2294 // Dd = vsub(Dn, Dm) double precision floating point subtraction. 2295 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 2296 // Instruction details available in ARM DDI 0406A, A8-784. 2297 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) | 2298 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0) 2299 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2300 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 | 2301 dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code()); 2302} 2303 2304 2305void Assembler::vmul(const DwVfpRegister dst, 2306 const DwVfpRegister src1, 2307 const DwVfpRegister src2, 2308 const Condition cond) { 2309 // Dd = vmul(Dn, Dm) double precision floating point multiplication. 2310 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 2311 // Instruction details available in ARM DDI 0406A, A8-784. 2312 // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) | 2313 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0) 2314 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2315 emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 | 2316 dst.code()*B12 | 0x5*B9 | B8 | src2.code()); 2317} 2318 2319 2320void Assembler::vdiv(const DwVfpRegister dst, 2321 const DwVfpRegister src1, 2322 const DwVfpRegister src2, 2323 const Condition cond) { 2324 // Dd = vdiv(Dn, Dm) double precision floating point division. 2325 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 2326 // Instruction details available in ARM DDI 0406A, A8-584. 2327 // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) | 2328 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0) 2329 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2330 emit(cond | 0xE*B24 | B23 | src1.code()*B16 | 2331 dst.code()*B12 | 0x5*B9 | B8 | src2.code()); 2332} 2333 2334 2335void Assembler::vcmp(const DwVfpRegister src1, 2336 const DwVfpRegister src2, 2337 const Condition cond) { 2338 // vcmp(Dd, Dm) double precision floating point comparison. 2339 // Instruction details available in ARM DDI 0406A, A8-570. 2340 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) | 2341 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | Vm(3-0) 2342 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2343 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | 2344 src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code()); 2345} 2346 2347 2348void Assembler::vcmp(const DwVfpRegister src1, 2349 const double src2, 2350 const Condition cond) { 2351 // vcmp(Dd, Dm) double precision floating point comparison. 2352 // Instruction details available in ARM DDI 0406A, A8-570. 2353 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) | 2354 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | 0000(3-0) 2355 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2356 ASSERT(src2 == 0.0); 2357 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 | 2358 src1.code()*B12 | 0x5*B9 | B8 | B6); 2359} 2360 2361 2362void Assembler::vmsr(Register dst, Condition cond) { 2363 // Instruction details available in ARM DDI 0406A, A8-652. 2364 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) | 2365 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 2366 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2367 emit(cond | 0xE*B24 | 0xE*B20 | B16 | 2368 dst.code()*B12 | 0xA*B8 | B4); 2369} 2370 2371 2372void Assembler::vmrs(Register dst, Condition cond) { 2373 // Instruction details available in ARM DDI 0406A, A8-652. 2374 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) | 2375 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 2376 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2377 emit(cond | 0xE*B24 | 0xF*B20 | B16 | 2378 dst.code()*B12 | 0xA*B8 | B4); 2379} 2380 2381 2382void Assembler::vsqrt(const DwVfpRegister dst, 2383 const DwVfpRegister src, 2384 const Condition cond) { 2385 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) | 2386 // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0) 2387 ASSERT(CpuFeatures::IsEnabled(VFP3)); 2388 emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 | 2389 dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code()); 2390} 2391 2392 2393// Pseudo instructions. 2394void Assembler::nop(int type) { 2395 // This is mov rx, rx. 2396 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop. 2397 emit(al | 13*B21 | type*B12 | type); 2398} 2399 2400 2401bool Assembler::IsNop(Instr instr, int type) { 2402 // Check for mov rx, rx where x = type. 2403 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop. 2404 return instr == (al | 13*B21 | type*B12 | type); 2405} 2406 2407 2408bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { 2409 uint32_t dummy1; 2410 uint32_t dummy2; 2411 return fits_shifter(imm32, &dummy1, &dummy2, NULL); 2412} 2413 2414 2415// Debugging. 2416void Assembler::RecordJSReturn() { 2417 positions_recorder()->WriteRecordedPositions(); 2418 CheckBuffer(); 2419 RecordRelocInfo(RelocInfo::JS_RETURN); 2420} 2421 2422 2423void Assembler::RecordDebugBreakSlot() { 2424 positions_recorder()->WriteRecordedPositions(); 2425 CheckBuffer(); 2426 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); 2427} 2428 2429 2430void Assembler::RecordComment(const char* msg) { 2431 if (FLAG_code_comments) { 2432 CheckBuffer(); 2433 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); 2434 } 2435} 2436 2437 2438void Assembler::GrowBuffer() { 2439 if (!own_buffer_) FATAL("external code buffer is too small"); 2440 2441 // Compute new buffer size. 2442 CodeDesc desc; // the new buffer 2443 if (buffer_size_ < 4*KB) { 2444 desc.buffer_size = 4*KB; 2445 } else if (buffer_size_ < 1*MB) { 2446 desc.buffer_size = 2*buffer_size_; 2447 } else { 2448 desc.buffer_size = buffer_size_ + 1*MB; 2449 } 2450 CHECK_GT(desc.buffer_size, 0); // no overflow 2451 2452 // Set up new buffer. 2453 desc.buffer = NewArray<byte>(desc.buffer_size); 2454 2455 desc.instr_size = pc_offset(); 2456 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 2457 2458 // Copy the data. 2459 int pc_delta = desc.buffer - buffer_; 2460 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); 2461 memmove(desc.buffer, buffer_, desc.instr_size); 2462 memmove(reloc_info_writer.pos() + rc_delta, 2463 reloc_info_writer.pos(), desc.reloc_size); 2464 2465 // Switch buffers. 2466 DeleteArray(buffer_); 2467 buffer_ = desc.buffer; 2468 buffer_size_ = desc.buffer_size; 2469 pc_ += pc_delta; 2470 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 2471 reloc_info_writer.last_pc() + pc_delta); 2472 2473 // None of our relocation types are pc relative pointing outside the code 2474 // buffer nor pc absolute pointing inside the code buffer, so there is no need 2475 // to relocate any emitted relocation entries. 2476 2477 // Relocate pending relocation entries. 2478 for (int i = 0; i < num_pending_reloc_info_; i++) { 2479 RelocInfo& rinfo = pending_reloc_info_[i]; 2480 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && 2481 rinfo.rmode() != RelocInfo::POSITION); 2482 if (rinfo.rmode() != RelocInfo::JS_RETURN) { 2483 rinfo.set_pc(rinfo.pc() + pc_delta); 2484 } 2485 } 2486} 2487 2488 2489void Assembler::db(uint8_t data) { 2490 // No relocation info should be pending while using db. db is used 2491 // to write pure data with no pointers and the constant pool should 2492 // be emitted before using db. 2493 ASSERT(num_pending_reloc_info_ == 0); 2494 CheckBuffer(); 2495 *reinterpret_cast<uint8_t*>(pc_) = data; 2496 pc_ += sizeof(uint8_t); 2497} 2498 2499 2500void Assembler::dd(uint32_t data) { 2501 // No relocation info should be pending while using dd. dd is used 2502 // to write pure data with no pointers and the constant pool should 2503 // be emitted before using dd. 2504 ASSERT(num_pending_reloc_info_ == 0); 2505 CheckBuffer(); 2506 *reinterpret_cast<uint32_t*>(pc_) = data; 2507 pc_ += sizeof(uint32_t); 2508} 2509 2510 2511void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 2512 // We do not try to reuse pool constants. 2513 RelocInfo rinfo(pc_, rmode, data, NULL); 2514 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { 2515 // Adjust code for new modes. 2516 ASSERT(RelocInfo::IsDebugBreakSlot(rmode) 2517 || RelocInfo::IsJSReturn(rmode) 2518 || RelocInfo::IsComment(rmode) 2519 || RelocInfo::IsPosition(rmode)); 2520 // These modes do not need an entry in the constant pool. 2521 } else { 2522 ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); 2523 if (num_pending_reloc_info_ == 0) { 2524 first_const_pool_use_ = pc_offset(); 2525 } 2526 pending_reloc_info_[num_pending_reloc_info_++] = rinfo; 2527 // Make sure the constant pool is not emitted in place of the next 2528 // instruction for which we just recorded relocation info. 2529 BlockConstPoolFor(1); 2530 } 2531 if (rinfo.rmode() != RelocInfo::NONE) { 2532 // Don't record external references unless the heap will be serialized. 2533 if (rmode == RelocInfo::EXTERNAL_REFERENCE) { 2534#ifdef DEBUG 2535 if (!Serializer::enabled()) { 2536 Serializer::TooLateToEnableNow(); 2537 } 2538#endif 2539 if (!Serializer::enabled() && !emit_debug_code()) { 2540 return; 2541 } 2542 } 2543 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here 2544 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { 2545 RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId(), NULL); 2546 ClearRecordedAstId(); 2547 reloc_info_writer.Write(&reloc_info_with_ast_id); 2548 } else { 2549 reloc_info_writer.Write(&rinfo); 2550 } 2551 } 2552} 2553 2554 2555void Assembler::BlockConstPoolFor(int instructions) { 2556 int pc_limit = pc_offset() + instructions * kInstrSize; 2557 if (no_const_pool_before_ < pc_limit) { 2558 // If there are some pending entries, the constant pool cannot be blocked 2559 // further than first_const_pool_use_ + kMaxDistToPool 2560 ASSERT((num_pending_reloc_info_ == 0) || 2561 (pc_limit < (first_const_pool_use_ + kMaxDistToPool))); 2562 no_const_pool_before_ = pc_limit; 2563 } 2564 2565 if (next_buffer_check_ < no_const_pool_before_) { 2566 next_buffer_check_ = no_const_pool_before_; 2567 } 2568} 2569 2570 2571void Assembler::CheckConstPool(bool force_emit, bool require_jump) { 2572 // Some short sequence of instruction mustn't be broken up by constant pool 2573 // emission, such sequences are protected by calls to BlockConstPoolFor and 2574 // BlockConstPoolScope. 2575 if (is_const_pool_blocked()) { 2576 // Something is wrong if emission is forced and blocked at the same time. 2577 ASSERT(!force_emit); 2578 return; 2579 } 2580 2581 // There is nothing to do if there are no pending constant pool entries. 2582 if (num_pending_reloc_info_ == 0) { 2583 // Calculate the offset of the next check. 2584 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 2585 return; 2586 } 2587 2588 // We emit a constant pool when: 2589 // * requested to do so by parameter force_emit (e.g. after each function). 2590 // * the distance to the first instruction accessing the constant pool is 2591 // kAvgDistToPool or more. 2592 // * no jump is required and the distance to the first instruction accessing 2593 // the constant pool is at least kMaxDistToPool / 2. 2594 ASSERT(first_const_pool_use_ >= 0); 2595 int dist = pc_offset() - first_const_pool_use_; 2596 if (!force_emit && dist < kAvgDistToPool && 2597 (require_jump || (dist < (kMaxDistToPool / 2)))) { 2598 return; 2599 } 2600 2601 // Check that the code buffer is large enough before emitting the constant 2602 // pool (include the jump over the pool and the constant pool marker and 2603 // the gap to the relocation information). 2604 int jump_instr = require_jump ? kInstrSize : 0; 2605 int needed_space = jump_instr + kInstrSize + 2606 num_pending_reloc_info_ * kInstrSize + kGap; 2607 while (buffer_space() <= needed_space) GrowBuffer(); 2608 2609 { 2610 // Block recursive calls to CheckConstPool. 2611 BlockConstPoolScope block_const_pool(this); 2612 2613 // Emit jump over constant pool if necessary. 2614 Label after_pool; 2615 if (require_jump) { 2616 b(&after_pool); 2617 } 2618 2619 RecordComment("[ Constant Pool"); 2620 2621 // Put down constant pool marker "Undefined instruction" as specified by 2622 // A5.6 (ARMv7) Instruction set encoding. 2623 emit(kConstantPoolMarker | num_pending_reloc_info_); 2624 2625 // Emit constant pool entries. 2626 for (int i = 0; i < num_pending_reloc_info_; i++) { 2627 RelocInfo& rinfo = pending_reloc_info_[i]; 2628 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && 2629 rinfo.rmode() != RelocInfo::POSITION && 2630 rinfo.rmode() != RelocInfo::STATEMENT_POSITION); 2631 2632 Instr instr = instr_at(rinfo.pc()); 2633 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0. 2634 ASSERT(IsLdrPcImmediateOffset(instr) && 2635 GetLdrRegisterImmediateOffset(instr) == 0); 2636 2637 int delta = pc_ - rinfo.pc() - kPcLoadDelta; 2638 // 0 is the smallest delta: 2639 // ldr rd, [pc, #0] 2640 // constant pool marker 2641 // data 2642 ASSERT(is_uint12(delta)); 2643 2644 instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); 2645 emit(rinfo.data()); 2646 } 2647 2648 num_pending_reloc_info_ = 0; 2649 first_const_pool_use_ = -1; 2650 2651 RecordComment("]"); 2652 2653 if (after_pool.is_linked()) { 2654 bind(&after_pool); 2655 } 2656 } 2657 2658 // Since a constant pool was just emitted, move the check offset forward by 2659 // the standard interval. 2660 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 2661} 2662 2663 2664} } // namespace v8::internal 2665 2666#endif // V8_TARGET_ARCH_ARM 2667