assembler-arm.cc revision 8389745919cae02139ddc085a63c00d024269cf2
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 2012 the V8 project authors. All rights reserved. 36 37#include "src/arm/assembler-arm.h" 38 39#if V8_TARGET_ARCH_ARM 40 41#include "src/arm/assembler-arm-inl.h" 42#include "src/base/bits.h" 43#include "src/base/cpu.h" 44#include "src/macro-assembler.h" 45 46namespace v8 { 47namespace internal { 48 49// Get the CPU features enabled by the build. For cross compilation the 50// preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS 51// can be defined to enable ARMv7 and VFPv3 instructions when building the 52// snapshot. 53static unsigned CpuFeaturesImpliedByCompiler() { 54 unsigned answer = 0; 55#ifdef CAN_USE_ARMV8_INSTRUCTIONS 56 if (FLAG_enable_armv8) { 57 answer |= 1u << ARMv8; 58 // ARMv8 always features VFP and NEON. 59 answer |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS; 60 answer |= 1u << SUDIV | 1u << MLS; 61 } 62#endif // CAN_USE_ARMV8_INSTRUCTIONS 63#ifdef CAN_USE_ARMV7_INSTRUCTIONS 64 if (FLAG_enable_armv7) answer |= 1u << ARMv7; 65#endif // CAN_USE_ARMV7_INSTRUCTIONS 66#ifdef CAN_USE_VFP3_INSTRUCTIONS 67 if (FLAG_enable_vfp3) answer |= 1u << VFP3 | 1u << ARMv7; 68#endif // CAN_USE_VFP3_INSTRUCTIONS 69#ifdef CAN_USE_VFP32DREGS 70 if (FLAG_enable_32dregs) answer |= 1u << VFP32DREGS; 71#endif // CAN_USE_VFP32DREGS 72#ifdef CAN_USE_NEON 73 if (FLAG_enable_neon) answer |= 1u << NEON; 74#endif // CAN_USE_VFP32DREGS 75 if ((answer & (1u << ARMv7)) && FLAG_enable_unaligned_accesses) { 76 answer |= 1u << UNALIGNED_ACCESSES; 77 } 78 79 return answer; 80} 81 82 83void CpuFeatures::ProbeImpl(bool cross_compile) { 84 supported_ |= CpuFeaturesImpliedByCompiler(); 85 dcache_line_size_ = 64; 86 87 // Only use statically determined features for cross compile (snapshot). 88 if (cross_compile) return; 89 90#ifndef __arm__ 91 // For the simulator build, use whatever the flags specify. 92 if (FLAG_enable_armv8) { 93 supported_ |= 1u << ARMv8; 94 // ARMv8 always features VFP and NEON. 95 supported_ |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS; 96 supported_ |= 1u << SUDIV | 1u << MLS; 97 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; 98 } 99 if (FLAG_enable_armv7) { 100 supported_ |= 1u << ARMv7; 101 if (FLAG_enable_vfp3) supported_ |= 1u << VFP3; 102 if (FLAG_enable_neon) supported_ |= 1u << NEON | 1u << VFP32DREGS; 103 if (FLAG_enable_sudiv) supported_ |= 1u << SUDIV; 104 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; 105 if (FLAG_enable_32dregs) supported_ |= 1u << VFP32DREGS; 106 } 107 if (FLAG_enable_mls) supported_ |= 1u << MLS; 108 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES; 109 110#else // __arm__ 111 // Probe for additional features at runtime. 112 base::CPU cpu; 113 if (FLAG_enable_vfp3 && cpu.has_vfp3()) { 114 // This implementation also sets the VFP flags if runtime 115 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI 116 // 0406B, page A1-6. 117 supported_ |= 1u << VFP3 | 1u << ARMv7; 118 } 119 120 if (FLAG_enable_neon && cpu.has_neon()) supported_ |= 1u << NEON; 121 if (FLAG_enable_sudiv && cpu.has_idiva()) supported_ |= 1u << SUDIV; 122 if (FLAG_enable_mls && cpu.has_thumb2()) supported_ |= 1u << MLS; 123 124 if (cpu.architecture() >= 7) { 125 if (FLAG_enable_armv7) supported_ |= 1u << ARMv7; 126 if (FLAG_enable_armv8 && cpu.architecture() >= 8) { 127 supported_ |= 1u << ARMv8; 128 } 129 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES; 130 // Use movw/movt for QUALCOMM ARMv7 cores. 131 if (FLAG_enable_movw_movt && cpu.implementer() == base::CPU::QUALCOMM) { 132 supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; 133 } 134 } 135 136 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines. 137 if (cpu.implementer() == base::CPU::ARM && 138 (cpu.part() == base::CPU::ARM_CORTEX_A5 || 139 cpu.part() == base::CPU::ARM_CORTEX_A9)) { 140 dcache_line_size_ = 32; 141 } 142 143 if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS; 144 145 if (cpu.implementer() == base::CPU::NVIDIA && 146 cpu.variant() == base::CPU::NVIDIA_DENVER && 147 cpu.part() <= base::CPU::NVIDIA_DENVER_V10) { 148 supported_ |= 1u << COHERENT_CACHE; 149 } 150#endif 151 152 DCHECK(!IsSupported(VFP3) || IsSupported(ARMv7)); 153} 154 155 156void CpuFeatures::PrintTarget() { 157 const char* arm_arch = NULL; 158 const char* arm_target_type = ""; 159 const char* arm_no_probe = ""; 160 const char* arm_fpu = ""; 161 const char* arm_thumb = ""; 162 const char* arm_float_abi = NULL; 163 164#if !defined __arm__ 165 arm_target_type = " simulator"; 166#endif 167 168#if defined ARM_TEST_NO_FEATURE_PROBE 169 arm_no_probe = " noprobe"; 170#endif 171 172#if defined CAN_USE_ARMV8_INSTRUCTIONS 173 arm_arch = "arm v8"; 174#elif defined CAN_USE_ARMV7_INSTRUCTIONS 175 arm_arch = "arm v7"; 176#else 177 arm_arch = "arm v6"; 178#endif 179 180#if defined CAN_USE_NEON 181 arm_fpu = " neon"; 182#elif defined CAN_USE_VFP3_INSTRUCTIONS 183# if defined CAN_USE_VFP32DREGS 184 arm_fpu = " vfp3"; 185# else 186 arm_fpu = " vfp3-d16"; 187# endif 188#else 189 arm_fpu = " vfp2"; 190#endif 191 192#ifdef __arm__ 193 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp"; 194#elif USE_EABI_HARDFLOAT 195 arm_float_abi = "hard"; 196#else 197 arm_float_abi = "softfp"; 198#endif 199 200#if defined __arm__ && (defined __thumb__) || (defined __thumb2__) 201 arm_thumb = " thumb"; 202#endif 203 204 printf("target%s%s %s%s%s %s\n", 205 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb, 206 arm_float_abi); 207} 208 209 210void CpuFeatures::PrintFeatures() { 211 printf( 212 "ARMv8=%d ARMv7=%d VFP3=%d VFP32DREGS=%d NEON=%d SUDIV=%d MLS=%d" 213 "UNALIGNED_ACCESSES=%d MOVW_MOVT_IMMEDIATE_LOADS=%d COHERENT_CACHE=%d", 214 CpuFeatures::IsSupported(ARMv8), 215 CpuFeatures::IsSupported(ARMv7), 216 CpuFeatures::IsSupported(VFP3), 217 CpuFeatures::IsSupported(VFP32DREGS), 218 CpuFeatures::IsSupported(NEON), 219 CpuFeatures::IsSupported(SUDIV), 220 CpuFeatures::IsSupported(MLS), 221 CpuFeatures::IsSupported(UNALIGNED_ACCESSES), 222 CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS), 223 CpuFeatures::IsSupported(COHERENT_CACHE)); 224#ifdef __arm__ 225 bool eabi_hardfloat = base::OS::ArmUsingHardFloat(); 226#elif USE_EABI_HARDFLOAT 227 bool eabi_hardfloat = true; 228#else 229 bool eabi_hardfloat = false; 230#endif 231 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat); 232} 233 234 235// ----------------------------------------------------------------------------- 236// Implementation of RelocInfo 237 238// static 239const int RelocInfo::kApplyMask = 0; 240 241 242bool RelocInfo::IsCodedSpecially() { 243 // The deserializer needs to know whether a pointer is specially coded. Being 244 // specially coded on ARM means that it is a movw/movt instruction, or is an 245 // embedded constant pool entry. These only occur if 246 // FLAG_enable_embedded_constant_pool is true. 247 return FLAG_enable_embedded_constant_pool; 248} 249 250 251bool RelocInfo::IsInConstantPool() { 252 return Assembler::is_constant_pool_load(pc_); 253} 254 255 256// ----------------------------------------------------------------------------- 257// Implementation of Operand and MemOperand 258// See assembler-arm-inl.h for inlined constructors 259 260Operand::Operand(Handle<Object> handle) { 261 AllowDeferredHandleDereference using_raw_address; 262 rm_ = no_reg; 263 // Verify all Objects referred by code are NOT in new space. 264 Object* obj = *handle; 265 if (obj->IsHeapObject()) { 266 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj)); 267 imm32_ = reinterpret_cast<intptr_t>(handle.location()); 268 rmode_ = RelocInfo::EMBEDDED_OBJECT; 269 } else { 270 // no relocation needed 271 imm32_ = reinterpret_cast<intptr_t>(obj); 272 rmode_ = RelocInfo::NONE32; 273 } 274} 275 276 277Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) { 278 DCHECK(is_uint5(shift_imm)); 279 280 rm_ = rm; 281 rs_ = no_reg; 282 shift_op_ = shift_op; 283 shift_imm_ = shift_imm & 31; 284 285 if ((shift_op == ROR) && (shift_imm == 0)) { 286 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode 287 // RRX as ROR #0 (See below). 288 shift_op = LSL; 289 } else if (shift_op == RRX) { 290 // encoded as ROR with shift_imm == 0 291 DCHECK(shift_imm == 0); 292 shift_op_ = ROR; 293 shift_imm_ = 0; 294 } 295} 296 297 298Operand::Operand(Register rm, ShiftOp shift_op, Register rs) { 299 DCHECK(shift_op != RRX); 300 rm_ = rm; 301 rs_ = no_reg; 302 shift_op_ = shift_op; 303 rs_ = rs; 304} 305 306 307MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) { 308 rn_ = rn; 309 rm_ = no_reg; 310 offset_ = offset; 311 am_ = am; 312 313 // Accesses below the stack pointer are not safe, and are prohibited by the 314 // ABI. We can check obvious violations here. 315 if (rn.is(sp)) { 316 if (am == Offset) DCHECK_LE(0, offset); 317 if (am == NegOffset) DCHECK_GE(0, offset); 318 } 319} 320 321 322MemOperand::MemOperand(Register rn, Register rm, AddrMode am) { 323 rn_ = rn; 324 rm_ = rm; 325 shift_op_ = LSL; 326 shift_imm_ = 0; 327 am_ = am; 328} 329 330 331MemOperand::MemOperand(Register rn, Register rm, 332 ShiftOp shift_op, int shift_imm, AddrMode am) { 333 DCHECK(is_uint5(shift_imm)); 334 rn_ = rn; 335 rm_ = rm; 336 shift_op_ = shift_op; 337 shift_imm_ = shift_imm & 31; 338 am_ = am; 339} 340 341 342NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) { 343 DCHECK((am == Offset) || (am == PostIndex)); 344 rn_ = rn; 345 rm_ = (am == Offset) ? pc : sp; 346 SetAlignment(align); 347} 348 349 350NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) { 351 rn_ = rn; 352 rm_ = rm; 353 SetAlignment(align); 354} 355 356 357void NeonMemOperand::SetAlignment(int align) { 358 switch (align) { 359 case 0: 360 align_ = 0; 361 break; 362 case 64: 363 align_ = 1; 364 break; 365 case 128: 366 align_ = 2; 367 break; 368 case 256: 369 align_ = 3; 370 break; 371 default: 372 UNREACHABLE(); 373 align_ = 0; 374 break; 375 } 376} 377 378 379NeonListOperand::NeonListOperand(DoubleRegister base, int registers_count) { 380 base_ = base; 381 switch (registers_count) { 382 case 1: 383 type_ = nlt_1; 384 break; 385 case 2: 386 type_ = nlt_2; 387 break; 388 case 3: 389 type_ = nlt_3; 390 break; 391 case 4: 392 type_ = nlt_4; 393 break; 394 default: 395 UNREACHABLE(); 396 type_ = nlt_1; 397 break; 398 } 399} 400 401 402// ----------------------------------------------------------------------------- 403// Specific instructions, constants, and masks. 404 405// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) 406// register r is not encoded. 407const Instr kPushRegPattern = 408 al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16; 409// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) 410// register r is not encoded. 411const Instr kPopRegPattern = 412 al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16; 413// ldr rd, [pc, #offset] 414const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16; 415const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16; 416// ldr rd, [pp, #offset] 417const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16; 418const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16; 419// ldr rd, [pp, rn] 420const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16; 421const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16; 422// vldr dd, [pc, #offset] 423const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8; 424const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8; 425// vldr dd, [pp, #offset] 426const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8; 427const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8; 428// blxcc rm 429const Instr kBlxRegMask = 430 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4; 431const Instr kBlxRegPattern = 432 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX; 433const Instr kBlxIp = al | kBlxRegPattern | ip.code(); 434const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; 435const Instr kMovMvnPattern = 0xd * B21; 436const Instr kMovMvnFlip = B22; 437const Instr kMovLeaveCCMask = 0xdff * B16; 438const Instr kMovLeaveCCPattern = 0x1a0 * B16; 439const Instr kMovwPattern = 0x30 * B20; 440const Instr kMovtPattern = 0x34 * B20; 441const Instr kMovwLeaveCCFlip = 0x5 * B21; 442const Instr kMovImmedMask = 0x7f * B21; 443const Instr kMovImmedPattern = 0x1d * B21; 444const Instr kOrrImmedMask = 0x7f * B21; 445const Instr kOrrImmedPattern = 0x1c * B21; 446const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12; 447const Instr kCmpCmnPattern = 0x15 * B20; 448const Instr kCmpCmnFlip = B21; 449const Instr kAddSubFlip = 0x6 * B21; 450const Instr kAndBicFlip = 0xe * B21; 451 452// A mask for the Rd register for push, pop, ldr, str instructions. 453const Instr kLdrRegFpOffsetPattern = 454 al | B26 | L | Offset | Register::kCode_fp * B16; 455const Instr kStrRegFpOffsetPattern = 456 al | B26 | Offset | Register::kCode_fp * B16; 457const Instr kLdrRegFpNegOffsetPattern = 458 al | B26 | L | NegOffset | Register::kCode_fp * B16; 459const Instr kStrRegFpNegOffsetPattern = 460 al | B26 | NegOffset | Register::kCode_fp * B16; 461const Instr kLdrStrInstrTypeMask = 0xffff0000; 462 463 464Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) 465 : AssemblerBase(isolate, buffer, buffer_size), 466 recorded_ast_id_(TypeFeedbackId::None()), 467 pending_32_bit_constants_(&pending_32_bit_constants_buffer_[0]), 468 pending_64_bit_constants_(&pending_64_bit_constants_buffer_[0]), 469 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits), 470 positions_recorder_(this) { 471 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); 472 num_pending_32_bit_constants_ = 0; 473 num_pending_64_bit_constants_ = 0; 474 next_buffer_check_ = 0; 475 const_pool_blocked_nesting_ = 0; 476 no_const_pool_before_ = 0; 477 first_const_pool_32_use_ = -1; 478 first_const_pool_64_use_ = -1; 479 last_bound_pos_ = 0; 480 ClearRecordedAstId(); 481} 482 483 484Assembler::~Assembler() { 485 DCHECK(const_pool_blocked_nesting_ == 0); 486 if (pending_32_bit_constants_ != &pending_32_bit_constants_buffer_[0]) { 487 delete[] pending_32_bit_constants_; 488 } 489 if (pending_64_bit_constants_ != &pending_64_bit_constants_buffer_[0]) { 490 delete[] pending_64_bit_constants_; 491 } 492} 493 494 495void Assembler::GetCode(CodeDesc* desc) { 496 reloc_info_writer.Finish(); 497 498 // Emit constant pool if necessary. 499 int constant_pool_offset = 0; 500 if (FLAG_enable_embedded_constant_pool) { 501 constant_pool_offset = EmitEmbeddedConstantPool(); 502 } else { 503 CheckConstPool(true, false); 504 DCHECK(num_pending_32_bit_constants_ == 0); 505 DCHECK(num_pending_64_bit_constants_ == 0); 506 } 507 // Set up code descriptor. 508 desc->buffer = buffer_; 509 desc->buffer_size = buffer_size_; 510 desc->instr_size = pc_offset(); 511 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 512 desc->constant_pool_size = 513 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0); 514 desc->origin = this; 515} 516 517 518void Assembler::Align(int m) { 519 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m)); 520 DCHECK((pc_offset() & (kInstrSize - 1)) == 0); 521 while ((pc_offset() & (m - 1)) != 0) { 522 nop(); 523 } 524} 525 526 527void Assembler::CodeTargetAlign() { 528 // Preferred alignment of jump targets on some ARM chips. 529 Align(8); 530} 531 532 533Condition Assembler::GetCondition(Instr instr) { 534 return Instruction::ConditionField(instr); 535} 536 537 538bool Assembler::IsBranch(Instr instr) { 539 return (instr & (B27 | B25)) == (B27 | B25); 540} 541 542 543int Assembler::GetBranchOffset(Instr instr) { 544 DCHECK(IsBranch(instr)); 545 // Take the jump offset in the lower 24 bits, sign extend it and multiply it 546 // with 4 to get the offset in bytes. 547 return ((instr & kImm24Mask) << 8) >> 6; 548} 549 550 551bool Assembler::IsLdrRegisterImmediate(Instr instr) { 552 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20); 553} 554 555 556bool Assembler::IsVldrDRegisterImmediate(Instr instr) { 557 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8); 558} 559 560 561int Assembler::GetLdrRegisterImmediateOffset(Instr instr) { 562 DCHECK(IsLdrRegisterImmediate(instr)); 563 bool positive = (instr & B23) == B23; 564 int offset = instr & kOff12Mask; // Zero extended offset. 565 return positive ? offset : -offset; 566} 567 568 569int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) { 570 DCHECK(IsVldrDRegisterImmediate(instr)); 571 bool positive = (instr & B23) == B23; 572 int offset = instr & kOff8Mask; // Zero extended offset. 573 offset <<= 2; 574 return positive ? offset : -offset; 575} 576 577 578Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) { 579 DCHECK(IsLdrRegisterImmediate(instr)); 580 bool positive = offset >= 0; 581 if (!positive) offset = -offset; 582 DCHECK(is_uint12(offset)); 583 // Set bit indicating whether the offset should be added. 584 instr = (instr & ~B23) | (positive ? B23 : 0); 585 // Set the actual offset. 586 return (instr & ~kOff12Mask) | offset; 587} 588 589 590Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) { 591 DCHECK(IsVldrDRegisterImmediate(instr)); 592 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned. 593 bool positive = offset >= 0; 594 if (!positive) offset = -offset; 595 DCHECK(is_uint10(offset)); 596 // Set bit indicating whether the offset should be added. 597 instr = (instr & ~B23) | (positive ? B23 : 0); 598 // Set the actual offset. Its bottom 2 bits are zero. 599 return (instr & ~kOff8Mask) | (offset >> 2); 600} 601 602 603bool Assembler::IsStrRegisterImmediate(Instr instr) { 604 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26; 605} 606 607 608Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) { 609 DCHECK(IsStrRegisterImmediate(instr)); 610 bool positive = offset >= 0; 611 if (!positive) offset = -offset; 612 DCHECK(is_uint12(offset)); 613 // Set bit indicating whether the offset should be added. 614 instr = (instr & ~B23) | (positive ? B23 : 0); 615 // Set the actual offset. 616 return (instr & ~kOff12Mask) | offset; 617} 618 619 620bool Assembler::IsAddRegisterImmediate(Instr instr) { 621 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23); 622} 623 624 625Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) { 626 DCHECK(IsAddRegisterImmediate(instr)); 627 DCHECK(offset >= 0); 628 DCHECK(is_uint12(offset)); 629 // Set the offset. 630 return (instr & ~kOff12Mask) | offset; 631} 632 633 634Register Assembler::GetRd(Instr instr) { 635 Register reg; 636 reg.reg_code = Instruction::RdValue(instr); 637 return reg; 638} 639 640 641Register Assembler::GetRn(Instr instr) { 642 Register reg; 643 reg.reg_code = Instruction::RnValue(instr); 644 return reg; 645} 646 647 648Register Assembler::GetRm(Instr instr) { 649 Register reg; 650 reg.reg_code = Instruction::RmValue(instr); 651 return reg; 652} 653 654 655Instr Assembler::GetConsantPoolLoadPattern() { 656 if (FLAG_enable_embedded_constant_pool) { 657 return kLdrPpImmedPattern; 658 } else { 659 return kLdrPCImmedPattern; 660 } 661} 662 663 664Instr Assembler::GetConsantPoolLoadMask() { 665 if (FLAG_enable_embedded_constant_pool) { 666 return kLdrPpImmedMask; 667 } else { 668 return kLdrPCImmedMask; 669 } 670} 671 672 673bool Assembler::IsPush(Instr instr) { 674 return ((instr & ~kRdMask) == kPushRegPattern); 675} 676 677 678bool Assembler::IsPop(Instr instr) { 679 return ((instr & ~kRdMask) == kPopRegPattern); 680} 681 682 683bool Assembler::IsStrRegFpOffset(Instr instr) { 684 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern); 685} 686 687 688bool Assembler::IsLdrRegFpOffset(Instr instr) { 689 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern); 690} 691 692 693bool Assembler::IsStrRegFpNegOffset(Instr instr) { 694 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern); 695} 696 697 698bool Assembler::IsLdrRegFpNegOffset(Instr instr) { 699 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern); 700} 701 702 703bool Assembler::IsLdrPcImmediateOffset(Instr instr) { 704 // Check the instruction is indeed a 705 // ldr<cond> <Rd>, [pc +/- offset_12]. 706 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern; 707} 708 709 710bool Assembler::IsLdrPpImmediateOffset(Instr instr) { 711 // Check the instruction is indeed a 712 // ldr<cond> <Rd>, [pp +/- offset_12]. 713 return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern; 714} 715 716 717bool Assembler::IsLdrPpRegOffset(Instr instr) { 718 // Check the instruction is indeed a 719 // ldr<cond> <Rd>, [pp, +/- <Rm>]. 720 return (instr & kLdrPpRegMask) == kLdrPpRegPattern; 721} 722 723 724Instr Assembler::GetLdrPpRegOffsetPattern() { return kLdrPpRegPattern; } 725 726 727bool Assembler::IsVldrDPcImmediateOffset(Instr instr) { 728 // Check the instruction is indeed a 729 // vldr<cond> <Dd>, [pc +/- offset_10]. 730 return (instr & kVldrDPCMask) == kVldrDPCPattern; 731} 732 733 734bool Assembler::IsVldrDPpImmediateOffset(Instr instr) { 735 // Check the instruction is indeed a 736 // vldr<cond> <Dd>, [pp +/- offset_10]. 737 return (instr & kVldrDPpMask) == kVldrDPpPattern; 738} 739 740 741bool Assembler::IsBlxReg(Instr instr) { 742 // Check the instruction is indeed a 743 // blxcc <Rm> 744 return (instr & kBlxRegMask) == kBlxRegPattern; 745} 746 747 748bool Assembler::IsBlxIp(Instr instr) { 749 // Check the instruction is indeed a 750 // blx ip 751 return instr == kBlxIp; 752} 753 754 755bool Assembler::IsTstImmediate(Instr instr) { 756 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 757 (I | TST | S); 758} 759 760 761bool Assembler::IsCmpRegister(Instr instr) { 762 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) == 763 (CMP | S); 764} 765 766 767bool Assembler::IsCmpImmediate(Instr instr) { 768 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 769 (I | CMP | S); 770} 771 772 773Register Assembler::GetCmpImmediateRegister(Instr instr) { 774 DCHECK(IsCmpImmediate(instr)); 775 return GetRn(instr); 776} 777 778 779int Assembler::GetCmpImmediateRawImmediate(Instr instr) { 780 DCHECK(IsCmpImmediate(instr)); 781 return instr & kOff12Mask; 782} 783 784 785// Labels refer to positions in the (to be) generated code. 786// There are bound, linked, and unused labels. 787// 788// Bound labels refer to known positions in the already 789// generated code. pos() is the position the label refers to. 790// 791// Linked labels refer to unknown positions in the code 792// to be generated; pos() is the position of the last 793// instruction using the label. 794// 795// The linked labels form a link chain by making the branch offset 796// in the instruction steam to point to the previous branch 797// instruction using the same label. 798// 799// The link chain is terminated by a branch offset pointing to the 800// same position. 801 802 803int Assembler::target_at(int pos) { 804 Instr instr = instr_at(pos); 805 if (is_uint24(instr)) { 806 // Emitted link to a label, not part of a branch. 807 return instr; 808 } 809 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24 810 int imm26 = ((instr & kImm24Mask) << 8) >> 6; 811 if ((Instruction::ConditionField(instr) == kSpecialCondition) && 812 ((instr & B24) != 0)) { 813 // blx uses bit 24 to encode bit 2 of imm26 814 imm26 += 2; 815 } 816 return pos + kPcLoadDelta + imm26; 817} 818 819 820void Assembler::target_at_put(int pos, int target_pos) { 821 Instr instr = instr_at(pos); 822 if (is_uint24(instr)) { 823 DCHECK(target_pos == pos || target_pos >= 0); 824 // Emitted link to a label, not part of a branch. 825 // Load the position of the label relative to the generated code object 826 // pointer in a register. 827 828 // Here are the instructions we need to emit: 829 // For ARMv7: target24 => target16_1:target16_0 830 // movw dst, #target16_0 831 // movt dst, #target16_1 832 // For ARMv6: target24 => target8_2:target8_1:target8_0 833 // mov dst, #target8_0 834 // orr dst, dst, #target8_1 << 8 835 // orr dst, dst, #target8_2 << 16 836 837 // We extract the destination register from the emitted nop instruction. 838 Register dst = Register::from_code( 839 Instruction::RmValue(instr_at(pos + kInstrSize))); 840 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code())); 841 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag); 842 DCHECK(is_uint24(target24)); 843 if (is_uint8(target24)) { 844 // If the target fits in a byte then only patch with a mov 845 // instruction. 846 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 1, 847 CodePatcher::DONT_FLUSH); 848 patcher.masm()->mov(dst, Operand(target24)); 849 } else { 850 uint16_t target16_0 = target24 & kImm16Mask; 851 uint16_t target16_1 = target24 >> 16; 852 if (CpuFeatures::IsSupported(ARMv7)) { 853 // Patch with movw/movt. 854 if (target16_1 == 0) { 855 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 856 1, CodePatcher::DONT_FLUSH); 857 patcher.masm()->movw(dst, target16_0); 858 } else { 859 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 860 2, CodePatcher::DONT_FLUSH); 861 patcher.masm()->movw(dst, target16_0); 862 patcher.masm()->movt(dst, target16_1); 863 } 864 } else { 865 // Patch with a sequence of mov/orr/orr instructions. 866 uint8_t target8_0 = target16_0 & kImm8Mask; 867 uint8_t target8_1 = target16_0 >> 8; 868 uint8_t target8_2 = target16_1 & kImm8Mask; 869 if (target8_2 == 0) { 870 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 871 2, CodePatcher::DONT_FLUSH); 872 patcher.masm()->mov(dst, Operand(target8_0)); 873 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); 874 } else { 875 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 876 3, CodePatcher::DONT_FLUSH); 877 patcher.masm()->mov(dst, Operand(target8_0)); 878 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); 879 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16)); 880 } 881 } 882 } 883 return; 884 } 885 int imm26 = target_pos - (pos + kPcLoadDelta); 886 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24 887 if (Instruction::ConditionField(instr) == kSpecialCondition) { 888 // blx uses bit 24 to encode bit 2 of imm26 889 DCHECK_EQ(0, imm26 & 1); 890 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24; 891 } else { 892 DCHECK_EQ(0, imm26 & 3); 893 instr &= ~kImm24Mask; 894 } 895 int imm24 = imm26 >> 2; 896 DCHECK(is_int24(imm24)); 897 instr_at_put(pos, instr | (imm24 & kImm24Mask)); 898} 899 900 901void Assembler::print(Label* L) { 902 if (L->is_unused()) { 903 PrintF("unused label\n"); 904 } else if (L->is_bound()) { 905 PrintF("bound label to %d\n", L->pos()); 906 } else if (L->is_linked()) { 907 Label l = *L; 908 PrintF("unbound label"); 909 while (l.is_linked()) { 910 PrintF("@ %d ", l.pos()); 911 Instr instr = instr_at(l.pos()); 912 if ((instr & ~kImm24Mask) == 0) { 913 PrintF("value\n"); 914 } else { 915 DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx 916 Condition cond = Instruction::ConditionField(instr); 917 const char* b; 918 const char* c; 919 if (cond == kSpecialCondition) { 920 b = "blx"; 921 c = ""; 922 } else { 923 if ((instr & B24) != 0) 924 b = "bl"; 925 else 926 b = "b"; 927 928 switch (cond) { 929 case eq: c = "eq"; break; 930 case ne: c = "ne"; break; 931 case hs: c = "hs"; break; 932 case lo: c = "lo"; break; 933 case mi: c = "mi"; break; 934 case pl: c = "pl"; break; 935 case vs: c = "vs"; break; 936 case vc: c = "vc"; break; 937 case hi: c = "hi"; break; 938 case ls: c = "ls"; break; 939 case ge: c = "ge"; break; 940 case lt: c = "lt"; break; 941 case gt: c = "gt"; break; 942 case le: c = "le"; break; 943 case al: c = ""; break; 944 default: 945 c = ""; 946 UNREACHABLE(); 947 } 948 } 949 PrintF("%s%s\n", b, c); 950 } 951 next(&l); 952 } 953 } else { 954 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); 955 } 956} 957 958 959void Assembler::bind_to(Label* L, int pos) { 960 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position 961 while (L->is_linked()) { 962 int fixup_pos = L->pos(); 963 next(L); // call next before overwriting link with target at fixup_pos 964 target_at_put(fixup_pos, pos); 965 } 966 L->bind_to(pos); 967 968 // Keep track of the last bound label so we don't eliminate any instructions 969 // before a bound label. 970 if (pos > last_bound_pos_) 971 last_bound_pos_ = pos; 972} 973 974 975void Assembler::bind(Label* L) { 976 DCHECK(!L->is_bound()); // label can only be bound once 977 bind_to(L, pc_offset()); 978} 979 980 981void Assembler::next(Label* L) { 982 DCHECK(L->is_linked()); 983 int link = target_at(L->pos()); 984 if (link == L->pos()) { 985 // Branch target points to the same instuction. This is the end of the link 986 // chain. 987 L->Unuse(); 988 } else { 989 DCHECK(link >= 0); 990 L->link_to(link); 991 } 992} 993 994 995// Low-level code emission routines depending on the addressing mode. 996// If this returns true then you have to use the rotate_imm and immed_8 997// that it returns, because it may have already changed the instruction 998// to match them! 999static bool fits_shifter(uint32_t imm32, 1000 uint32_t* rotate_imm, 1001 uint32_t* immed_8, 1002 Instr* instr) { 1003 // imm32 must be unsigned. 1004 for (int rot = 0; rot < 16; rot++) { 1005 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot); 1006 if ((imm8 <= 0xff)) { 1007 *rotate_imm = rot; 1008 *immed_8 = imm8; 1009 return true; 1010 } 1011 } 1012 // If the opcode is one with a complementary version and the complementary 1013 // immediate fits, change the opcode. 1014 if (instr != NULL) { 1015 if ((*instr & kMovMvnMask) == kMovMvnPattern) { 1016 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 1017 *instr ^= kMovMvnFlip; 1018 return true; 1019 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) { 1020 if (CpuFeatures::IsSupported(ARMv7)) { 1021 if (imm32 < 0x10000) { 1022 *instr ^= kMovwLeaveCCFlip; 1023 *instr |= Assembler::EncodeMovwImmediate(imm32); 1024 *rotate_imm = *immed_8 = 0; // Not used for movw. 1025 return true; 1026 } 1027 } 1028 } 1029 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) { 1030 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) { 1031 *instr ^= kCmpCmnFlip; 1032 return true; 1033 } 1034 } else { 1035 Instr alu_insn = (*instr & kALUMask); 1036 if (alu_insn == ADD || 1037 alu_insn == SUB) { 1038 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) { 1039 *instr ^= kAddSubFlip; 1040 return true; 1041 } 1042 } else if (alu_insn == AND || 1043 alu_insn == BIC) { 1044 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 1045 *instr ^= kAndBicFlip; 1046 return true; 1047 } 1048 } 1049 } 1050 } 1051 return false; 1052} 1053 1054 1055// We have to use the temporary register for things that can be relocated even 1056// if they can be encoded in the ARM's 12 bits of immediate-offset instruction 1057// space. There is no guarantee that the relocated location can be similarly 1058// encoded. 1059bool Operand::must_output_reloc_info(const Assembler* assembler) const { 1060 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { 1061 if (assembler != NULL && assembler->predictable_code_size()) return true; 1062 return assembler->serializer_enabled(); 1063 } else if (RelocInfo::IsNone(rmode_)) { 1064 return false; 1065 } 1066 return true; 1067} 1068 1069 1070static bool use_mov_immediate_load(const Operand& x, 1071 const Assembler* assembler) { 1072 if (FLAG_enable_embedded_constant_pool && assembler != NULL && 1073 !assembler->is_constant_pool_available()) { 1074 return true; 1075 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && 1076 (assembler == NULL || !assembler->predictable_code_size())) { 1077 // Prefer movw / movt to constant pool if it is more efficient on the CPU. 1078 return true; 1079 } else if (x.must_output_reloc_info(assembler)) { 1080 // Prefer constant pool if data is likely to be patched. 1081 return false; 1082 } else { 1083 // Otherwise, use immediate load if movw / movt is available. 1084 return CpuFeatures::IsSupported(ARMv7); 1085 } 1086} 1087 1088 1089int Operand::instructions_required(const Assembler* assembler, 1090 Instr instr) const { 1091 if (rm_.is_valid()) return 1; 1092 uint32_t dummy1, dummy2; 1093 if (must_output_reloc_info(assembler) || 1094 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { 1095 // The immediate operand cannot be encoded as a shifter operand, or use of 1096 // constant pool is required. First account for the instructions required 1097 // for the constant pool or immediate load 1098 int instructions; 1099 if (use_mov_immediate_load(*this, assembler)) { 1100 // A movw / movt or mov / orr immediate load. 1101 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4; 1102 } else if (assembler != NULL && 1103 assembler->ConstantPoolAccessIsInOverflow()) { 1104 // An overflowed constant pool load. 1105 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5; 1106 } else { 1107 // A small constant pool load. 1108 instructions = 1; 1109 } 1110 1111 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set 1112 // For a mov or mvn instruction which doesn't set the condition 1113 // code, the constant pool or immediate load is enough, otherwise we need 1114 // to account for the actual instruction being requested. 1115 instructions += 1; 1116 } 1117 return instructions; 1118 } else { 1119 // No use of constant pool and the immediate operand can be encoded as a 1120 // shifter operand. 1121 return 1; 1122 } 1123} 1124 1125 1126void Assembler::move_32_bit_immediate(Register rd, 1127 const Operand& x, 1128 Condition cond) { 1129 uint32_t imm32 = static_cast<uint32_t>(x.imm32_); 1130 if (x.must_output_reloc_info(this)) { 1131 RecordRelocInfo(x.rmode_); 1132 } 1133 1134 if (use_mov_immediate_load(x, this)) { 1135 Register target = rd.code() == pc.code() ? ip : rd; 1136 if (CpuFeatures::IsSupported(ARMv7)) { 1137 if (!FLAG_enable_embedded_constant_pool && 1138 x.must_output_reloc_info(this)) { 1139 // Make sure the movw/movt doesn't get separated. 1140 BlockConstPoolFor(2); 1141 } 1142 movw(target, imm32 & 0xffff, cond); 1143 movt(target, imm32 >> 16, cond); 1144 } else { 1145 DCHECK(FLAG_enable_embedded_constant_pool); 1146 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond); 1147 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond); 1148 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond); 1149 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond); 1150 } 1151 if (target.code() != rd.code()) { 1152 mov(rd, target, LeaveCC, cond); 1153 } 1154 } else { 1155 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available()); 1156 ConstantPoolEntry::Access access = 1157 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_); 1158 if (access == ConstantPoolEntry::OVERFLOWED) { 1159 DCHECK(FLAG_enable_embedded_constant_pool); 1160 Register target = rd.code() == pc.code() ? ip : rd; 1161 // Emit instructions to load constant pool offset. 1162 if (CpuFeatures::IsSupported(ARMv7)) { 1163 movw(target, 0, cond); 1164 movt(target, 0, cond); 1165 } else { 1166 mov(target, Operand(0), LeaveCC, cond); 1167 orr(target, target, Operand(0), LeaveCC, cond); 1168 orr(target, target, Operand(0), LeaveCC, cond); 1169 orr(target, target, Operand(0), LeaveCC, cond); 1170 } 1171 // Load from constant pool at offset. 1172 ldr(rd, MemOperand(pp, target), cond); 1173 } else { 1174 DCHECK(access == ConstantPoolEntry::REGULAR); 1175 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0), 1176 cond); 1177 } 1178 } 1179} 1180 1181 1182void Assembler::addrmod1(Instr instr, 1183 Register rn, 1184 Register rd, 1185 const Operand& x) { 1186 CheckBuffer(); 1187 DCHECK((instr & ~(kCondMask | kOpCodeMask | S)) == 0); 1188 if (!x.rm_.is_valid()) { 1189 // Immediate. 1190 uint32_t rotate_imm; 1191 uint32_t immed_8; 1192 if (x.must_output_reloc_info(this) || 1193 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { 1194 // The immediate operand cannot be encoded as a shifter operand, so load 1195 // it first to register ip and change the original instruction to use ip. 1196 // However, if the original instruction is a 'mov rd, x' (not setting the 1197 // condition code), then replace it with a 'ldr rd, [pc]'. 1198 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed 1199 Condition cond = Instruction::ConditionField(instr); 1200 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set 1201 move_32_bit_immediate(rd, x, cond); 1202 } else { 1203 mov(ip, x, LeaveCC, cond); 1204 addrmod1(instr, rn, rd, Operand(ip)); 1205 } 1206 return; 1207 } 1208 instr |= I | rotate_imm*B8 | immed_8; 1209 } else if (!x.rs_.is_valid()) { 1210 // Immediate shift. 1211 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 1212 } else { 1213 // Register shift. 1214 DCHECK(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); 1215 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); 1216 } 1217 emit(instr | rn.code()*B16 | rd.code()*B12); 1218 if (rn.is(pc) || x.rm_.is(pc)) { 1219 // Block constant pool emission for one instruction after reading pc. 1220 BlockConstPoolFor(1); 1221 } 1222} 1223 1224 1225void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { 1226 DCHECK((instr & ~(kCondMask | B | L)) == B26); 1227 int am = x.am_; 1228 if (!x.rm_.is_valid()) { 1229 // Immediate offset. 1230 int offset_12 = x.offset_; 1231 if (offset_12 < 0) { 1232 offset_12 = -offset_12; 1233 am ^= U; 1234 } 1235 if (!is_uint12(offset_12)) { 1236 // Immediate offset cannot be encoded, load it first to register ip 1237 // rn (and rd in a load) should never be ip, or will be trashed. 1238 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1239 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 1240 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1241 return; 1242 } 1243 DCHECK(offset_12 >= 0); // no masking needed 1244 instr |= offset_12; 1245 } else { 1246 // Register offset (shift_imm_ and shift_op_ are 0) or scaled 1247 // register offset the constructors make sure than both shift_imm_ 1248 // and shift_op_ are initialized. 1249 DCHECK(!x.rm_.is(pc)); 1250 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 1251 } 1252 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1253 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 1254} 1255 1256 1257void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { 1258 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7)); 1259 DCHECK(x.rn_.is_valid()); 1260 int am = x.am_; 1261 if (!x.rm_.is_valid()) { 1262 // Immediate offset. 1263 int offset_8 = x.offset_; 1264 if (offset_8 < 0) { 1265 offset_8 = -offset_8; 1266 am ^= U; 1267 } 1268 if (!is_uint8(offset_8)) { 1269 // Immediate offset cannot be encoded, load it first to register ip 1270 // rn (and rd in a load) should never be ip, or will be trashed. 1271 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1272 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 1273 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1274 return; 1275 } 1276 DCHECK(offset_8 >= 0); // no masking needed 1277 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf); 1278 } else if (x.shift_imm_ != 0) { 1279 // Scaled register offset not supported, load index first 1280 // rn (and rd in a load) should never be ip, or will be trashed. 1281 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1282 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC, 1283 Instruction::ConditionField(instr)); 1284 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1285 return; 1286 } else { 1287 // Register offset. 1288 DCHECK((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback 1289 instr |= x.rm_.code(); 1290 } 1291 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1292 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 1293} 1294 1295 1296void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { 1297 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27); 1298 DCHECK(rl != 0); 1299 DCHECK(!rn.is(pc)); 1300 emit(instr | rn.code()*B16 | rl); 1301} 1302 1303 1304void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) { 1305 // Unindexed addressing is not encoded by this function. 1306 DCHECK_EQ((B27 | B26), 1307 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L))); 1308 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid()); 1309 int am = x.am_; 1310 int offset_8 = x.offset_; 1311 DCHECK((offset_8 & 3) == 0); // offset must be an aligned word offset 1312 offset_8 >>= 2; 1313 if (offset_8 < 0) { 1314 offset_8 = -offset_8; 1315 am ^= U; 1316 } 1317 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte 1318 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1319 1320 // Post-indexed addressing requires W == 1; different than in addrmod2/3. 1321 if ((am & P) == 0) 1322 am |= W; 1323 1324 DCHECK(offset_8 >= 0); // no masking needed 1325 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8); 1326} 1327 1328 1329int Assembler::branch_offset(Label* L) { 1330 int target_pos; 1331 if (L->is_bound()) { 1332 target_pos = L->pos(); 1333 } else { 1334 if (L->is_linked()) { 1335 // Point to previous instruction that uses the link. 1336 target_pos = L->pos(); 1337 } else { 1338 // First entry of the link chain points to itself. 1339 target_pos = pc_offset(); 1340 } 1341 L->link_to(pc_offset()); 1342 } 1343 1344 // Block the emission of the constant pool, since the branch instruction must 1345 // be emitted at the pc offset recorded by the label. 1346 if (!is_const_pool_blocked()) BlockConstPoolFor(1); 1347 1348 return target_pos - (pc_offset() + kPcLoadDelta); 1349} 1350 1351 1352// Branch instructions. 1353void Assembler::b(int branch_offset, Condition cond) { 1354 DCHECK((branch_offset & 3) == 0); 1355 int imm24 = branch_offset >> 2; 1356 CHECK(is_int24(imm24)); 1357 emit(cond | B27 | B25 | (imm24 & kImm24Mask)); 1358 1359 if (cond == al) { 1360 // Dead code is a good location to emit the constant pool. 1361 CheckConstPool(false, false); 1362 } 1363} 1364 1365 1366void Assembler::bl(int branch_offset, Condition cond) { 1367 positions_recorder()->WriteRecordedPositions(); 1368 DCHECK((branch_offset & 3) == 0); 1369 int imm24 = branch_offset >> 2; 1370 CHECK(is_int24(imm24)); 1371 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); 1372} 1373 1374 1375void Assembler::blx(int branch_offset) { // v5 and above 1376 positions_recorder()->WriteRecordedPositions(); 1377 DCHECK((branch_offset & 1) == 0); 1378 int h = ((branch_offset & 2) >> 1)*B24; 1379 int imm24 = branch_offset >> 2; 1380 CHECK(is_int24(imm24)); 1381 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); 1382} 1383 1384 1385void Assembler::blx(Register target, Condition cond) { // v5 and above 1386 positions_recorder()->WriteRecordedPositions(); 1387 DCHECK(!target.is(pc)); 1388 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code()); 1389} 1390 1391 1392void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t 1393 positions_recorder()->WriteRecordedPositions(); 1394 DCHECK(!target.is(pc)); // use of pc is actually allowed, but discouraged 1395 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code()); 1396} 1397 1398 1399void Assembler::b(Label* L, Condition cond) { 1400 CheckBuffer(); 1401 b(branch_offset(L), cond); 1402} 1403 1404 1405void Assembler::bl(Label* L, Condition cond) { 1406 CheckBuffer(); 1407 bl(branch_offset(L), cond); 1408} 1409 1410 1411void Assembler::blx(Label* L) { 1412 CheckBuffer(); 1413 blx(branch_offset(L)); 1414} 1415 1416 1417// Data-processing instructions. 1418 1419void Assembler::and_(Register dst, Register src1, const Operand& src2, 1420 SBit s, Condition cond) { 1421 addrmod1(cond | AND | s, src1, dst, src2); 1422} 1423 1424 1425void Assembler::eor(Register dst, Register src1, const Operand& src2, 1426 SBit s, Condition cond) { 1427 addrmod1(cond | EOR | s, src1, dst, src2); 1428} 1429 1430 1431void Assembler::sub(Register dst, Register src1, const Operand& src2, 1432 SBit s, Condition cond) { 1433 addrmod1(cond | SUB | s, src1, dst, src2); 1434} 1435 1436 1437void Assembler::rsb(Register dst, Register src1, const Operand& src2, 1438 SBit s, Condition cond) { 1439 addrmod1(cond | RSB | s, src1, dst, src2); 1440} 1441 1442 1443void Assembler::add(Register dst, Register src1, const Operand& src2, 1444 SBit s, Condition cond) { 1445 addrmod1(cond | ADD | s, src1, dst, src2); 1446} 1447 1448 1449void Assembler::adc(Register dst, Register src1, const Operand& src2, 1450 SBit s, Condition cond) { 1451 addrmod1(cond | ADC | s, src1, dst, src2); 1452} 1453 1454 1455void Assembler::sbc(Register dst, Register src1, const Operand& src2, 1456 SBit s, Condition cond) { 1457 addrmod1(cond | SBC | s, src1, dst, src2); 1458} 1459 1460 1461void Assembler::rsc(Register dst, Register src1, const Operand& src2, 1462 SBit s, Condition cond) { 1463 addrmod1(cond | RSC | s, src1, dst, src2); 1464} 1465 1466 1467void Assembler::tst(Register src1, const Operand& src2, Condition cond) { 1468 addrmod1(cond | TST | S, src1, r0, src2); 1469} 1470 1471 1472void Assembler::teq(Register src1, const Operand& src2, Condition cond) { 1473 addrmod1(cond | TEQ | S, src1, r0, src2); 1474} 1475 1476 1477void Assembler::cmp(Register src1, const Operand& src2, Condition cond) { 1478 addrmod1(cond | CMP | S, src1, r0, src2); 1479} 1480 1481 1482void Assembler::cmp_raw_immediate( 1483 Register src, int raw_immediate, Condition cond) { 1484 DCHECK(is_uint12(raw_immediate)); 1485 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate); 1486} 1487 1488 1489void Assembler::cmn(Register src1, const Operand& src2, Condition cond) { 1490 addrmod1(cond | CMN | S, src1, r0, src2); 1491} 1492 1493 1494void Assembler::orr(Register dst, Register src1, const Operand& src2, 1495 SBit s, Condition cond) { 1496 addrmod1(cond | ORR | s, src1, dst, src2); 1497} 1498 1499 1500void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { 1501 if (dst.is(pc)) { 1502 positions_recorder()->WriteRecordedPositions(); 1503 } 1504 // Don't allow nop instructions in the form mov rn, rn to be generated using 1505 // the mov instruction. They must be generated using nop(int/NopMarkerTypes) 1506 // or MarkCode(int/NopMarkerTypes) pseudo instructions. 1507 DCHECK(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); 1508 addrmod1(cond | MOV | s, r0, dst, src); 1509} 1510 1511 1512void Assembler::mov_label_offset(Register dst, Label* label) { 1513 if (label->is_bound()) { 1514 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag))); 1515 } else { 1516 // Emit the link to the label in the code stream followed by extra nop 1517 // instructions. 1518 // If the label is not linked, then start a new link chain by linking it to 1519 // itself, emitting pc_offset(). 1520 int link = label->is_linked() ? label->pos() : pc_offset(); 1521 label->link_to(pc_offset()); 1522 1523 // When the label is bound, these instructions will be patched with a 1524 // sequence of movw/movt or mov/orr/orr instructions. They will load the 1525 // destination register with the position of the label from the beginning 1526 // of the code. 1527 // 1528 // The link will be extracted from the first instruction and the destination 1529 // register from the second. 1530 // For ARMv7: 1531 // link 1532 // mov dst, dst 1533 // For ARMv6: 1534 // link 1535 // mov dst, dst 1536 // mov dst, dst 1537 // 1538 // When the label gets bound: target_at extracts the link and target_at_put 1539 // patches the instructions. 1540 CHECK(is_uint24(link)); 1541 BlockConstPoolScope block_const_pool(this); 1542 emit(link); 1543 nop(dst.code()); 1544 if (!CpuFeatures::IsSupported(ARMv7)) { 1545 nop(dst.code()); 1546 } 1547 } 1548} 1549 1550 1551void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { 1552 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1553 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); 1554} 1555 1556 1557void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { 1558 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1559 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); 1560} 1561 1562 1563void Assembler::bic(Register dst, Register src1, const Operand& src2, 1564 SBit s, Condition cond) { 1565 addrmod1(cond | BIC | s, src1, dst, src2); 1566} 1567 1568 1569void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) { 1570 addrmod1(cond | MVN | s, r0, dst, src); 1571} 1572 1573 1574// Multiply instructions. 1575void Assembler::mla(Register dst, Register src1, Register src2, Register srcA, 1576 SBit s, Condition cond) { 1577 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1578 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 | 1579 src2.code()*B8 | B7 | B4 | src1.code()); 1580} 1581 1582 1583void Assembler::mls(Register dst, Register src1, Register src2, Register srcA, 1584 Condition cond) { 1585 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1586 DCHECK(IsEnabled(MLS)); 1587 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 | 1588 src2.code()*B8 | B7 | B4 | src1.code()); 1589} 1590 1591 1592void Assembler::sdiv(Register dst, Register src1, Register src2, 1593 Condition cond) { 1594 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1595 DCHECK(IsEnabled(SUDIV)); 1596 emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 | 1597 src2.code()*B8 | B4 | src1.code()); 1598} 1599 1600 1601void Assembler::udiv(Register dst, Register src1, Register src2, 1602 Condition cond) { 1603 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1604 DCHECK(IsEnabled(SUDIV)); 1605 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xf * B12 | 1606 src2.code() * B8 | B4 | src1.code()); 1607} 1608 1609 1610void Assembler::mul(Register dst, Register src1, Register src2, SBit s, 1611 Condition cond) { 1612 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1613 // dst goes in bits 16-19 for this instruction! 1614 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code()); 1615} 1616 1617 1618void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA, 1619 Condition cond) { 1620 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1621 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 1622 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code()); 1623} 1624 1625 1626void Assembler::smmul(Register dst, Register src1, Register src2, 1627 Condition cond) { 1628 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1629 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 | 1630 src2.code() * B8 | B4 | src1.code()); 1631} 1632 1633 1634void Assembler::smlal(Register dstL, 1635 Register dstH, 1636 Register src1, 1637 Register src2, 1638 SBit s, 1639 Condition cond) { 1640 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1641 DCHECK(!dstL.is(dstH)); 1642 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1643 src2.code()*B8 | B7 | B4 | src1.code()); 1644} 1645 1646 1647void Assembler::smull(Register dstL, 1648 Register dstH, 1649 Register src1, 1650 Register src2, 1651 SBit s, 1652 Condition cond) { 1653 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1654 DCHECK(!dstL.is(dstH)); 1655 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 | 1656 src2.code()*B8 | B7 | B4 | src1.code()); 1657} 1658 1659 1660void Assembler::umlal(Register dstL, 1661 Register dstH, 1662 Register src1, 1663 Register src2, 1664 SBit s, 1665 Condition cond) { 1666 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1667 DCHECK(!dstL.is(dstH)); 1668 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1669 src2.code()*B8 | B7 | B4 | src1.code()); 1670} 1671 1672 1673void Assembler::umull(Register dstL, 1674 Register dstH, 1675 Register src1, 1676 Register src2, 1677 SBit s, 1678 Condition cond) { 1679 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1680 DCHECK(!dstL.is(dstH)); 1681 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 | 1682 src2.code()*B8 | B7 | B4 | src1.code()); 1683} 1684 1685 1686// Miscellaneous arithmetic instructions. 1687void Assembler::clz(Register dst, Register src, Condition cond) { 1688 // v5 and above. 1689 DCHECK(!dst.is(pc) && !src.is(pc)); 1690 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 | 1691 15*B8 | CLZ | src.code()); 1692} 1693 1694 1695// Saturating instructions. 1696 1697// Unsigned saturate. 1698void Assembler::usat(Register dst, 1699 int satpos, 1700 const Operand& src, 1701 Condition cond) { 1702 // v6 and above. 1703 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1704 DCHECK(!dst.is(pc) && !src.rm_.is(pc)); 1705 DCHECK((satpos >= 0) && (satpos <= 31)); 1706 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL)); 1707 DCHECK(src.rs_.is(no_reg)); 1708 1709 int sh = 0; 1710 if (src.shift_op_ == ASR) { 1711 sh = 1; 1712 } 1713 1714 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 | 1715 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code()); 1716} 1717 1718 1719// Bitfield manipulation instructions. 1720 1721// Unsigned bit field extract. 1722// Extracts #width adjacent bits from position #lsb in a register, and 1723// writes them to the low bits of a destination register. 1724// ubfx dst, src, #lsb, #width 1725void Assembler::ubfx(Register dst, 1726 Register src, 1727 int lsb, 1728 int width, 1729 Condition cond) { 1730 // v7 and above. 1731 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1732 DCHECK(!dst.is(pc) && !src.is(pc)); 1733 DCHECK((lsb >= 0) && (lsb <= 31)); 1734 DCHECK((width >= 1) && (width <= (32 - lsb))); 1735 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 | 1736 lsb*B7 | B6 | B4 | src.code()); 1737} 1738 1739 1740// Signed bit field extract. 1741// Extracts #width adjacent bits from position #lsb in a register, and 1742// writes them to the low bits of a destination register. The extracted 1743// value is sign extended to fill the destination register. 1744// sbfx dst, src, #lsb, #width 1745void Assembler::sbfx(Register dst, 1746 Register src, 1747 int lsb, 1748 int width, 1749 Condition cond) { 1750 // v7 and above. 1751 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1752 DCHECK(!dst.is(pc) && !src.is(pc)); 1753 DCHECK((lsb >= 0) && (lsb <= 31)); 1754 DCHECK((width >= 1) && (width <= (32 - lsb))); 1755 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 | 1756 lsb*B7 | B6 | B4 | src.code()); 1757} 1758 1759 1760// Bit field clear. 1761// Sets #width adjacent bits at position #lsb in the destination register 1762// to zero, preserving the value of the other bits. 1763// bfc dst, #lsb, #width 1764void Assembler::bfc(Register dst, int lsb, int width, Condition cond) { 1765 // v7 and above. 1766 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1767 DCHECK(!dst.is(pc)); 1768 DCHECK((lsb >= 0) && (lsb <= 31)); 1769 DCHECK((width >= 1) && (width <= (32 - lsb))); 1770 int msb = lsb + width - 1; 1771 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf); 1772} 1773 1774 1775// Bit field insert. 1776// Inserts #width adjacent bits from the low bits of the source register 1777// into position #lsb of the destination register. 1778// bfi dst, src, #lsb, #width 1779void Assembler::bfi(Register dst, 1780 Register src, 1781 int lsb, 1782 int width, 1783 Condition cond) { 1784 // v7 and above. 1785 DCHECK(CpuFeatures::IsSupported(ARMv7)); 1786 DCHECK(!dst.is(pc) && !src.is(pc)); 1787 DCHECK((lsb >= 0) && (lsb <= 31)); 1788 DCHECK((width >= 1) && (width <= (32 - lsb))); 1789 int msb = lsb + width - 1; 1790 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 1791 src.code()); 1792} 1793 1794 1795void Assembler::pkhbt(Register dst, 1796 Register src1, 1797 const Operand& src2, 1798 Condition cond ) { 1799 // Instruction details available in ARM DDI 0406C.b, A8.8.125. 1800 // cond(31-28) | 01101000(27-20) | Rn(19-16) | 1801 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0) 1802 DCHECK(!dst.is(pc)); 1803 DCHECK(!src1.is(pc)); 1804 DCHECK(!src2.rm().is(pc)); 1805 DCHECK(!src2.rm().is(no_reg)); 1806 DCHECK(src2.rs().is(no_reg)); 1807 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31)); 1808 DCHECK(src2.shift_op() == LSL); 1809 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 | 1810 src2.shift_imm_*B7 | B4 | src2.rm().code()); 1811} 1812 1813 1814void Assembler::pkhtb(Register dst, 1815 Register src1, 1816 const Operand& src2, 1817 Condition cond) { 1818 // Instruction details available in ARM DDI 0406C.b, A8.8.125. 1819 // cond(31-28) | 01101000(27-20) | Rn(19-16) | 1820 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0) 1821 DCHECK(!dst.is(pc)); 1822 DCHECK(!src1.is(pc)); 1823 DCHECK(!src2.rm().is(pc)); 1824 DCHECK(!src2.rm().is(no_reg)); 1825 DCHECK(src2.rs().is(no_reg)); 1826 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32)); 1827 DCHECK(src2.shift_op() == ASR); 1828 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_; 1829 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 | 1830 asr*B7 | B6 | B4 | src2.rm().code()); 1831} 1832 1833 1834void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) { 1835 // Instruction details available in ARM DDI 0406C.b, A8.8.233. 1836 // cond(31-28) | 01101010(27-20) | 1111(19-16) | 1837 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1838 DCHECK(!dst.is(pc)); 1839 DCHECK(!src.is(pc)); 1840 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1841 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 | 1842 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1843} 1844 1845 1846void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate, 1847 Condition cond) { 1848 // Instruction details available in ARM DDI 0406C.b, A8.8.233. 1849 // cond(31-28) | 01101010(27-20) | Rn(19-16) | 1850 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1851 DCHECK(!dst.is(pc)); 1852 DCHECK(!src1.is(pc)); 1853 DCHECK(!src2.is(pc)); 1854 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1855 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 | 1856 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1857} 1858 1859 1860void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) { 1861 // Instruction details available in ARM DDI 0406C.b, A8.8.235. 1862 // cond(31-28) | 01101011(27-20) | 1111(19-16) | 1863 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1864 DCHECK(!dst.is(pc)); 1865 DCHECK(!src.is(pc)); 1866 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1867 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 | 1868 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1869} 1870 1871 1872void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate, 1873 Condition cond) { 1874 // Instruction details available in ARM DDI 0406C.b, A8.8.235. 1875 // cond(31-28) | 01101011(27-20) | Rn(19-16) | 1876 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1877 DCHECK(!dst.is(pc)); 1878 DCHECK(!src1.is(pc)); 1879 DCHECK(!src2.is(pc)); 1880 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1881 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 | 1882 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1883} 1884 1885 1886void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) { 1887 // Instruction details available in ARM DDI 0406C.b, A8.8.274. 1888 // cond(31-28) | 01101110(27-20) | 1111(19-16) | 1889 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1890 DCHECK(!dst.is(pc)); 1891 DCHECK(!src.is(pc)); 1892 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1893 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 | 1894 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1895} 1896 1897 1898void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate, 1899 Condition cond) { 1900 // Instruction details available in ARM DDI 0406C.b, A8.8.271. 1901 // cond(31-28) | 01101110(27-20) | Rn(19-16) | 1902 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1903 DCHECK(!dst.is(pc)); 1904 DCHECK(!src1.is(pc)); 1905 DCHECK(!src2.is(pc)); 1906 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1907 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 | 1908 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1909} 1910 1911 1912void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) { 1913 // Instruction details available in ARM DDI 0406C.b, A8.8.275. 1914 // cond(31-28) | 01101100(27-20) | 1111(19-16) | 1915 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1916 DCHECK(!dst.is(pc)); 1917 DCHECK(!src.is(pc)); 1918 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1919 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 | 1920 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1921} 1922 1923 1924void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) { 1925 // Instruction details available in ARM DDI 0406C.b, A8.8.276. 1926 // cond(31-28) | 01101111(27-20) | 1111(19-16) | 1927 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1928 DCHECK(!dst.is(pc)); 1929 DCHECK(!src.is(pc)); 1930 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1931 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 | 1932 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1933} 1934 1935 1936void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate, 1937 Condition cond) { 1938 // Instruction details available in ARM DDI 0406C.b, A8.8.273. 1939 // cond(31-28) | 01101111(27-20) | Rn(19-16) | 1940 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1941 DCHECK(!dst.is(pc)); 1942 DCHECK(!src1.is(pc)); 1943 DCHECK(!src2.is(pc)); 1944 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1945 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 | 1946 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1947} 1948 1949 1950void Assembler::rbit(Register dst, Register src, Condition cond) { 1951 // Instruction details available in ARM DDI 0406C.b, A8.8.144. 1952 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0) 1953 DCHECK(IsEnabled(ARMv7)); 1954 DCHECK(!dst.is(pc)); 1955 DCHECK(!src.is(pc)); 1956 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code()); 1957} 1958 1959 1960// Status register access instructions. 1961void Assembler::mrs(Register dst, SRegister s, Condition cond) { 1962 DCHECK(!dst.is(pc)); 1963 emit(cond | B24 | s | 15*B16 | dst.code()*B12); 1964} 1965 1966 1967void Assembler::msr(SRegisterFieldMask fields, const Operand& src, 1968 Condition cond) { 1969 DCHECK(fields >= B16 && fields < B20); // at least one field set 1970 Instr instr; 1971 if (!src.rm_.is_valid()) { 1972 // Immediate. 1973 uint32_t rotate_imm; 1974 uint32_t immed_8; 1975 if (src.must_output_reloc_info(this) || 1976 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { 1977 // Immediate operand cannot be encoded, load it first to register ip. 1978 move_32_bit_immediate(ip, src); 1979 msr(fields, Operand(ip), cond); 1980 return; 1981 } 1982 instr = I | rotate_imm*B8 | immed_8; 1983 } else { 1984 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed 1985 instr = src.rm_.code(); 1986 } 1987 emit(cond | instr | B24 | B21 | fields | 15*B12); 1988} 1989 1990 1991// Load/Store instructions. 1992void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { 1993 if (dst.is(pc)) { 1994 positions_recorder()->WriteRecordedPositions(); 1995 } 1996 addrmod2(cond | B26 | L, dst, src); 1997} 1998 1999 2000void Assembler::str(Register src, const MemOperand& dst, Condition cond) { 2001 addrmod2(cond | B26, src, dst); 2002} 2003 2004 2005void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) { 2006 addrmod2(cond | B26 | B | L, dst, src); 2007} 2008 2009 2010void Assembler::strb(Register src, const MemOperand& dst, Condition cond) { 2011 addrmod2(cond | B26 | B, src, dst); 2012} 2013 2014 2015void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) { 2016 addrmod3(cond | L | B7 | H | B4, dst, src); 2017} 2018 2019 2020void Assembler::strh(Register src, const MemOperand& dst, Condition cond) { 2021 addrmod3(cond | B7 | H | B4, src, dst); 2022} 2023 2024 2025void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) { 2026 addrmod3(cond | L | B7 | S6 | B4, dst, src); 2027} 2028 2029 2030void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) { 2031 addrmod3(cond | L | B7 | S6 | H | B4, dst, src); 2032} 2033 2034 2035void Assembler::ldrd(Register dst1, Register dst2, 2036 const MemOperand& src, Condition cond) { 2037 DCHECK(IsEnabled(ARMv7)); 2038 DCHECK(src.rm().is(no_reg)); 2039 DCHECK(!dst1.is(lr)); // r14. 2040 DCHECK_EQ(0, dst1.code() % 2); 2041 DCHECK_EQ(dst1.code() + 1, dst2.code()); 2042 addrmod3(cond | B7 | B6 | B4, dst1, src); 2043} 2044 2045 2046void Assembler::strd(Register src1, Register src2, 2047 const MemOperand& dst, Condition cond) { 2048 DCHECK(dst.rm().is(no_reg)); 2049 DCHECK(!src1.is(lr)); // r14. 2050 DCHECK_EQ(0, src1.code() % 2); 2051 DCHECK_EQ(src1.code() + 1, src2.code()); 2052 DCHECK(IsEnabled(ARMv7)); 2053 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst); 2054} 2055 2056 2057// Preload instructions. 2058void Assembler::pld(const MemOperand& address) { 2059 // Instruction details available in ARM DDI 0406C.b, A8.8.128. 2060 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) | 2061 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) | 2062 DCHECK(address.rm().is(no_reg)); 2063 DCHECK(address.am() == Offset); 2064 int U = B23; 2065 int offset = address.offset(); 2066 if (offset < 0) { 2067 offset = -offset; 2068 U = 0; 2069 } 2070 DCHECK(offset < 4096); 2071 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 | 2072 0xf*B12 | offset); 2073} 2074 2075 2076// Load/Store multiple instructions. 2077void Assembler::ldm(BlockAddrMode am, 2078 Register base, 2079 RegList dst, 2080 Condition cond) { 2081 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable. 2082 DCHECK(base.is(sp) || (dst & sp.bit()) == 0); 2083 2084 addrmod4(cond | B27 | am | L, base, dst); 2085 2086 // Emit the constant pool after a function return implemented by ldm ..{..pc}. 2087 if (cond == al && (dst & pc.bit()) != 0) { 2088 // There is a slight chance that the ldm instruction was actually a call, 2089 // in which case it would be wrong to return into the constant pool; we 2090 // recognize this case by checking if the emission of the pool was blocked 2091 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is 2092 // the case, we emit a jump over the pool. 2093 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize); 2094 } 2095} 2096 2097 2098void Assembler::stm(BlockAddrMode am, 2099 Register base, 2100 RegList src, 2101 Condition cond) { 2102 addrmod4(cond | B27 | am, base, src); 2103} 2104 2105 2106// Exception-generating instructions and debugging support. 2107// Stops with a non-negative code less than kNumOfWatchedStops support 2108// enabling/disabling and a counter feature. See simulator-arm.h . 2109void Assembler::stop(const char* msg, Condition cond, int32_t code) { 2110#ifndef __arm__ 2111 DCHECK(code >= kDefaultStopCode); 2112 { 2113 // The Simulator will handle the stop instruction and get the message 2114 // address. It expects to find the address just after the svc instruction. 2115 BlockConstPoolScope block_const_pool(this); 2116 if (code >= 0) { 2117 svc(kStopCode + code, cond); 2118 } else { 2119 svc(kStopCode + kMaxStopCode, cond); 2120 } 2121 emit(reinterpret_cast<Instr>(msg)); 2122 } 2123#else // def __arm__ 2124 if (cond != al) { 2125 Label skip; 2126 b(&skip, NegateCondition(cond)); 2127 bkpt(0); 2128 bind(&skip); 2129 } else { 2130 bkpt(0); 2131 } 2132#endif // def __arm__ 2133} 2134 2135 2136void Assembler::bkpt(uint32_t imm16) { // v5 and above 2137 DCHECK(is_uint16(imm16)); 2138 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf)); 2139} 2140 2141 2142void Assembler::svc(uint32_t imm24, Condition cond) { 2143 DCHECK(is_uint24(imm24)); 2144 emit(cond | 15*B24 | imm24); 2145} 2146 2147 2148void Assembler::dmb(BarrierOption option) { 2149 emit(kSpecialCondition | 0x57ff*B12 | 5*B4 | option); 2150} 2151 2152 2153void Assembler::dsb(BarrierOption option) { 2154 emit(kSpecialCondition | 0x57ff*B12 | 4*B4 | option); 2155} 2156 2157 2158void Assembler::isb(BarrierOption option) { 2159 emit(kSpecialCondition | 0x57ff*B12 | 6*B4 | option); 2160} 2161 2162 2163// Coprocessor instructions. 2164void Assembler::cdp(Coprocessor coproc, 2165 int opcode_1, 2166 CRegister crd, 2167 CRegister crn, 2168 CRegister crm, 2169 int opcode_2, 2170 Condition cond) { 2171 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2)); 2172 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 | 2173 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code()); 2174} 2175 2176 2177void Assembler::cdp2(Coprocessor coproc, 2178 int opcode_1, 2179 CRegister crd, 2180 CRegister crn, 2181 CRegister crm, 2182 int opcode_2) { // v5 and above 2183 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition); 2184} 2185 2186 2187void Assembler::mcr(Coprocessor coproc, 2188 int opcode_1, 2189 Register rd, 2190 CRegister crn, 2191 CRegister crm, 2192 int opcode_2, 2193 Condition cond) { 2194 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2)); 2195 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 | 2196 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 2197} 2198 2199 2200void Assembler::mcr2(Coprocessor coproc, 2201 int opcode_1, 2202 Register rd, 2203 CRegister crn, 2204 CRegister crm, 2205 int opcode_2) { // v5 and above 2206 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 2207} 2208 2209 2210void Assembler::mrc(Coprocessor coproc, 2211 int opcode_1, 2212 Register rd, 2213 CRegister crn, 2214 CRegister crm, 2215 int opcode_2, 2216 Condition cond) { 2217 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2)); 2218 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 | 2219 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 2220} 2221 2222 2223void Assembler::mrc2(Coprocessor coproc, 2224 int opcode_1, 2225 Register rd, 2226 CRegister crn, 2227 CRegister crm, 2228 int opcode_2) { // v5 and above 2229 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 2230} 2231 2232 2233void Assembler::ldc(Coprocessor coproc, 2234 CRegister crd, 2235 const MemOperand& src, 2236 LFlag l, 2237 Condition cond) { 2238 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src); 2239} 2240 2241 2242void Assembler::ldc(Coprocessor coproc, 2243 CRegister crd, 2244 Register rn, 2245 int option, 2246 LFlag l, 2247 Condition cond) { 2248 // Unindexed addressing. 2249 DCHECK(is_uint8(option)); 2250 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 | 2251 coproc*B8 | (option & 255)); 2252} 2253 2254 2255void Assembler::ldc2(Coprocessor coproc, 2256 CRegister crd, 2257 const MemOperand& src, 2258 LFlag l) { // v5 and above 2259 ldc(coproc, crd, src, l, kSpecialCondition); 2260} 2261 2262 2263void Assembler::ldc2(Coprocessor coproc, 2264 CRegister crd, 2265 Register rn, 2266 int option, 2267 LFlag l) { // v5 and above 2268 ldc(coproc, crd, rn, option, l, kSpecialCondition); 2269} 2270 2271 2272// Support for VFP. 2273 2274void Assembler::vldr(const DwVfpRegister dst, 2275 const Register base, 2276 int offset, 2277 const Condition cond) { 2278 // Ddst = MEM(Rbase + offset). 2279 // Instruction details available in ARM DDI 0406C.b, A8-924. 2280 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) | 2281 // Vd(15-12) | 1011(11-8) | offset 2282 int u = 1; 2283 if (offset < 0) { 2284 CHECK(offset != kMinInt); 2285 offset = -offset; 2286 u = 0; 2287 } 2288 int vd, d; 2289 dst.split_code(&vd, &d); 2290 2291 DCHECK(offset >= 0); 2292 if ((offset % 4) == 0 && (offset / 4) < 256) { 2293 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 | 2294 0xB*B8 | ((offset / 4) & 255)); 2295 } else { 2296 // Larger offsets must be handled by computing the correct address 2297 // in the ip register. 2298 DCHECK(!base.is(ip)); 2299 if (u == 1) { 2300 add(ip, base, Operand(offset)); 2301 } else { 2302 sub(ip, base, Operand(offset)); 2303 } 2304 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8); 2305 } 2306} 2307 2308 2309void Assembler::vldr(const DwVfpRegister dst, 2310 const MemOperand& operand, 2311 const Condition cond) { 2312 DCHECK(operand.am_ == Offset); 2313 if (operand.rm().is_valid()) { 2314 add(ip, operand.rn(), 2315 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2316 vldr(dst, ip, 0, cond); 2317 } else { 2318 vldr(dst, operand.rn(), operand.offset(), cond); 2319 } 2320} 2321 2322 2323void Assembler::vldr(const SwVfpRegister dst, 2324 const Register base, 2325 int offset, 2326 const Condition cond) { 2327 // Sdst = MEM(Rbase + offset). 2328 // Instruction details available in ARM DDI 0406A, A8-628. 2329 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) | 2330 // Vdst(15-12) | 1010(11-8) | offset 2331 int u = 1; 2332 if (offset < 0) { 2333 offset = -offset; 2334 u = 0; 2335 } 2336 int sd, d; 2337 dst.split_code(&sd, &d); 2338 DCHECK(offset >= 0); 2339 2340 if ((offset % 4) == 0 && (offset / 4) < 256) { 2341 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 | 2342 0xA*B8 | ((offset / 4) & 255)); 2343 } else { 2344 // Larger offsets must be handled by computing the correct address 2345 // in the ip register. 2346 DCHECK(!base.is(ip)); 2347 if (u == 1) { 2348 add(ip, base, Operand(offset)); 2349 } else { 2350 sub(ip, base, Operand(offset)); 2351 } 2352 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 2353 } 2354} 2355 2356 2357void Assembler::vldr(const SwVfpRegister dst, 2358 const MemOperand& operand, 2359 const Condition cond) { 2360 DCHECK(operand.am_ == Offset); 2361 if (operand.rm().is_valid()) { 2362 add(ip, operand.rn(), 2363 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2364 vldr(dst, ip, 0, cond); 2365 } else { 2366 vldr(dst, operand.rn(), operand.offset(), cond); 2367 } 2368} 2369 2370 2371void Assembler::vstr(const DwVfpRegister src, 2372 const Register base, 2373 int offset, 2374 const Condition cond) { 2375 // MEM(Rbase + offset) = Dsrc. 2376 // Instruction details available in ARM DDI 0406C.b, A8-1082. 2377 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) | 2378 // Vd(15-12) | 1011(11-8) | (offset/4) 2379 int u = 1; 2380 if (offset < 0) { 2381 CHECK(offset != kMinInt); 2382 offset = -offset; 2383 u = 0; 2384 } 2385 DCHECK(offset >= 0); 2386 int vd, d; 2387 src.split_code(&vd, &d); 2388 2389 if ((offset % 4) == 0 && (offset / 4) < 256) { 2390 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 | 2391 ((offset / 4) & 255)); 2392 } else { 2393 // Larger offsets must be handled by computing the correct address 2394 // in the ip register. 2395 DCHECK(!base.is(ip)); 2396 if (u == 1) { 2397 add(ip, base, Operand(offset)); 2398 } else { 2399 sub(ip, base, Operand(offset)); 2400 } 2401 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8); 2402 } 2403} 2404 2405 2406void Assembler::vstr(const DwVfpRegister src, 2407 const MemOperand& operand, 2408 const Condition cond) { 2409 DCHECK(operand.am_ == Offset); 2410 if (operand.rm().is_valid()) { 2411 add(ip, operand.rn(), 2412 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2413 vstr(src, ip, 0, cond); 2414 } else { 2415 vstr(src, operand.rn(), operand.offset(), cond); 2416 } 2417} 2418 2419 2420void Assembler::vstr(const SwVfpRegister src, 2421 const Register base, 2422 int offset, 2423 const Condition cond) { 2424 // MEM(Rbase + offset) = SSrc. 2425 // Instruction details available in ARM DDI 0406A, A8-786. 2426 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) | 2427 // Vdst(15-12) | 1010(11-8) | (offset/4) 2428 int u = 1; 2429 if (offset < 0) { 2430 CHECK(offset != kMinInt); 2431 offset = -offset; 2432 u = 0; 2433 } 2434 int sd, d; 2435 src.split_code(&sd, &d); 2436 DCHECK(offset >= 0); 2437 if ((offset % 4) == 0 && (offset / 4) < 256) { 2438 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 | 2439 0xA*B8 | ((offset / 4) & 255)); 2440 } else { 2441 // Larger offsets must be handled by computing the correct address 2442 // in the ip register. 2443 DCHECK(!base.is(ip)); 2444 if (u == 1) { 2445 add(ip, base, Operand(offset)); 2446 } else { 2447 sub(ip, base, Operand(offset)); 2448 } 2449 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 2450 } 2451} 2452 2453 2454void Assembler::vstr(const SwVfpRegister src, 2455 const MemOperand& operand, 2456 const Condition cond) { 2457 DCHECK(operand.am_ == Offset); 2458 if (operand.rm().is_valid()) { 2459 add(ip, operand.rn(), 2460 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2461 vstr(src, ip, 0, cond); 2462 } else { 2463 vstr(src, operand.rn(), operand.offset(), cond); 2464 } 2465} 2466 2467 2468void Assembler::vldm(BlockAddrMode am, 2469 Register base, 2470 DwVfpRegister first, 2471 DwVfpRegister last, 2472 Condition cond) { 2473 // Instruction details available in ARM DDI 0406C.b, A8-922. 2474 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 2475 // first(15-12) | 1011(11-8) | (count * 2) 2476 DCHECK_LE(first.code(), last.code()); 2477 DCHECK(am == ia || am == ia_w || am == db_w); 2478 DCHECK(!base.is(pc)); 2479 2480 int sd, d; 2481 first.split_code(&sd, &d); 2482 int count = last.code() - first.code() + 1; 2483 DCHECK(count <= 16); 2484 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 2485 0xB*B8 | count*2); 2486} 2487 2488 2489void Assembler::vstm(BlockAddrMode am, 2490 Register base, 2491 DwVfpRegister first, 2492 DwVfpRegister last, 2493 Condition cond) { 2494 // Instruction details available in ARM DDI 0406C.b, A8-1080. 2495 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 2496 // first(15-12) | 1011(11-8) | (count * 2) 2497 DCHECK_LE(first.code(), last.code()); 2498 DCHECK(am == ia || am == ia_w || am == db_w); 2499 DCHECK(!base.is(pc)); 2500 2501 int sd, d; 2502 first.split_code(&sd, &d); 2503 int count = last.code() - first.code() + 1; 2504 DCHECK(count <= 16); 2505 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 2506 0xB*B8 | count*2); 2507} 2508 2509void Assembler::vldm(BlockAddrMode am, 2510 Register base, 2511 SwVfpRegister first, 2512 SwVfpRegister last, 2513 Condition cond) { 2514 // Instruction details available in ARM DDI 0406A, A8-626. 2515 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 2516 // first(15-12) | 1010(11-8) | (count/2) 2517 DCHECK_LE(first.code(), last.code()); 2518 DCHECK(am == ia || am == ia_w || am == db_w); 2519 DCHECK(!base.is(pc)); 2520 2521 int sd, d; 2522 first.split_code(&sd, &d); 2523 int count = last.code() - first.code() + 1; 2524 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 2525 0xA*B8 | count); 2526} 2527 2528 2529void Assembler::vstm(BlockAddrMode am, 2530 Register base, 2531 SwVfpRegister first, 2532 SwVfpRegister last, 2533 Condition cond) { 2534 // Instruction details available in ARM DDI 0406A, A8-784. 2535 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 2536 // first(15-12) | 1011(11-8) | (count/2) 2537 DCHECK_LE(first.code(), last.code()); 2538 DCHECK(am == ia || am == ia_w || am == db_w); 2539 DCHECK(!base.is(pc)); 2540 2541 int sd, d; 2542 first.split_code(&sd, &d); 2543 int count = last.code() - first.code() + 1; 2544 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 2545 0xA*B8 | count); 2546} 2547 2548 2549void Assembler::vmov(const SwVfpRegister dst, float imm) { 2550 mov(ip, Operand(bit_cast<int32_t>(imm))); 2551 vmov(dst, ip); 2552} 2553 2554 2555static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) { 2556 uint64_t i; 2557 memcpy(&i, &d, 8); 2558 2559 *lo = i & 0xffffffff; 2560 *hi = i >> 32; 2561} 2562 2563 2564// Only works for little endian floating point formats. 2565// We don't support VFP on the mixed endian floating point platform. 2566static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) { 2567 DCHECK(CpuFeatures::IsSupported(VFP3)); 2568 2569 // VMOV can accept an immediate of the form: 2570 // 2571 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7 2572 // 2573 // The immediate is encoded using an 8-bit quantity, comprised of two 2574 // 4-bit fields. For an 8-bit immediate of the form: 2575 // 2576 // [abcdefgh] 2577 // 2578 // where a is the MSB and h is the LSB, an immediate 64-bit double can be 2579 // created of the form: 2580 // 2581 // [aBbbbbbb,bbcdefgh,00000000,00000000, 2582 // 00000000,00000000,00000000,00000000] 2583 // 2584 // where B = ~b. 2585 // 2586 2587 uint32_t lo, hi; 2588 DoubleAsTwoUInt32(d, &lo, &hi); 2589 2590 // The most obvious constraint is the long block of zeroes. 2591 if ((lo != 0) || ((hi & 0xffff) != 0)) { 2592 return false; 2593 } 2594 2595 // Bits 62:55 must be all clear or all set. 2596 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) { 2597 return false; 2598 } 2599 2600 // Bit 63 must be NOT bit 62. 2601 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) { 2602 return false; 2603 } 2604 2605 // Create the encoded immediate in the form: 2606 // [00000000,0000abcd,00000000,0000efgh] 2607 *encoding = (hi >> 16) & 0xf; // Low nybble. 2608 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble. 2609 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble. 2610 2611 return true; 2612} 2613 2614 2615void Assembler::vmov(const DwVfpRegister dst, 2616 double imm, 2617 const Register scratch) { 2618 uint32_t enc; 2619 // If the embedded constant pool is disabled, we can use the normal, inline 2620 // constant pool. If the embedded constant pool is enabled (via 2621 // FLAG_enable_embedded_constant_pool), we can only use it where the pool 2622 // pointer (pp) is valid. 2623 bool can_use_pool = 2624 !FLAG_enable_embedded_constant_pool || is_constant_pool_available(); 2625 if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) { 2626 // The double can be encoded in the instruction. 2627 // 2628 // Dd = immediate 2629 // Instruction details available in ARM DDI 0406C.b, A8-936. 2630 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) | 2631 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0) 2632 int vd, d; 2633 dst.split_code(&vd, &d); 2634 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc); 2635 } else if (FLAG_enable_vldr_imm && can_use_pool) { 2636 // TODO(jfb) Temporarily turned off until we have constant blinding or 2637 // some equivalent mitigation: an attacker can otherwise control 2638 // generated data which also happens to be executable, a Very Bad 2639 // Thing indeed. 2640 // Blinding gets tricky because we don't have xor, we probably 2641 // need to add/subtract without losing precision, which requires a 2642 // cookie value that Lithium is probably better positioned to 2643 // choose. 2644 // We could also add a few peepholes here like detecting 0.0 and 2645 // -0.0 and doing a vmov from the sequestered d14, forcing denorms 2646 // to zero (we set flush-to-zero), and normalizing NaN values. 2647 // We could also detect redundant values. 2648 // The code could also randomize the order of values, though 2649 // that's tricky because vldr has a limited reach. Furthermore 2650 // it breaks load locality. 2651 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm); 2652 if (access == ConstantPoolEntry::OVERFLOWED) { 2653 DCHECK(FLAG_enable_embedded_constant_pool); 2654 // Emit instructions to load constant pool offset. 2655 movw(ip, 0); 2656 movt(ip, 0); 2657 // Load from constant pool at offset. 2658 vldr(dst, MemOperand(pp, ip)); 2659 } else { 2660 DCHECK(access == ConstantPoolEntry::REGULAR); 2661 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0)); 2662 } 2663 } else { 2664 // Synthesise the double from ARM immediates. 2665 uint32_t lo, hi; 2666 DoubleAsTwoUInt32(imm, &lo, &hi); 2667 2668 if (lo == hi) { 2669 // Move the low and high parts of the double to a D register in one 2670 // instruction. 2671 mov(ip, Operand(lo)); 2672 vmov(dst, ip, ip); 2673 } else if (scratch.is(no_reg)) { 2674 mov(ip, Operand(lo)); 2675 vmov(dst, VmovIndexLo, ip); 2676 if (((lo & 0xffff) == (hi & 0xffff)) && 2677 CpuFeatures::IsSupported(ARMv7)) { 2678 movt(ip, hi >> 16); 2679 } else { 2680 mov(ip, Operand(hi)); 2681 } 2682 vmov(dst, VmovIndexHi, ip); 2683 } else { 2684 // Move the low and high parts of the double to a D register in one 2685 // instruction. 2686 mov(ip, Operand(lo)); 2687 mov(scratch, Operand(hi)); 2688 vmov(dst, ip, scratch); 2689 } 2690 } 2691} 2692 2693 2694void Assembler::vmov(const SwVfpRegister dst, 2695 const SwVfpRegister src, 2696 const Condition cond) { 2697 // Sd = Sm 2698 // Instruction details available in ARM DDI 0406B, A8-642. 2699 int sd, d, sm, m; 2700 dst.split_code(&sd, &d); 2701 src.split_code(&sm, &m); 2702 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm); 2703} 2704 2705 2706void Assembler::vmov(const DwVfpRegister dst, 2707 const DwVfpRegister src, 2708 const Condition cond) { 2709 // Dd = Dm 2710 // Instruction details available in ARM DDI 0406C.b, A8-938. 2711 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 2712 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2713 int vd, d; 2714 dst.split_code(&vd, &d); 2715 int vm, m; 2716 src.split_code(&vm, &m); 2717 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 | 2718 vm); 2719} 2720 2721 2722void Assembler::vmov(const DwVfpRegister dst, 2723 const VmovIndex index, 2724 const Register src, 2725 const Condition cond) { 2726 // Dd[index] = Rt 2727 // Instruction details available in ARM DDI 0406C.b, A8-940. 2728 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) | 2729 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0) 2730 DCHECK(index.index == 0 || index.index == 1); 2731 int vd, d; 2732 dst.split_code(&vd, &d); 2733 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 | 2734 d*B7 | B4); 2735} 2736 2737 2738void Assembler::vmov(const Register dst, 2739 const VmovIndex index, 2740 const DwVfpRegister src, 2741 const Condition cond) { 2742 // Dd[index] = Rt 2743 // Instruction details available in ARM DDI 0406C.b, A8.8.342. 2744 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) | 2745 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0) 2746 DCHECK(index.index == 0 || index.index == 1); 2747 int vn, n; 2748 src.split_code(&vn, &n); 2749 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 | 2750 0xB*B8 | n*B7 | B4); 2751} 2752 2753 2754void Assembler::vmov(const DwVfpRegister dst, 2755 const Register src1, 2756 const Register src2, 2757 const Condition cond) { 2758 // Dm = <Rt,Rt2>. 2759 // Instruction details available in ARM DDI 0406C.b, A8-948. 2760 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) | 2761 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2762 DCHECK(!src1.is(pc) && !src2.is(pc)); 2763 int vm, m; 2764 dst.split_code(&vm, &m); 2765 emit(cond | 0xC*B24 | B22 | src2.code()*B16 | 2766 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm); 2767} 2768 2769 2770void Assembler::vmov(const Register dst1, 2771 const Register dst2, 2772 const DwVfpRegister src, 2773 const Condition cond) { 2774 // <Rt,Rt2> = Dm. 2775 // Instruction details available in ARM DDI 0406C.b, A8-948. 2776 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) | 2777 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2778 DCHECK(!dst1.is(pc) && !dst2.is(pc)); 2779 int vm, m; 2780 src.split_code(&vm, &m); 2781 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 | 2782 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm); 2783} 2784 2785 2786void Assembler::vmov(const SwVfpRegister dst, 2787 const Register src, 2788 const Condition cond) { 2789 // Sn = Rt. 2790 // Instruction details available in ARM DDI 0406A, A8-642. 2791 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) | 2792 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2793 DCHECK(!src.is(pc)); 2794 int sn, n; 2795 dst.split_code(&sn, &n); 2796 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4); 2797} 2798 2799 2800void Assembler::vmov(const Register dst, 2801 const SwVfpRegister src, 2802 const Condition cond) { 2803 // Rt = Sn. 2804 // Instruction details available in ARM DDI 0406A, A8-642. 2805 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) | 2806 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2807 DCHECK(!dst.is(pc)); 2808 int sn, n; 2809 src.split_code(&sn, &n); 2810 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4); 2811} 2812 2813 2814// Type of data to read from or write to VFP register. 2815// Used as specifier in generic vcvt instruction. 2816enum VFPType { S32, U32, F32, F64 }; 2817 2818 2819static bool IsSignedVFPType(VFPType type) { 2820 switch (type) { 2821 case S32: 2822 return true; 2823 case U32: 2824 return false; 2825 default: 2826 UNREACHABLE(); 2827 return false; 2828 } 2829} 2830 2831 2832static bool IsIntegerVFPType(VFPType type) { 2833 switch (type) { 2834 case S32: 2835 case U32: 2836 return true; 2837 case F32: 2838 case F64: 2839 return false; 2840 default: 2841 UNREACHABLE(); 2842 return false; 2843 } 2844} 2845 2846 2847static bool IsDoubleVFPType(VFPType type) { 2848 switch (type) { 2849 case F32: 2850 return false; 2851 case F64: 2852 return true; 2853 default: 2854 UNREACHABLE(); 2855 return false; 2856 } 2857} 2858 2859 2860// Split five bit reg_code based on size of reg_type. 2861// 32-bit register codes are Vm:M 2862// 64-bit register codes are M:Vm 2863// where Vm is four bits, and M is a single bit. 2864static void SplitRegCode(VFPType reg_type, 2865 int reg_code, 2866 int* vm, 2867 int* m) { 2868 DCHECK((reg_code >= 0) && (reg_code <= 31)); 2869 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) { 2870 // 32 bit type. 2871 *m = reg_code & 0x1; 2872 *vm = reg_code >> 1; 2873 } else { 2874 // 64 bit type. 2875 *m = (reg_code & 0x10) >> 4; 2876 *vm = reg_code & 0x0F; 2877 } 2878} 2879 2880 2881// Encode vcvt.src_type.dst_type instruction. 2882static Instr EncodeVCVT(const VFPType dst_type, 2883 const int dst_code, 2884 const VFPType src_type, 2885 const int src_code, 2886 VFPConversionMode mode, 2887 const Condition cond) { 2888 DCHECK(src_type != dst_type); 2889 int D, Vd, M, Vm; 2890 SplitRegCode(src_type, src_code, &Vm, &M); 2891 SplitRegCode(dst_type, dst_code, &Vd, &D); 2892 2893 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) { 2894 // Conversion between IEEE floating point and 32-bit integer. 2895 // Instruction details available in ARM DDI 0406B, A8.6.295. 2896 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) | 2897 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2898 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type)); 2899 2900 int sz, opc2, op; 2901 2902 if (IsIntegerVFPType(dst_type)) { 2903 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4; 2904 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 2905 op = mode; 2906 } else { 2907 DCHECK(IsIntegerVFPType(src_type)); 2908 opc2 = 0x0; 2909 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0; 2910 op = IsSignedVFPType(src_type) ? 0x1 : 0x0; 2911 } 2912 2913 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 | 2914 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm); 2915 } else { 2916 // Conversion between IEEE double and single precision. 2917 // Instruction details available in ARM DDI 0406B, A8.6.298. 2918 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) | 2919 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2920 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 2921 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 | 2922 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm); 2923 } 2924} 2925 2926 2927void Assembler::vcvt_f64_s32(const DwVfpRegister dst, 2928 const SwVfpRegister src, 2929 VFPConversionMode mode, 2930 const Condition cond) { 2931 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond)); 2932} 2933 2934 2935void Assembler::vcvt_f32_s32(const SwVfpRegister dst, 2936 const SwVfpRegister src, 2937 VFPConversionMode mode, 2938 const Condition cond) { 2939 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond)); 2940} 2941 2942 2943void Assembler::vcvt_f64_u32(const DwVfpRegister dst, 2944 const SwVfpRegister src, 2945 VFPConversionMode mode, 2946 const Condition cond) { 2947 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond)); 2948} 2949 2950 2951void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src, 2952 VFPConversionMode mode, const Condition cond) { 2953 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond)); 2954} 2955 2956 2957void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src, 2958 VFPConversionMode mode, const Condition cond) { 2959 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond)); 2960} 2961 2962 2963void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src, 2964 VFPConversionMode mode, const Condition cond) { 2965 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond)); 2966} 2967 2968 2969void Assembler::vcvt_s32_f64(const SwVfpRegister dst, 2970 const DwVfpRegister src, 2971 VFPConversionMode mode, 2972 const Condition cond) { 2973 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond)); 2974} 2975 2976 2977void Assembler::vcvt_u32_f64(const SwVfpRegister dst, 2978 const DwVfpRegister src, 2979 VFPConversionMode mode, 2980 const Condition cond) { 2981 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond)); 2982} 2983 2984 2985void Assembler::vcvt_f64_f32(const DwVfpRegister dst, 2986 const SwVfpRegister src, 2987 VFPConversionMode mode, 2988 const Condition cond) { 2989 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond)); 2990} 2991 2992 2993void Assembler::vcvt_f32_f64(const SwVfpRegister dst, 2994 const DwVfpRegister src, 2995 VFPConversionMode mode, 2996 const Condition cond) { 2997 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond)); 2998} 2999 3000 3001void Assembler::vcvt_f64_s32(const DwVfpRegister dst, 3002 int fraction_bits, 3003 const Condition cond) { 3004 // Instruction details available in ARM DDI 0406C.b, A8-874. 3005 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) | 3006 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0) 3007 DCHECK(fraction_bits > 0 && fraction_bits <= 32); 3008 DCHECK(CpuFeatures::IsSupported(VFP3)); 3009 int vd, d; 3010 dst.split_code(&vd, &d); 3011 int imm5 = 32 - fraction_bits; 3012 int i = imm5 & 1; 3013 int imm4 = (imm5 >> 1) & 0xf; 3014 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 | 3015 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4); 3016} 3017 3018 3019void Assembler::vneg(const DwVfpRegister dst, 3020 const DwVfpRegister src, 3021 const Condition cond) { 3022 // Instruction details available in ARM DDI 0406C.b, A8-968. 3023 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) | 3024 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3025 int vd, d; 3026 dst.split_code(&vd, &d); 3027 int vm, m; 3028 src.split_code(&vm, &m); 3029 3030 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 | 3031 m*B5 | vm); 3032} 3033 3034 3035void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src, 3036 const Condition cond) { 3037 // Instruction details available in ARM DDI 0406C.b, A8-968. 3038 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) | 3039 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3040 int vd, d; 3041 dst.split_code(&vd, &d); 3042 int vm, m; 3043 src.split_code(&vm, &m); 3044 3045 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 | 3046 B6 | m * B5 | vm); 3047} 3048 3049 3050void Assembler::vabs(const DwVfpRegister dst, 3051 const DwVfpRegister src, 3052 const Condition cond) { 3053 // Instruction details available in ARM DDI 0406C.b, A8-524. 3054 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 3055 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3056 int vd, d; 3057 dst.split_code(&vd, &d); 3058 int vm, m; 3059 src.split_code(&vm, &m); 3060 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 | 3061 m*B5 | vm); 3062} 3063 3064 3065void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src, 3066 const Condition cond) { 3067 // Instruction details available in ARM DDI 0406C.b, A8-524. 3068 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 3069 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3070 int vd, d; 3071 dst.split_code(&vd, &d); 3072 int vm, m; 3073 src.split_code(&vm, &m); 3074 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 | 3075 m * B5 | vm); 3076} 3077 3078 3079void Assembler::vadd(const DwVfpRegister dst, 3080 const DwVfpRegister src1, 3081 const DwVfpRegister src2, 3082 const Condition cond) { 3083 // Dd = vadd(Dn, Dm) double precision floating point addition. 3084 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3085 // Instruction details available in ARM DDI 0406C.b, A8-830. 3086 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3087 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3088 int vd, d; 3089 dst.split_code(&vd, &d); 3090 int vn, n; 3091 src1.split_code(&vn, &n); 3092 int vm, m; 3093 src2.split_code(&vm, &m); 3094 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3095 n*B7 | m*B5 | vm); 3096} 3097 3098 3099void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1, 3100 const SwVfpRegister src2, const Condition cond) { 3101 // Sd = vadd(Sn, Sm) single precision floating point addition. 3102 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3103 // Instruction details available in ARM DDI 0406C.b, A8-830. 3104 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3105 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3106 int vd, d; 3107 dst.split_code(&vd, &d); 3108 int vn, n; 3109 src1.split_code(&vn, &n); 3110 int vm, m; 3111 src2.split_code(&vm, &m); 3112 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 3113 0x5 * B9 | n * B7 | m * B5 | vm); 3114} 3115 3116 3117void Assembler::vsub(const DwVfpRegister dst, 3118 const DwVfpRegister src1, 3119 const DwVfpRegister src2, 3120 const Condition cond) { 3121 // Dd = vsub(Dn, Dm) double precision floating point subtraction. 3122 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3123 // Instruction details available in ARM DDI 0406C.b, A8-1086. 3124 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3125 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3126 int vd, d; 3127 dst.split_code(&vd, &d); 3128 int vn, n; 3129 src1.split_code(&vn, &n); 3130 int vm, m; 3131 src2.split_code(&vm, &m); 3132 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3133 n*B7 | B6 | m*B5 | vm); 3134} 3135 3136 3137void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1, 3138 const SwVfpRegister src2, const Condition cond) { 3139 // Sd = vsub(Sn, Sm) single precision floating point subtraction. 3140 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3141 // Instruction details available in ARM DDI 0406C.b, A8-1086. 3142 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3143 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3144 int vd, d; 3145 dst.split_code(&vd, &d); 3146 int vn, n; 3147 src1.split_code(&vn, &n); 3148 int vm, m; 3149 src2.split_code(&vm, &m); 3150 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 3151 0x5 * B9 | n * B7 | B6 | m * B5 | vm); 3152} 3153 3154 3155void Assembler::vmul(const DwVfpRegister dst, 3156 const DwVfpRegister src1, 3157 const DwVfpRegister src2, 3158 const Condition cond) { 3159 // Dd = vmul(Dn, Dm) double precision floating point multiplication. 3160 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3161 // Instruction details available in ARM DDI 0406C.b, A8-960. 3162 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) | 3163 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3164 int vd, d; 3165 dst.split_code(&vd, &d); 3166 int vn, n; 3167 src1.split_code(&vn, &n); 3168 int vm, m; 3169 src2.split_code(&vm, &m); 3170 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3171 n*B7 | m*B5 | vm); 3172} 3173 3174 3175void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1, 3176 const SwVfpRegister src2, const Condition cond) { 3177 // Sd = vmul(Sn, Sm) single precision floating point multiplication. 3178 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3179 // Instruction details available in ARM DDI 0406C.b, A8-960. 3180 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) | 3181 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3182 int vd, d; 3183 dst.split_code(&vd, &d); 3184 int vn, n; 3185 src1.split_code(&vn, &n); 3186 int vm, m; 3187 src2.split_code(&vm, &m); 3188 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 | 3189 0x5 * B9 | n * B7 | m * B5 | vm); 3190} 3191 3192 3193void Assembler::vmla(const DwVfpRegister dst, 3194 const DwVfpRegister src1, 3195 const DwVfpRegister src2, 3196 const Condition cond) { 3197 // Instruction details available in ARM DDI 0406C.b, A8-932. 3198 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3199 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0) 3200 int vd, d; 3201 dst.split_code(&vd, &d); 3202 int vn, n; 3203 src1.split_code(&vn, &n); 3204 int vm, m; 3205 src2.split_code(&vm, &m); 3206 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 | 3207 vm); 3208} 3209 3210 3211void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1, 3212 const SwVfpRegister src2, const Condition cond) { 3213 // Instruction details available in ARM DDI 0406C.b, A8-932. 3214 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3215 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0) 3216 int vd, d; 3217 dst.split_code(&vd, &d); 3218 int vn, n; 3219 src1.split_code(&vn, &n); 3220 int vm, m; 3221 src2.split_code(&vm, &m); 3222 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3223 m * B5 | vm); 3224} 3225 3226 3227void Assembler::vmls(const DwVfpRegister dst, 3228 const DwVfpRegister src1, 3229 const DwVfpRegister src2, 3230 const Condition cond) { 3231 // Instruction details available in ARM DDI 0406C.b, A8-932. 3232 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3233 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0) 3234 int vd, d; 3235 dst.split_code(&vd, &d); 3236 int vn, n; 3237 src1.split_code(&vn, &n); 3238 int vm, m; 3239 src2.split_code(&vm, &m); 3240 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 | 3241 m*B5 | vm); 3242} 3243 3244 3245void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1, 3246 const SwVfpRegister src2, const Condition cond) { 3247 // Instruction details available in ARM DDI 0406C.b, A8-932. 3248 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3249 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0) 3250 int vd, d; 3251 dst.split_code(&vd, &d); 3252 int vn, n; 3253 src1.split_code(&vn, &n); 3254 int vm, m; 3255 src2.split_code(&vm, &m); 3256 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3257 B6 | m * B5 | vm); 3258} 3259 3260 3261void Assembler::vdiv(const DwVfpRegister dst, 3262 const DwVfpRegister src1, 3263 const DwVfpRegister src2, 3264 const Condition cond) { 3265 // Dd = vdiv(Dn, Dm) double precision floating point division. 3266 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3267 // Instruction details available in ARM DDI 0406C.b, A8-882. 3268 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) | 3269 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3270 int vd, d; 3271 dst.split_code(&vd, &d); 3272 int vn, n; 3273 src1.split_code(&vn, &n); 3274 int vm, m; 3275 src2.split_code(&vm, &m); 3276 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 | 3277 vm); 3278} 3279 3280 3281void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1, 3282 const SwVfpRegister src2, const Condition cond) { 3283 // Sd = vdiv(Sn, Sm) single precision floating point division. 3284 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3285 // Instruction details available in ARM DDI 0406C.b, A8-882. 3286 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) | 3287 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3288 int vd, d; 3289 dst.split_code(&vd, &d); 3290 int vn, n; 3291 src1.split_code(&vn, &n); 3292 int vm, m; 3293 src2.split_code(&vm, &m); 3294 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3295 m * B5 | vm); 3296} 3297 3298 3299void Assembler::vcmp(const DwVfpRegister src1, 3300 const DwVfpRegister src2, 3301 const Condition cond) { 3302 // vcmp(Dd, Dm) double precision floating point comparison. 3303 // Instruction details available in ARM DDI 0406C.b, A8-864. 3304 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) | 3305 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3306 int vd, d; 3307 src1.split_code(&vd, &d); 3308 int vm, m; 3309 src2.split_code(&vm, &m); 3310 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 | 3311 m*B5 | vm); 3312} 3313 3314 3315void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2, 3316 const Condition cond) { 3317 // vcmp(Sd, Sm) single precision floating point comparison. 3318 // Instruction details available in ARM DDI 0406C.b, A8-864. 3319 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) | 3320 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3321 int vd, d; 3322 src1.split_code(&vd, &d); 3323 int vm, m; 3324 src2.split_code(&vm, &m); 3325 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 | 3326 0x5 * B9 | B6 | m * B5 | vm); 3327} 3328 3329 3330void Assembler::vcmp(const DwVfpRegister src1, 3331 const double src2, 3332 const Condition cond) { 3333 // vcmp(Dd, #0.0) double precision floating point comparison. 3334 // Instruction details available in ARM DDI 0406C.b, A8-864. 3335 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) | 3336 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0) 3337 DCHECK(src2 == 0.0); 3338 int vd, d; 3339 src1.split_code(&vd, &d); 3340 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6); 3341} 3342 3343 3344void Assembler::vcmp(const SwVfpRegister src1, const float src2, 3345 const Condition cond) { 3346 // vcmp(Sd, #0.0) single precision floating point comparison. 3347 // Instruction details available in ARM DDI 0406C.b, A8-864. 3348 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) | 3349 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0) 3350 DCHECK(src2 == 0.0); 3351 int vd, d; 3352 src1.split_code(&vd, &d); 3353 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 | 3354 0x5 * B9 | B6); 3355} 3356 3357 3358void Assembler::vsqrt(const DwVfpRegister dst, 3359 const DwVfpRegister src, 3360 const Condition cond) { 3361 // Instruction details available in ARM DDI 0406C.b, A8-1058. 3362 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) | 3363 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0) 3364 int vd, d; 3365 dst.split_code(&vd, &d); 3366 int vm, m; 3367 src.split_code(&vm, &m); 3368 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 | 3369 m*B5 | vm); 3370} 3371 3372 3373void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src, 3374 const Condition cond) { 3375 // Instruction details available in ARM DDI 0406C.b, A8-1058. 3376 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) | 3377 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0) 3378 int vd, d; 3379 dst.split_code(&vd, &d); 3380 int vm, m; 3381 src.split_code(&vm, &m); 3382 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 | 3383 0x3 * B6 | m * B5 | vm); 3384} 3385 3386 3387void Assembler::vmsr(Register dst, Condition cond) { 3388 // Instruction details available in ARM DDI 0406A, A8-652. 3389 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) | 3390 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 3391 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4); 3392} 3393 3394 3395void Assembler::vmrs(Register dst, Condition cond) { 3396 // Instruction details available in ARM DDI 0406A, A8-652. 3397 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) | 3398 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 3399 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4); 3400} 3401 3402 3403void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) { 3404 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3405 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3406 // M(5) | 0(4) | Vm(3-0) 3407 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3408 int vd, d; 3409 dst.split_code(&vd, &d); 3410 int vm, m; 3411 src.split_code(&vm, &m); 3412 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 | 3413 0x5 * B9 | B6 | m * B5 | vm); 3414} 3415 3416 3417void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) { 3418 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3419 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3420 // M(5) | 0(4) | Vm(3-0) 3421 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3422 int vd, d; 3423 dst.split_code(&vd, &d); 3424 int vm, m; 3425 src.split_code(&vm, &m); 3426 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 | 3427 0x5 * B9 | B8 | B6 | m * B5 | vm); 3428} 3429 3430 3431void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) { 3432 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3433 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3434 // M(5) | 0(4) | Vm(3-0) 3435 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3436 int vd, d; 3437 dst.split_code(&vd, &d); 3438 int vm, m; 3439 src.split_code(&vm, &m); 3440 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 | 3441 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3442} 3443 3444 3445void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) { 3446 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3447 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3448 // M(5) | 0(4) | Vm(3-0) 3449 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3450 int vd, d; 3451 dst.split_code(&vd, &d); 3452 int vm, m; 3453 src.split_code(&vm, &m); 3454 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 | 3455 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3456} 3457 3458 3459void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) { 3460 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3461 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3462 // M(5) | 0(4) | Vm(3-0) 3463 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3464 int vd, d; 3465 dst.split_code(&vd, &d); 3466 int vm, m; 3467 src.split_code(&vm, &m); 3468 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 | 3469 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3470} 3471 3472 3473void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) { 3474 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3475 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3476 // M(5) | 0(4) | Vm(3-0) 3477 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3478 int vd, d; 3479 dst.split_code(&vd, &d); 3480 int vm, m; 3481 src.split_code(&vm, &m); 3482 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 | 3483 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3484} 3485 3486 3487void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) { 3488 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3489 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3490 // M(5) | 0(4) | Vm(3-0) 3491 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3492 int vd, d; 3493 dst.split_code(&vd, &d); 3494 int vm, m; 3495 src.split_code(&vm, &m); 3496 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 | 3497 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3498} 3499 3500 3501void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) { 3502 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3503 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3504 // M(5) | 0(4) | Vm(3-0) 3505 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3506 int vd, d; 3507 dst.split_code(&vd, &d); 3508 int vm, m; 3509 src.split_code(&vm, &m); 3510 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 | 3511 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3512} 3513 3514 3515void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src, 3516 const Condition cond) { 3517 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) | 3518 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3519 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3520 int vd, d; 3521 dst.split_code(&vd, &d); 3522 int vm, m; 3523 src.split_code(&vm, &m); 3524 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 | 3525 0x5 * B9 | B7 | B6 | m * B5 | vm); 3526} 3527 3528 3529void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src, 3530 const Condition cond) { 3531 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) | 3532 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3533 DCHECK(CpuFeatures::IsSupported(ARMv8)); 3534 int vd, d; 3535 dst.split_code(&vd, &d); 3536 int vm, m; 3537 src.split_code(&vm, &m); 3538 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 | 3539 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm); 3540} 3541 3542 3543// Support for NEON. 3544 3545void Assembler::vld1(NeonSize size, 3546 const NeonListOperand& dst, 3547 const NeonMemOperand& src) { 3548 // Instruction details available in ARM DDI 0406C.b, A8.8.320. 3549 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) | 3550 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0) 3551 DCHECK(CpuFeatures::IsSupported(NEON)); 3552 int vd, d; 3553 dst.base().split_code(&vd, &d); 3554 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 | 3555 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code()); 3556} 3557 3558 3559void Assembler::vst1(NeonSize size, 3560 const NeonListOperand& src, 3561 const NeonMemOperand& dst) { 3562 // Instruction details available in ARM DDI 0406C.b, A8.8.404. 3563 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) | 3564 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0) 3565 DCHECK(CpuFeatures::IsSupported(NEON)); 3566 int vd, d; 3567 src.base().split_code(&vd, &d); 3568 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 | 3569 size*B6 | dst.align()*B4 | dst.rm().code()); 3570} 3571 3572 3573void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) { 3574 // Instruction details available in ARM DDI 0406C.b, A8.8.346. 3575 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) | 3576 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0) 3577 DCHECK(CpuFeatures::IsSupported(NEON)); 3578 int vd, d; 3579 dst.split_code(&vd, &d); 3580 int vm, m; 3581 src.split_code(&vm, &m); 3582 emit(0xFU*B28 | B25 | (dt & NeonDataTypeUMask) | B23 | d*B22 | 3583 (dt & NeonDataTypeSizeMask)*B19 | vd*B12 | 0xA*B8 | m*B5 | B4 | vm); 3584} 3585 3586 3587// Pseudo instructions. 3588void Assembler::nop(int type) { 3589 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes 3590 // some of the CPU's pipeline and has to issue. Older ARM chips simply used 3591 // MOV Rx, Rx as NOP and it performs better even in newer CPUs. 3592 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode 3593 // a type. 3594 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop. 3595 emit(al | 13*B21 | type*B12 | type); 3596} 3597 3598 3599bool Assembler::IsMovT(Instr instr) { 3600 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions 3601 ((kNumRegisters-1)*B12) | // mask out register 3602 EncodeMovwImmediate(0xFFFF)); // mask out immediate value 3603 return instr == kMovtPattern; 3604} 3605 3606 3607bool Assembler::IsMovW(Instr instr) { 3608 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions 3609 ((kNumRegisters-1)*B12) | // mask out destination 3610 EncodeMovwImmediate(0xFFFF)); // mask out immediate value 3611 return instr == kMovwPattern; 3612} 3613 3614 3615Instr Assembler::GetMovTPattern() { return kMovtPattern; } 3616 3617 3618Instr Assembler::GetMovWPattern() { return kMovwPattern; } 3619 3620 3621Instr Assembler::EncodeMovwImmediate(uint32_t immediate) { 3622 DCHECK(immediate < 0x10000); 3623 return ((immediate & 0xf000) << 4) | (immediate & 0xfff); 3624} 3625 3626 3627Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) { 3628 instruction &= ~EncodeMovwImmediate(0xffff); 3629 return instruction | EncodeMovwImmediate(immediate); 3630} 3631 3632 3633int Assembler::DecodeShiftImm(Instr instr) { 3634 int rotate = Instruction::RotateValue(instr) * 2; 3635 int immed8 = Instruction::Immed8Value(instr); 3636 return base::bits::RotateRight32(immed8, rotate); 3637} 3638 3639 3640Instr Assembler::PatchShiftImm(Instr instr, int immed) { 3641 uint32_t rotate_imm = 0; 3642 uint32_t immed_8 = 0; 3643 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL); 3644 DCHECK(immed_fits); 3645 USE(immed_fits); 3646 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8; 3647} 3648 3649 3650bool Assembler::IsNop(Instr instr, int type) { 3651 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop. 3652 // Check for mov rx, rx where x = type. 3653 return instr == (al | 13*B21 | type*B12 | type); 3654} 3655 3656 3657bool Assembler::IsMovImmed(Instr instr) { 3658 return (instr & kMovImmedMask) == kMovImmedPattern; 3659} 3660 3661 3662bool Assembler::IsOrrImmed(Instr instr) { 3663 return (instr & kOrrImmedMask) == kOrrImmedPattern; 3664} 3665 3666 3667// static 3668bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { 3669 uint32_t dummy1; 3670 uint32_t dummy2; 3671 return fits_shifter(imm32, &dummy1, &dummy2, NULL); 3672} 3673 3674 3675bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) { 3676 return is_uint12(abs(imm32)); 3677} 3678 3679 3680// Debugging. 3681void Assembler::RecordConstPool(int size) { 3682 // We only need this for debugger support, to correctly compute offsets in the 3683 // code. 3684 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size)); 3685} 3686 3687 3688void Assembler::GrowBuffer() { 3689 if (!own_buffer_) FATAL("external code buffer is too small"); 3690 3691 // Compute new buffer size. 3692 CodeDesc desc; // the new buffer 3693 if (buffer_size_ < 1 * MB) { 3694 desc.buffer_size = 2*buffer_size_; 3695 } else { 3696 desc.buffer_size = buffer_size_ + 1*MB; 3697 } 3698 CHECK_GT(desc.buffer_size, 0); // no overflow 3699 3700 // Set up new buffer. 3701 desc.buffer = NewArray<byte>(desc.buffer_size); 3702 3703 desc.instr_size = pc_offset(); 3704 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 3705 desc.origin = this; 3706 3707 // Copy the data. 3708 int pc_delta = desc.buffer - buffer_; 3709 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); 3710 MemMove(desc.buffer, buffer_, desc.instr_size); 3711 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), 3712 desc.reloc_size); 3713 3714 // Switch buffers. 3715 DeleteArray(buffer_); 3716 buffer_ = desc.buffer; 3717 buffer_size_ = desc.buffer_size; 3718 pc_ += pc_delta; 3719 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 3720 reloc_info_writer.last_pc() + pc_delta); 3721 3722 // None of our relocation types are pc relative pointing outside the code 3723 // buffer nor pc absolute pointing inside the code buffer, so there is no need 3724 // to relocate any emitted relocation entries. 3725} 3726 3727 3728void Assembler::db(uint8_t data) { 3729 // db is used to write raw data. The constant pool should be emitted or 3730 // blocked before using db. 3731 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0)); 3732 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0)); 3733 CheckBuffer(); 3734 *reinterpret_cast<uint8_t*>(pc_) = data; 3735 pc_ += sizeof(uint8_t); 3736} 3737 3738 3739void Assembler::dd(uint32_t data) { 3740 // dd is used to write raw data. The constant pool should be emitted or 3741 // blocked before using dd. 3742 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0)); 3743 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0)); 3744 CheckBuffer(); 3745 *reinterpret_cast<uint32_t*>(pc_) = data; 3746 pc_ += sizeof(uint32_t); 3747} 3748 3749 3750void Assembler::dq(uint64_t value) { 3751 // dq is used to write raw data. The constant pool should be emitted or 3752 // blocked before using dq. 3753 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0)); 3754 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0)); 3755 CheckBuffer(); 3756 *reinterpret_cast<uint64_t*>(pc_) = value; 3757 pc_ += sizeof(uint64_t); 3758} 3759 3760 3761void Assembler::emit_code_stub_address(Code* stub) { 3762 CheckBuffer(); 3763 *reinterpret_cast<uint32_t*>(pc_) = 3764 reinterpret_cast<uint32_t>(stub->instruction_start()); 3765 pc_ += sizeof(uint32_t); 3766} 3767 3768 3769void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 3770 if (RelocInfo::IsNone(rmode) || 3771 // Don't record external references unless the heap will be serialized. 3772 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() && 3773 !emit_debug_code())) { 3774 return; 3775 } 3776 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here 3777 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { 3778 data = RecordedAstId().ToInt(); 3779 ClearRecordedAstId(); 3780 } 3781 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL); 3782 reloc_info_writer.Write(&rinfo); 3783} 3784 3785 3786ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, 3787 RelocInfo::Mode rmode, 3788 intptr_t value) { 3789 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION && 3790 rmode != RelocInfo::STATEMENT_POSITION && 3791 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64); 3792 bool sharing_ok = RelocInfo::IsNone(rmode) || 3793 !(serializer_enabled() || rmode < RelocInfo::CELL); 3794 if (FLAG_enable_embedded_constant_pool) { 3795 return constant_pool_builder_.AddEntry(position, value, sharing_ok); 3796 } else { 3797 DCHECK(num_pending_32_bit_constants_ < kMaxNumPending32Constants); 3798 if (num_pending_32_bit_constants_ == 0) { 3799 first_const_pool_32_use_ = position; 3800 } else if (num_pending_32_bit_constants_ == kMinNumPendingConstants && 3801 pending_32_bit_constants_ == 3802 &pending_32_bit_constants_buffer_[0]) { 3803 // Inline buffer is full, switch to dynamically allocated buffer. 3804 pending_32_bit_constants_ = 3805 new ConstantPoolEntry[kMaxNumPending32Constants]; 3806 std::copy(&pending_32_bit_constants_buffer_[0], 3807 &pending_32_bit_constants_buffer_[kMinNumPendingConstants], 3808 &pending_32_bit_constants_[0]); 3809 } 3810 ConstantPoolEntry entry(position, value, sharing_ok); 3811 pending_32_bit_constants_[num_pending_32_bit_constants_++] = entry; 3812 3813 // Make sure the constant pool is not emitted in place of the next 3814 // instruction for which we just recorded relocation info. 3815 BlockConstPoolFor(1); 3816 return ConstantPoolEntry::REGULAR; 3817 } 3818} 3819 3820 3821ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, 3822 double value) { 3823 if (FLAG_enable_embedded_constant_pool) { 3824 return constant_pool_builder_.AddEntry(position, value); 3825 } else { 3826 DCHECK(num_pending_64_bit_constants_ < kMaxNumPending64Constants); 3827 if (num_pending_64_bit_constants_ == 0) { 3828 first_const_pool_64_use_ = position; 3829 } else if (num_pending_64_bit_constants_ == kMinNumPendingConstants && 3830 pending_64_bit_constants_ == 3831 &pending_64_bit_constants_buffer_[0]) { 3832 // Inline buffer is full, switch to dynamically allocated buffer. 3833 pending_64_bit_constants_ = 3834 new ConstantPoolEntry[kMaxNumPending64Constants]; 3835 std::copy(&pending_64_bit_constants_buffer_[0], 3836 &pending_64_bit_constants_buffer_[kMinNumPendingConstants], 3837 &pending_64_bit_constants_[0]); 3838 } 3839 ConstantPoolEntry entry(position, value); 3840 pending_64_bit_constants_[num_pending_64_bit_constants_++] = entry; 3841 3842 // Make sure the constant pool is not emitted in place of the next 3843 // instruction for which we just recorded relocation info. 3844 BlockConstPoolFor(1); 3845 return ConstantPoolEntry::REGULAR; 3846 } 3847} 3848 3849 3850void Assembler::BlockConstPoolFor(int instructions) { 3851 if (FLAG_enable_embedded_constant_pool) { 3852 // Should be a no-op if using an embedded constant pool. 3853 DCHECK(num_pending_32_bit_constants_ == 0); 3854 DCHECK(num_pending_64_bit_constants_ == 0); 3855 return; 3856 } 3857 3858 int pc_limit = pc_offset() + instructions * kInstrSize; 3859 if (no_const_pool_before_ < pc_limit) { 3860 // Max pool start (if we need a jump and an alignment). 3861#ifdef DEBUG 3862 int start = pc_limit + kInstrSize + 2 * kPointerSize; 3863 DCHECK((num_pending_32_bit_constants_ == 0) || 3864 (start - first_const_pool_32_use_ + 3865 num_pending_64_bit_constants_ * kDoubleSize < 3866 kMaxDistToIntPool)); 3867 DCHECK((num_pending_64_bit_constants_ == 0) || 3868 (start - first_const_pool_64_use_ < kMaxDistToFPPool)); 3869#endif 3870 no_const_pool_before_ = pc_limit; 3871 } 3872 3873 if (next_buffer_check_ < no_const_pool_before_) { 3874 next_buffer_check_ = no_const_pool_before_; 3875 } 3876} 3877 3878 3879void Assembler::CheckConstPool(bool force_emit, bool require_jump) { 3880 if (FLAG_enable_embedded_constant_pool) { 3881 // Should be a no-op if using an embedded constant pool. 3882 DCHECK(num_pending_32_bit_constants_ == 0); 3883 DCHECK(num_pending_64_bit_constants_ == 0); 3884 return; 3885 } 3886 3887 // Some short sequence of instruction mustn't be broken up by constant pool 3888 // emission, such sequences are protected by calls to BlockConstPoolFor and 3889 // BlockConstPoolScope. 3890 if (is_const_pool_blocked()) { 3891 // Something is wrong if emission is forced and blocked at the same time. 3892 DCHECK(!force_emit); 3893 return; 3894 } 3895 3896 // There is nothing to do if there are no pending constant pool entries. 3897 if ((num_pending_32_bit_constants_ == 0) && 3898 (num_pending_64_bit_constants_ == 0)) { 3899 // Calculate the offset of the next check. 3900 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 3901 return; 3902 } 3903 3904 // Check that the code buffer is large enough before emitting the constant 3905 // pool (include the jump over the pool and the constant pool marker and 3906 // the gap to the relocation information). 3907 int jump_instr = require_jump ? kInstrSize : 0; 3908 int size_up_to_marker = jump_instr + kInstrSize; 3909 int estimated_size_after_marker = 3910 num_pending_32_bit_constants_ * kPointerSize; 3911 bool has_int_values = (num_pending_32_bit_constants_ > 0); 3912 bool has_fp_values = (num_pending_64_bit_constants_ > 0); 3913 bool require_64_bit_align = false; 3914 if (has_fp_values) { 3915 require_64_bit_align = 3916 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker), 3917 kDoubleAlignment); 3918 if (require_64_bit_align) { 3919 estimated_size_after_marker += kInstrSize; 3920 } 3921 estimated_size_after_marker += num_pending_64_bit_constants_ * kDoubleSize; 3922 } 3923 int estimated_size = size_up_to_marker + estimated_size_after_marker; 3924 3925 // We emit a constant pool when: 3926 // * requested to do so by parameter force_emit (e.g. after each function). 3927 // * the distance from the first instruction accessing the constant pool to 3928 // any of the constant pool entries will exceed its limit the next 3929 // time the pool is checked. This is overly restrictive, but we don't emit 3930 // constant pool entries in-order so it's conservatively correct. 3931 // * the instruction doesn't require a jump after itself to jump over the 3932 // constant pool, and we're getting close to running out of range. 3933 if (!force_emit) { 3934 DCHECK(has_fp_values || has_int_values); 3935 bool need_emit = false; 3936 if (has_fp_values) { 3937 // The 64-bit constants are always emitted before the 32-bit constants, so 3938 // we can ignore the effect of the 32-bit constants on estimated_size. 3939 int dist64 = pc_offset() + estimated_size - 3940 num_pending_32_bit_constants_ * kPointerSize - 3941 first_const_pool_64_use_; 3942 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) || 3943 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) { 3944 need_emit = true; 3945 } 3946 } 3947 if (has_int_values) { 3948 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_; 3949 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) || 3950 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) { 3951 need_emit = true; 3952 } 3953 } 3954 if (!need_emit) return; 3955 } 3956 3957 // Deduplicate constants. 3958 int size_after_marker = estimated_size_after_marker; 3959 for (int i = 0; i < num_pending_64_bit_constants_; i++) { 3960 ConstantPoolEntry& entry = pending_64_bit_constants_[i]; 3961 DCHECK(!entry.is_merged()); 3962 for (int j = 0; j < i; j++) { 3963 if (entry.value64() == pending_64_bit_constants_[j].value64()) { 3964 DCHECK(!pending_64_bit_constants_[j].is_merged()); 3965 entry.set_merged_index(j); 3966 size_after_marker -= kDoubleSize; 3967 break; 3968 } 3969 } 3970 } 3971 3972 for (int i = 0; i < num_pending_32_bit_constants_; i++) { 3973 ConstantPoolEntry& entry = pending_32_bit_constants_[i]; 3974 DCHECK(!entry.is_merged()); 3975 if (!entry.sharing_ok()) continue; 3976 for (int j = 0; j < i; j++) { 3977 if (entry.value() == pending_32_bit_constants_[j].value()) { 3978 DCHECK(!pending_32_bit_constants_[j].is_merged()); 3979 entry.set_merged_index(j); 3980 size_after_marker -= kPointerSize; 3981 break; 3982 } 3983 } 3984 } 3985 3986 int size = size_up_to_marker + size_after_marker; 3987 3988 int needed_space = size + kGap; 3989 while (buffer_space() <= needed_space) GrowBuffer(); 3990 3991 { 3992 // Block recursive calls to CheckConstPool. 3993 BlockConstPoolScope block_const_pool(this); 3994 RecordComment("[ Constant Pool"); 3995 RecordConstPool(size); 3996 3997 Label size_check; 3998 bind(&size_check); 3999 4000 // Emit jump over constant pool if necessary. 4001 Label after_pool; 4002 if (require_jump) { 4003 b(&after_pool); 4004 } 4005 4006 // Put down constant pool marker "Undefined instruction". 4007 // The data size helps disassembly know what to print. 4008 emit(kConstantPoolMarker | 4009 EncodeConstantPoolLength(size_after_marker / kPointerSize)); 4010 4011 if (require_64_bit_align) { 4012 emit(kConstantPoolMarker); 4013 } 4014 4015 // Emit 64-bit constant pool entries first: their range is smaller than 4016 // 32-bit entries. 4017 for (int i = 0; i < num_pending_64_bit_constants_; i++) { 4018 ConstantPoolEntry& entry = pending_64_bit_constants_[i]; 4019 4020 Instr instr = instr_at(entry.position()); 4021 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0. 4022 DCHECK((IsVldrDPcImmediateOffset(instr) && 4023 GetVldrDRegisterImmediateOffset(instr) == 0)); 4024 4025 int delta = pc_offset() - entry.position() - kPcLoadDelta; 4026 DCHECK(is_uint10(delta)); 4027 4028 if (entry.is_merged()) { 4029 ConstantPoolEntry& merged = 4030 pending_64_bit_constants_[entry.merged_index()]; 4031 DCHECK(entry.value64() == merged.value64()); 4032 Instr merged_instr = instr_at(merged.position()); 4033 DCHECK(IsVldrDPcImmediateOffset(merged_instr)); 4034 delta = GetVldrDRegisterImmediateOffset(merged_instr); 4035 delta += merged.position() - entry.position(); 4036 } 4037 instr_at_put(entry.position(), 4038 SetVldrDRegisterImmediateOffset(instr, delta)); 4039 if (!entry.is_merged()) { 4040 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment)); 4041 dq(entry.value64()); 4042 } 4043 } 4044 4045 // Emit 32-bit constant pool entries. 4046 for (int i = 0; i < num_pending_32_bit_constants_; i++) { 4047 ConstantPoolEntry& entry = pending_32_bit_constants_[i]; 4048 Instr instr = instr_at(entry.position()); 4049 4050 // 64-bit loads shouldn't get here. 4051 DCHECK(!IsVldrDPcImmediateOffset(instr)); 4052 DCHECK(!IsMovW(instr)); 4053 DCHECK(IsLdrPcImmediateOffset(instr) && 4054 GetLdrRegisterImmediateOffset(instr) == 0); 4055 4056 int delta = pc_offset() - entry.position() - kPcLoadDelta; 4057 DCHECK(is_uint12(delta)); 4058 // 0 is the smallest delta: 4059 // ldr rd, [pc, #0] 4060 // constant pool marker 4061 // data 4062 4063 if (entry.is_merged()) { 4064 DCHECK(entry.sharing_ok()); 4065 ConstantPoolEntry& merged = 4066 pending_32_bit_constants_[entry.merged_index()]; 4067 DCHECK(entry.value() == merged.value()); 4068 Instr merged_instr = instr_at(merged.position()); 4069 DCHECK(IsLdrPcImmediateOffset(merged_instr)); 4070 delta = GetLdrRegisterImmediateOffset(merged_instr); 4071 delta += merged.position() - entry.position(); 4072 } 4073 instr_at_put(entry.position(), 4074 SetLdrRegisterImmediateOffset(instr, delta)); 4075 if (!entry.is_merged()) { 4076 emit(entry.value()); 4077 } 4078 } 4079 4080 num_pending_32_bit_constants_ = 0; 4081 num_pending_64_bit_constants_ = 0; 4082 first_const_pool_32_use_ = -1; 4083 first_const_pool_64_use_ = -1; 4084 4085 RecordComment("]"); 4086 4087 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check)); 4088 4089 if (after_pool.is_linked()) { 4090 bind(&after_pool); 4091 } 4092 } 4093 4094 // Since a constant pool was just emitted, move the check offset forward by 4095 // the standard interval. 4096 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 4097} 4098 4099 4100void Assembler::PatchConstantPoolAccessInstruction( 4101 int pc_offset, int offset, ConstantPoolEntry::Access access, 4102 ConstantPoolEntry::Type type) { 4103 DCHECK(FLAG_enable_embedded_constant_pool); 4104 Address pc = buffer_ + pc_offset; 4105 4106 // Patch vldr/ldr instruction with correct offset. 4107 Instr instr = instr_at(pc); 4108 if (access == ConstantPoolEntry::OVERFLOWED) { 4109 if (CpuFeatures::IsSupported(ARMv7)) { 4110 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0]. 4111 Instr next_instr = instr_at(pc + kInstrSize); 4112 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0)); 4113 DCHECK((IsMovT(next_instr) && 4114 Instruction::ImmedMovwMovtValue(next_instr) == 0)); 4115 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff)); 4116 instr_at_put(pc + kInstrSize, 4117 PatchMovwImmediate(next_instr, offset >> 16)); 4118 } else { 4119 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0]. 4120 Instr instr_2 = instr_at(pc + kInstrSize); 4121 Instr instr_3 = instr_at(pc + 2 * kInstrSize); 4122 Instr instr_4 = instr_at(pc + 3 * kInstrSize); 4123 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0)); 4124 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) && 4125 GetRn(instr_2).is(GetRd(instr_2))); 4126 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) && 4127 GetRn(instr_3).is(GetRd(instr_3))); 4128 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) && 4129 GetRn(instr_4).is(GetRd(instr_4))); 4130 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask))); 4131 instr_at_put(pc + kInstrSize, 4132 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8)))); 4133 instr_at_put(pc + 2 * kInstrSize, 4134 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16)))); 4135 instr_at_put(pc + 3 * kInstrSize, 4136 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24)))); 4137 } 4138 } else if (type == ConstantPoolEntry::DOUBLE) { 4139 // Instruction to patch must be 'vldr rd, [pp, #0]'. 4140 DCHECK((IsVldrDPpImmediateOffset(instr) && 4141 GetVldrDRegisterImmediateOffset(instr) == 0)); 4142 DCHECK(is_uint10(offset)); 4143 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset)); 4144 } else { 4145 // Instruction to patch must be 'ldr rd, [pp, #0]'. 4146 DCHECK((IsLdrPpImmediateOffset(instr) && 4147 GetLdrRegisterImmediateOffset(instr) == 0)); 4148 DCHECK(is_uint12(offset)); 4149 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset)); 4150 } 4151} 4152 4153 4154} // namespace internal 4155} // namespace v8 4156 4157#endif // V8_TARGET_ARCH_ARM 4158