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 49static const unsigned kArmv6 = 0u; 50static const unsigned kArmv7 = kArmv6 | (1u << ARMv7); 51static const unsigned kArmv7WithSudiv = kArmv7 | (1u << ARMv7_SUDIV); 52static const unsigned kArmv8 = kArmv7WithSudiv | (1u << ARMv8); 53 54static unsigned CpuFeaturesFromCommandLine() { 55 unsigned result; 56 if (strcmp(FLAG_arm_arch, "armv8") == 0) { 57 result = kArmv8; 58 } else if (strcmp(FLAG_arm_arch, "armv7+sudiv") == 0) { 59 result = kArmv7WithSudiv; 60 } else if (strcmp(FLAG_arm_arch, "armv7") == 0) { 61 result = kArmv7; 62 } else if (strcmp(FLAG_arm_arch, "armv6") == 0) { 63 result = kArmv6; 64 } else { 65 fprintf(stderr, "Error: unrecognised value for --arm-arch ('%s').\n", 66 FLAG_arm_arch); 67 fprintf(stderr, 68 "Supported values are: armv8\n" 69 " armv7+sudiv\n" 70 " armv7\n" 71 " armv6\n"); 72 CHECK(false); 73 } 74 75 // If any of the old (deprecated) flags are specified, print a warning, but 76 // otherwise try to respect them for now. 77 // TODO(jbramley): When all the old bots have been updated, remove this. 78 if (FLAG_enable_armv7.has_value || FLAG_enable_vfp3.has_value || 79 FLAG_enable_32dregs.has_value || FLAG_enable_neon.has_value || 80 FLAG_enable_sudiv.has_value || FLAG_enable_armv8.has_value) { 81 // As an approximation of the old behaviour, set the default values from the 82 // arm_arch setting, then apply the flags over the top. 83 bool enable_armv7 = (result & (1u << ARMv7)) != 0; 84 bool enable_vfp3 = (result & (1u << ARMv7)) != 0; 85 bool enable_32dregs = (result & (1u << ARMv7)) != 0; 86 bool enable_neon = (result & (1u << ARMv7)) != 0; 87 bool enable_sudiv = (result & (1u << ARMv7_SUDIV)) != 0; 88 bool enable_armv8 = (result & (1u << ARMv8)) != 0; 89 if (FLAG_enable_armv7.has_value) { 90 fprintf(stderr, 91 "Warning: --enable_armv7 is deprecated. " 92 "Use --arm_arch instead.\n"); 93 enable_armv7 = FLAG_enable_armv7.value; 94 } 95 if (FLAG_enable_vfp3.has_value) { 96 fprintf(stderr, 97 "Warning: --enable_vfp3 is deprecated. " 98 "Use --arm_arch instead.\n"); 99 enable_vfp3 = FLAG_enable_vfp3.value; 100 } 101 if (FLAG_enable_32dregs.has_value) { 102 fprintf(stderr, 103 "Warning: --enable_32dregs is deprecated. " 104 "Use --arm_arch instead.\n"); 105 enable_32dregs = FLAG_enable_32dregs.value; 106 } 107 if (FLAG_enable_neon.has_value) { 108 fprintf(stderr, 109 "Warning: --enable_neon is deprecated. " 110 "Use --arm_arch instead.\n"); 111 enable_neon = FLAG_enable_neon.value; 112 } 113 if (FLAG_enable_sudiv.has_value) { 114 fprintf(stderr, 115 "Warning: --enable_sudiv is deprecated. " 116 "Use --arm_arch instead.\n"); 117 enable_sudiv = FLAG_enable_sudiv.value; 118 } 119 if (FLAG_enable_armv8.has_value) { 120 fprintf(stderr, 121 "Warning: --enable_armv8 is deprecated. " 122 "Use --arm_arch instead.\n"); 123 enable_armv8 = FLAG_enable_armv8.value; 124 } 125 // Emulate the old implications. 126 if (enable_armv8) { 127 enable_vfp3 = true; 128 enable_neon = true; 129 enable_32dregs = true; 130 enable_sudiv = true; 131 } 132 // Select the best available configuration. 133 if (enable_armv7 && enable_vfp3 && enable_32dregs && enable_neon) { 134 if (enable_sudiv) { 135 if (enable_armv8) { 136 result = kArmv8; 137 } else { 138 result = kArmv7WithSudiv; 139 } 140 } else { 141 result = kArmv7; 142 } 143 } else { 144 result = kArmv6; 145 } 146 } 147 return result; 148} 149 150// Get the CPU features enabled by the build. 151// For cross compilation the preprocessor symbols such as 152// CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS can be used to 153// enable ARMv7 and VFPv3 instructions when building the snapshot. However, 154// these flags should be consistent with a supported ARM configuration: 155// "armv6": ARMv6 + VFPv2 156// "armv7": ARMv7 + VFPv3-D32 + NEON 157// "armv7+sudiv": ARMv7 + VFPv4-D32 + NEON + SUDIV 158// "armv8": ARMv8 (+ all of the above) 159static constexpr unsigned CpuFeaturesFromCompiler() { 160// TODO(jbramley): Once the build flags are simplified, these tests should 161// also be simplified. 162 163// Check *architectural* implications. 164#if defined(CAN_USE_ARMV8_INSTRUCTIONS) && !defined(CAN_USE_ARMV7_INSTRUCTIONS) 165#error "CAN_USE_ARMV8_INSTRUCTIONS should imply CAN_USE_ARMV7_INSTRUCTIONS" 166#endif 167#if defined(CAN_USE_ARMV8_INSTRUCTIONS) && !defined(CAN_USE_SUDIV) 168#error "CAN_USE_ARMV8_INSTRUCTIONS should imply CAN_USE_SUDIV" 169#endif 170#if defined(CAN_USE_ARMV7_INSTRUCTIONS) != defined(CAN_USE_VFP3_INSTRUCTIONS) 171// V8 requires VFP, and all ARMv7 devices with VFP have VFPv3. Similarly, 172// VFPv3 isn't available before ARMv7. 173#error "CAN_USE_ARMV7_INSTRUCTIONS should match CAN_USE_VFP3_INSTRUCTIONS" 174#endif 175#if defined(CAN_USE_NEON) && !defined(CAN_USE_ARMV7_INSTRUCTIONS) 176#error "CAN_USE_NEON should imply CAN_USE_ARMV7_INSTRUCTIONS" 177#endif 178 179// Find compiler-implied features. 180#if defined(CAN_USE_ARMV8_INSTRUCTIONS) && \ 181 defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_SUDIV) && \ 182 defined(CAN_USE_NEON) && defined(CAN_USE_VFP3_INSTRUCTIONS) 183 return kArmv8; 184#elif defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_SUDIV) && \ 185 defined(CAN_USE_NEON) && defined(CAN_USE_VFP3_INSTRUCTIONS) 186 return kArmv7WithSudiv; 187#elif defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_NEON) && \ 188 defined(CAN_USE_VFP3_INSTRUCTIONS) 189 return kArmv7; 190#else 191 return kArmv6; 192#endif 193} 194 195 196void CpuFeatures::ProbeImpl(bool cross_compile) { 197 dcache_line_size_ = 64; 198 199 unsigned command_line = CpuFeaturesFromCommandLine(); 200 // Only use statically determined features for cross compile (snapshot). 201 if (cross_compile) { 202 supported_ |= command_line & CpuFeaturesFromCompiler(); 203 return; 204 } 205 206#ifndef __arm__ 207 // For the simulator build, use whatever the flags specify. 208 supported_ |= command_line; 209 210#else // __arm__ 211 // Probe for additional features at runtime. 212 base::CPU cpu; 213 // Runtime detection is slightly fuzzy, and some inferences are necessary. 214 unsigned runtime = kArmv6; 215 // NEON and VFPv3 imply at least ARMv7-A. 216 if (cpu.has_neon() && cpu.has_vfp3_d32()) { 217 DCHECK(cpu.has_vfp3()); 218 runtime |= kArmv7; 219 if (cpu.has_idiva()) { 220 runtime |= kArmv7WithSudiv; 221 if (cpu.architecture() >= 8) { 222 runtime |= kArmv8; 223 } 224 } 225 } 226 227 // Use the best of the features found by CPU detection and those inferred from 228 // the build system. In both cases, restrict available features using the 229 // command-line. Note that the command-line flags are very permissive (kArmv8) 230 // by default. 231 supported_ |= command_line & CpuFeaturesFromCompiler(); 232 supported_ |= command_line & runtime; 233 234 // Additional tuning options. 235 236 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines. 237 if (cpu.implementer() == base::CPU::ARM && 238 (cpu.part() == base::CPU::ARM_CORTEX_A5 || 239 cpu.part() == base::CPU::ARM_CORTEX_A9)) { 240 dcache_line_size_ = 32; 241 } 242#endif 243 244 DCHECK_IMPLIES(IsSupported(ARMv7_SUDIV), IsSupported(ARMv7)); 245 DCHECK_IMPLIES(IsSupported(ARMv8), IsSupported(ARMv7_SUDIV)); 246} 247 248 249void CpuFeatures::PrintTarget() { 250 const char* arm_arch = NULL; 251 const char* arm_target_type = ""; 252 const char* arm_no_probe = ""; 253 const char* arm_fpu = ""; 254 const char* arm_thumb = ""; 255 const char* arm_float_abi = NULL; 256 257#if !defined __arm__ 258 arm_target_type = " simulator"; 259#endif 260 261#if defined ARM_TEST_NO_FEATURE_PROBE 262 arm_no_probe = " noprobe"; 263#endif 264 265#if defined CAN_USE_ARMV8_INSTRUCTIONS 266 arm_arch = "arm v8"; 267#elif defined CAN_USE_ARMV7_INSTRUCTIONS 268 arm_arch = "arm v7"; 269#else 270 arm_arch = "arm v6"; 271#endif 272 273#if defined CAN_USE_NEON 274 arm_fpu = " neon"; 275#elif defined CAN_USE_VFP3_INSTRUCTIONS 276# if defined CAN_USE_VFP32DREGS 277 arm_fpu = " vfp3"; 278# else 279 arm_fpu = " vfp3-d16"; 280# endif 281#else 282 arm_fpu = " vfp2"; 283#endif 284 285#ifdef __arm__ 286 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp"; 287#elif USE_EABI_HARDFLOAT 288 arm_float_abi = "hard"; 289#else 290 arm_float_abi = "softfp"; 291#endif 292 293#if defined __arm__ && (defined __thumb__) || (defined __thumb2__) 294 arm_thumb = " thumb"; 295#endif 296 297 printf("target%s%s %s%s%s %s\n", 298 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb, 299 arm_float_abi); 300} 301 302 303void CpuFeatures::PrintFeatures() { 304 printf("ARMv8=%d ARMv7=%d VFPv3=%d VFP32DREGS=%d NEON=%d SUDIV=%d", 305 CpuFeatures::IsSupported(ARMv8), CpuFeatures::IsSupported(ARMv7), 306 CpuFeatures::IsSupported(VFPv3), CpuFeatures::IsSupported(VFP32DREGS), 307 CpuFeatures::IsSupported(NEON), CpuFeatures::IsSupported(SUDIV)); 308#ifdef __arm__ 309 bool eabi_hardfloat = base::OS::ArmUsingHardFloat(); 310#elif USE_EABI_HARDFLOAT 311 bool eabi_hardfloat = true; 312#else 313 bool eabi_hardfloat = false; 314#endif 315 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat); 316} 317 318 319// ----------------------------------------------------------------------------- 320// Implementation of RelocInfo 321 322// static 323const int RelocInfo::kApplyMask = 0; 324 325 326bool RelocInfo::IsCodedSpecially() { 327 // The deserializer needs to know whether a pointer is specially coded. Being 328 // specially coded on ARM means that it is a movw/movt instruction, or is an 329 // embedded constant pool entry. These only occur if 330 // FLAG_enable_embedded_constant_pool is true. 331 return FLAG_enable_embedded_constant_pool; 332} 333 334 335bool RelocInfo::IsInConstantPool() { 336 return Assembler::is_constant_pool_load(pc_); 337} 338 339Address RelocInfo::wasm_memory_reference() { 340 DCHECK(IsWasmMemoryReference(rmode_)); 341 return Assembler::target_address_at(pc_, host_); 342} 343 344uint32_t RelocInfo::wasm_memory_size_reference() { 345 DCHECK(IsWasmMemorySizeReference(rmode_)); 346 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_)); 347} 348 349Address RelocInfo::wasm_global_reference() { 350 DCHECK(IsWasmGlobalReference(rmode_)); 351 return Assembler::target_address_at(pc_, host_); 352} 353 354uint32_t RelocInfo::wasm_function_table_size_reference() { 355 DCHECK(IsWasmFunctionTableSizeReference(rmode_)); 356 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_)); 357} 358 359void RelocInfo::unchecked_update_wasm_memory_reference( 360 Address address, ICacheFlushMode flush_mode) { 361 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode); 362} 363 364void RelocInfo::unchecked_update_wasm_size(uint32_t size, 365 ICacheFlushMode flush_mode) { 366 Assembler::set_target_address_at(isolate_, pc_, host_, 367 reinterpret_cast<Address>(size), flush_mode); 368} 369 370// ----------------------------------------------------------------------------- 371// Implementation of Operand and MemOperand 372// See assembler-arm-inl.h for inlined constructors 373 374Operand::Operand(Handle<Object> handle) { 375 AllowDeferredHandleDereference using_raw_address; 376 rm_ = no_reg; 377 // Verify all Objects referred by code are NOT in new space. 378 Object* obj = *handle; 379 if (obj->IsHeapObject()) { 380 imm32_ = reinterpret_cast<intptr_t>(handle.location()); 381 rmode_ = RelocInfo::EMBEDDED_OBJECT; 382 } else { 383 // no relocation needed 384 imm32_ = reinterpret_cast<intptr_t>(obj); 385 rmode_ = RelocInfo::NONE32; 386 } 387} 388 389 390Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) { 391 DCHECK(is_uint5(shift_imm)); 392 393 rm_ = rm; 394 rs_ = no_reg; 395 shift_op_ = shift_op; 396 shift_imm_ = shift_imm & 31; 397 398 if ((shift_op == ROR) && (shift_imm == 0)) { 399 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode 400 // RRX as ROR #0 (See below). 401 shift_op = LSL; 402 } else if (shift_op == RRX) { 403 // encoded as ROR with shift_imm == 0 404 DCHECK(shift_imm == 0); 405 shift_op_ = ROR; 406 shift_imm_ = 0; 407 } 408} 409 410 411Operand::Operand(Register rm, ShiftOp shift_op, Register rs) { 412 DCHECK(shift_op != RRX); 413 rm_ = rm; 414 rs_ = no_reg; 415 shift_op_ = shift_op; 416 rs_ = rs; 417} 418 419 420MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) { 421 rn_ = rn; 422 rm_ = no_reg; 423 offset_ = offset; 424 am_ = am; 425 426 // Accesses below the stack pointer are not safe, and are prohibited by the 427 // ABI. We can check obvious violations here. 428 if (rn.is(sp)) { 429 if (am == Offset) DCHECK_LE(0, offset); 430 if (am == NegOffset) DCHECK_GE(0, offset); 431 } 432} 433 434 435MemOperand::MemOperand(Register rn, Register rm, AddrMode am) { 436 rn_ = rn; 437 rm_ = rm; 438 shift_op_ = LSL; 439 shift_imm_ = 0; 440 am_ = am; 441} 442 443 444MemOperand::MemOperand(Register rn, Register rm, 445 ShiftOp shift_op, int shift_imm, AddrMode am) { 446 DCHECK(is_uint5(shift_imm)); 447 rn_ = rn; 448 rm_ = rm; 449 shift_op_ = shift_op; 450 shift_imm_ = shift_imm & 31; 451 am_ = am; 452} 453 454 455NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) { 456 DCHECK((am == Offset) || (am == PostIndex)); 457 rn_ = rn; 458 rm_ = (am == Offset) ? pc : sp; 459 SetAlignment(align); 460} 461 462 463NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) { 464 rn_ = rn; 465 rm_ = rm; 466 SetAlignment(align); 467} 468 469 470void NeonMemOperand::SetAlignment(int align) { 471 switch (align) { 472 case 0: 473 align_ = 0; 474 break; 475 case 64: 476 align_ = 1; 477 break; 478 case 128: 479 align_ = 2; 480 break; 481 case 256: 482 align_ = 3; 483 break; 484 default: 485 UNREACHABLE(); 486 align_ = 0; 487 break; 488 } 489} 490 491// ----------------------------------------------------------------------------- 492// Specific instructions, constants, and masks. 493 494// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) 495// register r is not encoded. 496const Instr kPushRegPattern = 497 al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16; 498// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) 499// register r is not encoded. 500const Instr kPopRegPattern = 501 al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16; 502// ldr rd, [pc, #offset] 503const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16; 504const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16; 505// ldr rd, [pp, #offset] 506const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16; 507const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16; 508// ldr rd, [pp, rn] 509const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16; 510const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16; 511// vldr dd, [pc, #offset] 512const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8; 513const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8; 514// vldr dd, [pp, #offset] 515const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8; 516const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8; 517// blxcc rm 518const Instr kBlxRegMask = 519 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4; 520const Instr kBlxRegPattern = 521 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX; 522const Instr kBlxIp = al | kBlxRegPattern | ip.code(); 523const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; 524const Instr kMovMvnPattern = 0xd * B21; 525const Instr kMovMvnFlip = B22; 526const Instr kMovLeaveCCMask = 0xdff * B16; 527const Instr kMovLeaveCCPattern = 0x1a0 * B16; 528const Instr kMovwPattern = 0x30 * B20; 529const Instr kMovtPattern = 0x34 * B20; 530const Instr kMovwLeaveCCFlip = 0x5 * B21; 531const Instr kMovImmedMask = 0x7f * B21; 532const Instr kMovImmedPattern = 0x1d * B21; 533const Instr kOrrImmedMask = 0x7f * B21; 534const Instr kOrrImmedPattern = 0x1c * B21; 535const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12; 536const Instr kCmpCmnPattern = 0x15 * B20; 537const Instr kCmpCmnFlip = B21; 538const Instr kAddSubFlip = 0x6 * B21; 539const Instr kAndBicFlip = 0xe * B21; 540 541// A mask for the Rd register for push, pop, ldr, str instructions. 542const Instr kLdrRegFpOffsetPattern = 543 al | B26 | L | Offset | Register::kCode_fp * B16; 544const Instr kStrRegFpOffsetPattern = 545 al | B26 | Offset | Register::kCode_fp * B16; 546const Instr kLdrRegFpNegOffsetPattern = 547 al | B26 | L | NegOffset | Register::kCode_fp * B16; 548const Instr kStrRegFpNegOffsetPattern = 549 al | B26 | NegOffset | Register::kCode_fp * B16; 550const Instr kLdrStrInstrTypeMask = 0xffff0000; 551 552Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) 553 : AssemblerBase(isolate, buffer, buffer_size), 554 recorded_ast_id_(TypeFeedbackId::None()), 555 pending_32_bit_constants_(), 556 pending_64_bit_constants_(), 557 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits) { 558 pending_32_bit_constants_.reserve(kMinNumPendingConstants); 559 pending_64_bit_constants_.reserve(kMinNumPendingConstants); 560 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); 561 next_buffer_check_ = 0; 562 const_pool_blocked_nesting_ = 0; 563 no_const_pool_before_ = 0; 564 first_const_pool_32_use_ = -1; 565 first_const_pool_64_use_ = -1; 566 last_bound_pos_ = 0; 567 ClearRecordedAstId(); 568 if (CpuFeatures::IsSupported(VFP32DREGS)) { 569 // Register objects tend to be abstracted and survive between scopes, so 570 // it's awkward to use CpuFeatures::VFP32DREGS with CpuFeatureScope. To make 571 // its use consistent with other features, we always enable it if we can. 572 EnableCpuFeature(VFP32DREGS); 573 } 574} 575 576 577Assembler::~Assembler() { 578 DCHECK(const_pool_blocked_nesting_ == 0); 579} 580 581 582void Assembler::GetCode(CodeDesc* desc) { 583 // Emit constant pool if necessary. 584 int constant_pool_offset = 0; 585 if (FLAG_enable_embedded_constant_pool) { 586 constant_pool_offset = EmitEmbeddedConstantPool(); 587 } else { 588 CheckConstPool(true, false); 589 DCHECK(pending_32_bit_constants_.empty()); 590 DCHECK(pending_64_bit_constants_.empty()); 591 } 592 // Set up code descriptor. 593 desc->buffer = buffer_; 594 desc->buffer_size = buffer_size_; 595 desc->instr_size = pc_offset(); 596 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 597 desc->constant_pool_size = 598 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0); 599 desc->origin = this; 600 desc->unwinding_info_size = 0; 601 desc->unwinding_info = nullptr; 602} 603 604 605void Assembler::Align(int m) { 606 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m)); 607 DCHECK((pc_offset() & (kInstrSize - 1)) == 0); 608 while ((pc_offset() & (m - 1)) != 0) { 609 nop(); 610 } 611} 612 613 614void Assembler::CodeTargetAlign() { 615 // Preferred alignment of jump targets on some ARM chips. 616 Align(8); 617} 618 619 620Condition Assembler::GetCondition(Instr instr) { 621 return Instruction::ConditionField(instr); 622} 623 624 625bool Assembler::IsBranch(Instr instr) { 626 return (instr & (B27 | B25)) == (B27 | B25); 627} 628 629 630int Assembler::GetBranchOffset(Instr instr) { 631 DCHECK(IsBranch(instr)); 632 // Take the jump offset in the lower 24 bits, sign extend it and multiply it 633 // with 4 to get the offset in bytes. 634 return ((instr & kImm24Mask) << 8) >> 6; 635} 636 637 638bool Assembler::IsLdrRegisterImmediate(Instr instr) { 639 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20); 640} 641 642 643bool Assembler::IsVldrDRegisterImmediate(Instr instr) { 644 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8); 645} 646 647 648int Assembler::GetLdrRegisterImmediateOffset(Instr instr) { 649 DCHECK(IsLdrRegisterImmediate(instr)); 650 bool positive = (instr & B23) == B23; 651 int offset = instr & kOff12Mask; // Zero extended offset. 652 return positive ? offset : -offset; 653} 654 655 656int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) { 657 DCHECK(IsVldrDRegisterImmediate(instr)); 658 bool positive = (instr & B23) == B23; 659 int offset = instr & kOff8Mask; // Zero extended offset. 660 offset <<= 2; 661 return positive ? offset : -offset; 662} 663 664 665Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) { 666 DCHECK(IsLdrRegisterImmediate(instr)); 667 bool positive = offset >= 0; 668 if (!positive) offset = -offset; 669 DCHECK(is_uint12(offset)); 670 // Set bit indicating whether the offset should be added. 671 instr = (instr & ~B23) | (positive ? B23 : 0); 672 // Set the actual offset. 673 return (instr & ~kOff12Mask) | offset; 674} 675 676 677Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) { 678 DCHECK(IsVldrDRegisterImmediate(instr)); 679 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned. 680 bool positive = offset >= 0; 681 if (!positive) offset = -offset; 682 DCHECK(is_uint10(offset)); 683 // Set bit indicating whether the offset should be added. 684 instr = (instr & ~B23) | (positive ? B23 : 0); 685 // Set the actual offset. Its bottom 2 bits are zero. 686 return (instr & ~kOff8Mask) | (offset >> 2); 687} 688 689 690bool Assembler::IsStrRegisterImmediate(Instr instr) { 691 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26; 692} 693 694 695Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) { 696 DCHECK(IsStrRegisterImmediate(instr)); 697 bool positive = offset >= 0; 698 if (!positive) offset = -offset; 699 DCHECK(is_uint12(offset)); 700 // Set bit indicating whether the offset should be added. 701 instr = (instr & ~B23) | (positive ? B23 : 0); 702 // Set the actual offset. 703 return (instr & ~kOff12Mask) | offset; 704} 705 706 707bool Assembler::IsAddRegisterImmediate(Instr instr) { 708 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23); 709} 710 711 712Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) { 713 DCHECK(IsAddRegisterImmediate(instr)); 714 DCHECK(offset >= 0); 715 DCHECK(is_uint12(offset)); 716 // Set the offset. 717 return (instr & ~kOff12Mask) | offset; 718} 719 720 721Register Assembler::GetRd(Instr instr) { 722 Register reg; 723 reg.reg_code = Instruction::RdValue(instr); 724 return reg; 725} 726 727 728Register Assembler::GetRn(Instr instr) { 729 Register reg; 730 reg.reg_code = Instruction::RnValue(instr); 731 return reg; 732} 733 734 735Register Assembler::GetRm(Instr instr) { 736 Register reg; 737 reg.reg_code = Instruction::RmValue(instr); 738 return reg; 739} 740 741 742Instr Assembler::GetConsantPoolLoadPattern() { 743 if (FLAG_enable_embedded_constant_pool) { 744 return kLdrPpImmedPattern; 745 } else { 746 return kLdrPCImmedPattern; 747 } 748} 749 750 751Instr Assembler::GetConsantPoolLoadMask() { 752 if (FLAG_enable_embedded_constant_pool) { 753 return kLdrPpImmedMask; 754 } else { 755 return kLdrPCImmedMask; 756 } 757} 758 759 760bool Assembler::IsPush(Instr instr) { 761 return ((instr & ~kRdMask) == kPushRegPattern); 762} 763 764 765bool Assembler::IsPop(Instr instr) { 766 return ((instr & ~kRdMask) == kPopRegPattern); 767} 768 769 770bool Assembler::IsStrRegFpOffset(Instr instr) { 771 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern); 772} 773 774 775bool Assembler::IsLdrRegFpOffset(Instr instr) { 776 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern); 777} 778 779 780bool Assembler::IsStrRegFpNegOffset(Instr instr) { 781 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern); 782} 783 784 785bool Assembler::IsLdrRegFpNegOffset(Instr instr) { 786 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern); 787} 788 789 790bool Assembler::IsLdrPcImmediateOffset(Instr instr) { 791 // Check the instruction is indeed a 792 // ldr<cond> <Rd>, [pc +/- offset_12]. 793 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern; 794} 795 796 797bool Assembler::IsLdrPpImmediateOffset(Instr instr) { 798 // Check the instruction is indeed a 799 // ldr<cond> <Rd>, [pp +/- offset_12]. 800 return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern; 801} 802 803 804bool Assembler::IsLdrPpRegOffset(Instr instr) { 805 // Check the instruction is indeed a 806 // ldr<cond> <Rd>, [pp, +/- <Rm>]. 807 return (instr & kLdrPpRegMask) == kLdrPpRegPattern; 808} 809 810 811Instr Assembler::GetLdrPpRegOffsetPattern() { return kLdrPpRegPattern; } 812 813 814bool Assembler::IsVldrDPcImmediateOffset(Instr instr) { 815 // Check the instruction is indeed a 816 // vldr<cond> <Dd>, [pc +/- offset_10]. 817 return (instr & kVldrDPCMask) == kVldrDPCPattern; 818} 819 820 821bool Assembler::IsVldrDPpImmediateOffset(Instr instr) { 822 // Check the instruction is indeed a 823 // vldr<cond> <Dd>, [pp +/- offset_10]. 824 return (instr & kVldrDPpMask) == kVldrDPpPattern; 825} 826 827 828bool Assembler::IsBlxReg(Instr instr) { 829 // Check the instruction is indeed a 830 // blxcc <Rm> 831 return (instr & kBlxRegMask) == kBlxRegPattern; 832} 833 834 835bool Assembler::IsBlxIp(Instr instr) { 836 // Check the instruction is indeed a 837 // blx ip 838 return instr == kBlxIp; 839} 840 841 842bool Assembler::IsTstImmediate(Instr instr) { 843 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 844 (I | TST | S); 845} 846 847 848bool Assembler::IsCmpRegister(Instr instr) { 849 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) == 850 (CMP | S); 851} 852 853 854bool Assembler::IsCmpImmediate(Instr instr) { 855 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) == 856 (I | CMP | S); 857} 858 859 860Register Assembler::GetCmpImmediateRegister(Instr instr) { 861 DCHECK(IsCmpImmediate(instr)); 862 return GetRn(instr); 863} 864 865 866int Assembler::GetCmpImmediateRawImmediate(Instr instr) { 867 DCHECK(IsCmpImmediate(instr)); 868 return instr & kOff12Mask; 869} 870 871 872// Labels refer to positions in the (to be) generated code. 873// There are bound, linked, and unused labels. 874// 875// Bound labels refer to known positions in the already 876// generated code. pos() is the position the label refers to. 877// 878// Linked labels refer to unknown positions in the code 879// to be generated; pos() is the position of the last 880// instruction using the label. 881// 882// The linked labels form a link chain by making the branch offset 883// in the instruction steam to point to the previous branch 884// instruction using the same label. 885// 886// The link chain is terminated by a branch offset pointing to the 887// same position. 888 889 890int Assembler::target_at(int pos) { 891 Instr instr = instr_at(pos); 892 if (is_uint24(instr)) { 893 // Emitted link to a label, not part of a branch. 894 return instr; 895 } 896 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24 897 int imm26 = ((instr & kImm24Mask) << 8) >> 6; 898 if ((Instruction::ConditionField(instr) == kSpecialCondition) && 899 ((instr & B24) != 0)) { 900 // blx uses bit 24 to encode bit 2 of imm26 901 imm26 += 2; 902 } 903 return pos + kPcLoadDelta + imm26; 904} 905 906 907void Assembler::target_at_put(int pos, int target_pos) { 908 Instr instr = instr_at(pos); 909 if (is_uint24(instr)) { 910 DCHECK(target_pos == pos || target_pos >= 0); 911 // Emitted link to a label, not part of a branch. 912 // Load the position of the label relative to the generated code object 913 // pointer in a register. 914 915 // The existing code must be a single 24-bit label chain link, followed by 916 // nops encoding the destination register. See mov_label_offset. 917 918 // Extract the destination register from the first nop instructions. 919 Register dst = 920 Register::from_code(Instruction::RmValue(instr_at(pos + kInstrSize))); 921 // In addition to the 24-bit label chain link, we expect to find one nop for 922 // ARMv7 and above, or two nops for ARMv6. See mov_label_offset. 923 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code())); 924 if (!CpuFeatures::IsSupported(ARMv7)) { 925 DCHECK(IsNop(instr_at(pos + 2 * kInstrSize), dst.code())); 926 } 927 928 // Here are the instructions we need to emit: 929 // For ARMv7: target24 => target16_1:target16_0 930 // movw dst, #target16_0 931 // movt dst, #target16_1 932 // For ARMv6: target24 => target8_2:target8_1:target8_0 933 // mov dst, #target8_0 934 // orr dst, dst, #target8_1 << 8 935 // orr dst, dst, #target8_2 << 16 936 937 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag); 938 DCHECK(is_uint24(target24)); 939 if (is_uint8(target24)) { 940 // If the target fits in a byte then only patch with a mov 941 // instruction. 942 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 1, 943 CodePatcher::DONT_FLUSH); 944 patcher.masm()->mov(dst, Operand(target24)); 945 } else { 946 uint16_t target16_0 = target24 & kImm16Mask; 947 uint16_t target16_1 = target24 >> 16; 948 if (CpuFeatures::IsSupported(ARMv7)) { 949 // Patch with movw/movt. 950 if (target16_1 == 0) { 951 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 952 1, CodePatcher::DONT_FLUSH); 953 CpuFeatureScope scope(patcher.masm(), ARMv7); 954 patcher.masm()->movw(dst, target16_0); 955 } else { 956 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 957 2, CodePatcher::DONT_FLUSH); 958 CpuFeatureScope scope(patcher.masm(), ARMv7); 959 patcher.masm()->movw(dst, target16_0); 960 patcher.masm()->movt(dst, target16_1); 961 } 962 } else { 963 // Patch with a sequence of mov/orr/orr instructions. 964 uint8_t target8_0 = target16_0 & kImm8Mask; 965 uint8_t target8_1 = target16_0 >> 8; 966 uint8_t target8_2 = target16_1 & kImm8Mask; 967 if (target8_2 == 0) { 968 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 969 2, CodePatcher::DONT_FLUSH); 970 patcher.masm()->mov(dst, Operand(target8_0)); 971 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); 972 } else { 973 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 974 3, CodePatcher::DONT_FLUSH); 975 patcher.masm()->mov(dst, Operand(target8_0)); 976 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); 977 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16)); 978 } 979 } 980 } 981 return; 982 } 983 int imm26 = target_pos - (pos + kPcLoadDelta); 984 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24 985 if (Instruction::ConditionField(instr) == kSpecialCondition) { 986 // blx uses bit 24 to encode bit 2 of imm26 987 DCHECK_EQ(0, imm26 & 1); 988 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24; 989 } else { 990 DCHECK_EQ(0, imm26 & 3); 991 instr &= ~kImm24Mask; 992 } 993 int imm24 = imm26 >> 2; 994 DCHECK(is_int24(imm24)); 995 instr_at_put(pos, instr | (imm24 & kImm24Mask)); 996} 997 998 999void Assembler::print(Label* L) { 1000 if (L->is_unused()) { 1001 PrintF("unused label\n"); 1002 } else if (L->is_bound()) { 1003 PrintF("bound label to %d\n", L->pos()); 1004 } else if (L->is_linked()) { 1005 Label l = *L; 1006 PrintF("unbound label"); 1007 while (l.is_linked()) { 1008 PrintF("@ %d ", l.pos()); 1009 Instr instr = instr_at(l.pos()); 1010 if ((instr & ~kImm24Mask) == 0) { 1011 PrintF("value\n"); 1012 } else { 1013 DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx 1014 Condition cond = Instruction::ConditionField(instr); 1015 const char* b; 1016 const char* c; 1017 if (cond == kSpecialCondition) { 1018 b = "blx"; 1019 c = ""; 1020 } else { 1021 if ((instr & B24) != 0) 1022 b = "bl"; 1023 else 1024 b = "b"; 1025 1026 switch (cond) { 1027 case eq: c = "eq"; break; 1028 case ne: c = "ne"; break; 1029 case hs: c = "hs"; break; 1030 case lo: c = "lo"; break; 1031 case mi: c = "mi"; break; 1032 case pl: c = "pl"; break; 1033 case vs: c = "vs"; break; 1034 case vc: c = "vc"; break; 1035 case hi: c = "hi"; break; 1036 case ls: c = "ls"; break; 1037 case ge: c = "ge"; break; 1038 case lt: c = "lt"; break; 1039 case gt: c = "gt"; break; 1040 case le: c = "le"; break; 1041 case al: c = ""; break; 1042 default: 1043 c = ""; 1044 UNREACHABLE(); 1045 } 1046 } 1047 PrintF("%s%s\n", b, c); 1048 } 1049 next(&l); 1050 } 1051 } else { 1052 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); 1053 } 1054} 1055 1056 1057void Assembler::bind_to(Label* L, int pos) { 1058 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position 1059 while (L->is_linked()) { 1060 int fixup_pos = L->pos(); 1061 next(L); // call next before overwriting link with target at fixup_pos 1062 target_at_put(fixup_pos, pos); 1063 } 1064 L->bind_to(pos); 1065 1066 // Keep track of the last bound label so we don't eliminate any instructions 1067 // before a bound label. 1068 if (pos > last_bound_pos_) 1069 last_bound_pos_ = pos; 1070} 1071 1072 1073void Assembler::bind(Label* L) { 1074 DCHECK(!L->is_bound()); // label can only be bound once 1075 bind_to(L, pc_offset()); 1076} 1077 1078 1079void Assembler::next(Label* L) { 1080 DCHECK(L->is_linked()); 1081 int link = target_at(L->pos()); 1082 if (link == L->pos()) { 1083 // Branch target points to the same instuction. This is the end of the link 1084 // chain. 1085 L->Unuse(); 1086 } else { 1087 DCHECK(link >= 0); 1088 L->link_to(link); 1089 } 1090} 1091 1092 1093// Low-level code emission routines depending on the addressing mode. 1094// If this returns true then you have to use the rotate_imm and immed_8 1095// that it returns, because it may have already changed the instruction 1096// to match them! 1097static bool fits_shifter(uint32_t imm32, 1098 uint32_t* rotate_imm, 1099 uint32_t* immed_8, 1100 Instr* instr) { 1101 // imm32 must be unsigned. 1102 for (int rot = 0; rot < 16; rot++) { 1103 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot); 1104 if ((imm8 <= 0xff)) { 1105 *rotate_imm = rot; 1106 *immed_8 = imm8; 1107 return true; 1108 } 1109 } 1110 // If the opcode is one with a complementary version and the complementary 1111 // immediate fits, change the opcode. 1112 if (instr != NULL) { 1113 if ((*instr & kMovMvnMask) == kMovMvnPattern) { 1114 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 1115 *instr ^= kMovMvnFlip; 1116 return true; 1117 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) { 1118 if (CpuFeatures::IsSupported(ARMv7)) { 1119 if (imm32 < 0x10000) { 1120 *instr ^= kMovwLeaveCCFlip; 1121 *instr |= Assembler::EncodeMovwImmediate(imm32); 1122 *rotate_imm = *immed_8 = 0; // Not used for movw. 1123 return true; 1124 } 1125 } 1126 } 1127 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) { 1128 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) { 1129 *instr ^= kCmpCmnFlip; 1130 return true; 1131 } 1132 } else { 1133 Instr alu_insn = (*instr & kALUMask); 1134 if (alu_insn == ADD || 1135 alu_insn == SUB) { 1136 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) { 1137 *instr ^= kAddSubFlip; 1138 return true; 1139 } 1140 } else if (alu_insn == AND || 1141 alu_insn == BIC) { 1142 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { 1143 *instr ^= kAndBicFlip; 1144 return true; 1145 } 1146 } 1147 } 1148 } 1149 return false; 1150} 1151 1152 1153// We have to use the temporary register for things that can be relocated even 1154// if they can be encoded in the ARM's 12 bits of immediate-offset instruction 1155// space. There is no guarantee that the relocated location can be similarly 1156// encoded. 1157bool Operand::must_output_reloc_info(const Assembler* assembler) const { 1158 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { 1159 if (assembler != NULL && assembler->predictable_code_size()) return true; 1160 return assembler->serializer_enabled(); 1161 } else if (RelocInfo::IsNone(rmode_)) { 1162 return false; 1163 } 1164 return true; 1165} 1166 1167 1168static bool use_mov_immediate_load(const Operand& x, 1169 const Assembler* assembler) { 1170 DCHECK(assembler != nullptr); 1171 if (FLAG_enable_embedded_constant_pool && 1172 !assembler->is_constant_pool_available()) { 1173 return true; 1174 } else if (x.must_output_reloc_info(assembler)) { 1175 // Prefer constant pool if data is likely to be patched. 1176 return false; 1177 } else { 1178 // Otherwise, use immediate load if movw / movt is available. 1179 return CpuFeatures::IsSupported(ARMv7); 1180 } 1181} 1182 1183 1184int Operand::instructions_required(const Assembler* assembler, 1185 Instr instr) const { 1186 DCHECK(assembler != nullptr); 1187 if (rm_.is_valid()) return 1; 1188 uint32_t dummy1, dummy2; 1189 if (must_output_reloc_info(assembler) || 1190 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { 1191 // The immediate operand cannot be encoded as a shifter operand, or use of 1192 // constant pool is required. First account for the instructions required 1193 // for the constant pool or immediate load 1194 int instructions; 1195 if (use_mov_immediate_load(*this, assembler)) { 1196 // A movw / movt or mov / orr immediate load. 1197 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4; 1198 } else if (assembler->ConstantPoolAccessIsInOverflow()) { 1199 // An overflowed constant pool load. 1200 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5; 1201 } else { 1202 // A small constant pool load. 1203 instructions = 1; 1204 } 1205 1206 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set 1207 // For a mov or mvn instruction which doesn't set the condition 1208 // code, the constant pool or immediate load is enough, otherwise we need 1209 // to account for the actual instruction being requested. 1210 instructions += 1; 1211 } 1212 return instructions; 1213 } else { 1214 // No use of constant pool and the immediate operand can be encoded as a 1215 // shifter operand. 1216 return 1; 1217 } 1218} 1219 1220 1221void Assembler::move_32_bit_immediate(Register rd, 1222 const Operand& x, 1223 Condition cond) { 1224 uint32_t imm32 = static_cast<uint32_t>(x.imm32_); 1225 if (x.must_output_reloc_info(this)) { 1226 RecordRelocInfo(x.rmode_); 1227 } 1228 1229 if (use_mov_immediate_load(x, this)) { 1230 Register target = rd.code() == pc.code() ? ip : rd; 1231 if (CpuFeatures::IsSupported(ARMv7)) { 1232 CpuFeatureScope scope(this, ARMv7); 1233 if (!FLAG_enable_embedded_constant_pool && 1234 x.must_output_reloc_info(this)) { 1235 // Make sure the movw/movt doesn't get separated. 1236 BlockConstPoolFor(2); 1237 } 1238 movw(target, imm32 & 0xffff, cond); 1239 movt(target, imm32 >> 16, cond); 1240 } else { 1241 DCHECK(FLAG_enable_embedded_constant_pool); 1242 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond); 1243 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond); 1244 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond); 1245 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond); 1246 } 1247 if (target.code() != rd.code()) { 1248 mov(rd, target, LeaveCC, cond); 1249 } 1250 } else { 1251 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available()); 1252 ConstantPoolEntry::Access access = 1253 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_); 1254 if (access == ConstantPoolEntry::OVERFLOWED) { 1255 DCHECK(FLAG_enable_embedded_constant_pool); 1256 Register target = rd.code() == pc.code() ? ip : rd; 1257 // Emit instructions to load constant pool offset. 1258 if (CpuFeatures::IsSupported(ARMv7)) { 1259 CpuFeatureScope scope(this, ARMv7); 1260 movw(target, 0, cond); 1261 movt(target, 0, cond); 1262 } else { 1263 mov(target, Operand(0), LeaveCC, cond); 1264 orr(target, target, Operand(0), LeaveCC, cond); 1265 orr(target, target, Operand(0), LeaveCC, cond); 1266 orr(target, target, Operand(0), LeaveCC, cond); 1267 } 1268 // Load from constant pool at offset. 1269 ldr(rd, MemOperand(pp, target), cond); 1270 } else { 1271 DCHECK(access == ConstantPoolEntry::REGULAR); 1272 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0), 1273 cond); 1274 } 1275 } 1276} 1277 1278 1279void Assembler::addrmod1(Instr instr, 1280 Register rn, 1281 Register rd, 1282 const Operand& x) { 1283 CheckBuffer(); 1284 DCHECK((instr & ~(kCondMask | kOpCodeMask | S)) == 0); 1285 if (!x.rm_.is_valid()) { 1286 // Immediate. 1287 uint32_t rotate_imm; 1288 uint32_t immed_8; 1289 if (x.must_output_reloc_info(this) || 1290 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { 1291 // The immediate operand cannot be encoded as a shifter operand, so load 1292 // it first to register ip and change the original instruction to use ip. 1293 // However, if the original instruction is a 'mov rd, x' (not setting the 1294 // condition code), then replace it with a 'ldr rd, [pc]'. 1295 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed 1296 Condition cond = Instruction::ConditionField(instr); 1297 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set 1298 move_32_bit_immediate(rd, x, cond); 1299 } else { 1300 mov(ip, x, LeaveCC, cond); 1301 addrmod1(instr, rn, rd, Operand(ip)); 1302 } 1303 return; 1304 } 1305 instr |= I | rotate_imm*B8 | immed_8; 1306 } else if (!x.rs_.is_valid()) { 1307 // Immediate shift. 1308 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 1309 } else { 1310 // Register shift. 1311 DCHECK(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); 1312 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); 1313 } 1314 emit(instr | rn.code()*B16 | rd.code()*B12); 1315 if (rn.is(pc) || x.rm_.is(pc)) { 1316 // Block constant pool emission for one instruction after reading pc. 1317 BlockConstPoolFor(1); 1318 } 1319} 1320 1321 1322void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { 1323 DCHECK((instr & ~(kCondMask | B | L)) == B26); 1324 int am = x.am_; 1325 if (!x.rm_.is_valid()) { 1326 // Immediate offset. 1327 int offset_12 = x.offset_; 1328 if (offset_12 < 0) { 1329 offset_12 = -offset_12; 1330 am ^= U; 1331 } 1332 if (!is_uint12(offset_12)) { 1333 // Immediate offset cannot be encoded, load it first to register ip 1334 // rn (and rd in a load) should never be ip, or will be trashed. 1335 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1336 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 1337 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1338 return; 1339 } 1340 DCHECK(offset_12 >= 0); // no masking needed 1341 instr |= offset_12; 1342 } else { 1343 // Register offset (shift_imm_ and shift_op_ are 0) or scaled 1344 // register offset the constructors make sure than both shift_imm_ 1345 // and shift_op_ are initialized. 1346 DCHECK(!x.rm_.is(pc)); 1347 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); 1348 } 1349 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1350 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 1351} 1352 1353 1354void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { 1355 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7)); 1356 DCHECK(x.rn_.is_valid()); 1357 int am = x.am_; 1358 if (!x.rm_.is_valid()) { 1359 // Immediate offset. 1360 int offset_8 = x.offset_; 1361 if (offset_8 < 0) { 1362 offset_8 = -offset_8; 1363 am ^= U; 1364 } 1365 if (!is_uint8(offset_8)) { 1366 // Immediate offset cannot be encoded, load it first to register ip 1367 // rn (and rd in a load) should never be ip, or will be trashed. 1368 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1369 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); 1370 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1371 return; 1372 } 1373 DCHECK(offset_8 >= 0); // no masking needed 1374 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf); 1375 } else if (x.shift_imm_ != 0) { 1376 // Scaled register offset not supported, load index first 1377 // rn (and rd in a load) should never be ip, or will be trashed. 1378 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); 1379 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC, 1380 Instruction::ConditionField(instr)); 1381 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); 1382 return; 1383 } else { 1384 // Register offset. 1385 DCHECK((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback 1386 instr |= x.rm_.code(); 1387 } 1388 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1389 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12); 1390} 1391 1392 1393void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { 1394 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27); 1395 DCHECK(rl != 0); 1396 DCHECK(!rn.is(pc)); 1397 emit(instr | rn.code()*B16 | rl); 1398} 1399 1400 1401void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) { 1402 // Unindexed addressing is not encoded by this function. 1403 DCHECK_EQ((B27 | B26), 1404 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L))); 1405 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid()); 1406 int am = x.am_; 1407 int offset_8 = x.offset_; 1408 DCHECK((offset_8 & 3) == 0); // offset must be an aligned word offset 1409 offset_8 >>= 2; 1410 if (offset_8 < 0) { 1411 offset_8 = -offset_8; 1412 am ^= U; 1413 } 1414 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte 1415 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback 1416 1417 // Post-indexed addressing requires W == 1; different than in addrmod2/3. 1418 if ((am & P) == 0) 1419 am |= W; 1420 1421 DCHECK(offset_8 >= 0); // no masking needed 1422 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8); 1423} 1424 1425 1426int Assembler::branch_offset(Label* L) { 1427 int target_pos; 1428 if (L->is_bound()) { 1429 target_pos = L->pos(); 1430 } else { 1431 if (L->is_linked()) { 1432 // Point to previous instruction that uses the link. 1433 target_pos = L->pos(); 1434 } else { 1435 // First entry of the link chain points to itself. 1436 target_pos = pc_offset(); 1437 } 1438 L->link_to(pc_offset()); 1439 } 1440 1441 // Block the emission of the constant pool, since the branch instruction must 1442 // be emitted at the pc offset recorded by the label. 1443 if (!is_const_pool_blocked()) BlockConstPoolFor(1); 1444 1445 return target_pos - (pc_offset() + kPcLoadDelta); 1446} 1447 1448 1449// Branch instructions. 1450void Assembler::b(int branch_offset, Condition cond) { 1451 DCHECK((branch_offset & 3) == 0); 1452 int imm24 = branch_offset >> 2; 1453 CHECK(is_int24(imm24)); 1454 emit(cond | B27 | B25 | (imm24 & kImm24Mask)); 1455 1456 if (cond == al) { 1457 // Dead code is a good location to emit the constant pool. 1458 CheckConstPool(false, false); 1459 } 1460} 1461 1462 1463void Assembler::bl(int branch_offset, Condition cond) { 1464 DCHECK((branch_offset & 3) == 0); 1465 int imm24 = branch_offset >> 2; 1466 CHECK(is_int24(imm24)); 1467 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); 1468} 1469 1470void Assembler::blx(int branch_offset) { 1471 DCHECK((branch_offset & 1) == 0); 1472 int h = ((branch_offset & 2) >> 1)*B24; 1473 int imm24 = branch_offset >> 2; 1474 CHECK(is_int24(imm24)); 1475 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); 1476} 1477 1478void Assembler::blx(Register target, Condition cond) { 1479 DCHECK(!target.is(pc)); 1480 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code()); 1481} 1482 1483void Assembler::bx(Register target, Condition cond) { 1484 DCHECK(!target.is(pc)); // use of pc is actually allowed, but discouraged 1485 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code()); 1486} 1487 1488 1489void Assembler::b(Label* L, Condition cond) { 1490 CheckBuffer(); 1491 b(branch_offset(L), cond); 1492} 1493 1494 1495void Assembler::bl(Label* L, Condition cond) { 1496 CheckBuffer(); 1497 bl(branch_offset(L), cond); 1498} 1499 1500 1501void Assembler::blx(Label* L) { 1502 CheckBuffer(); 1503 blx(branch_offset(L)); 1504} 1505 1506 1507// Data-processing instructions. 1508 1509void Assembler::and_(Register dst, Register src1, const Operand& src2, 1510 SBit s, Condition cond) { 1511 addrmod1(cond | AND | s, src1, dst, src2); 1512} 1513 1514 1515void Assembler::eor(Register dst, Register src1, const Operand& src2, 1516 SBit s, Condition cond) { 1517 addrmod1(cond | EOR | s, src1, dst, src2); 1518} 1519 1520 1521void Assembler::sub(Register dst, Register src1, const Operand& src2, 1522 SBit s, Condition cond) { 1523 addrmod1(cond | SUB | s, src1, dst, src2); 1524} 1525 1526 1527void Assembler::rsb(Register dst, Register src1, const Operand& src2, 1528 SBit s, Condition cond) { 1529 addrmod1(cond | RSB | s, src1, dst, src2); 1530} 1531 1532 1533void Assembler::add(Register dst, Register src1, const Operand& src2, 1534 SBit s, Condition cond) { 1535 addrmod1(cond | ADD | s, src1, dst, src2); 1536} 1537 1538 1539void Assembler::adc(Register dst, Register src1, const Operand& src2, 1540 SBit s, Condition cond) { 1541 addrmod1(cond | ADC | s, src1, dst, src2); 1542} 1543 1544 1545void Assembler::sbc(Register dst, Register src1, const Operand& src2, 1546 SBit s, Condition cond) { 1547 addrmod1(cond | SBC | s, src1, dst, src2); 1548} 1549 1550 1551void Assembler::rsc(Register dst, Register src1, const Operand& src2, 1552 SBit s, Condition cond) { 1553 addrmod1(cond | RSC | s, src1, dst, src2); 1554} 1555 1556 1557void Assembler::tst(Register src1, const Operand& src2, Condition cond) { 1558 addrmod1(cond | TST | S, src1, r0, src2); 1559} 1560 1561 1562void Assembler::teq(Register src1, const Operand& src2, Condition cond) { 1563 addrmod1(cond | TEQ | S, src1, r0, src2); 1564} 1565 1566 1567void Assembler::cmp(Register src1, const Operand& src2, Condition cond) { 1568 addrmod1(cond | CMP | S, src1, r0, src2); 1569} 1570 1571 1572void Assembler::cmp_raw_immediate( 1573 Register src, int raw_immediate, Condition cond) { 1574 DCHECK(is_uint12(raw_immediate)); 1575 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate); 1576} 1577 1578 1579void Assembler::cmn(Register src1, const Operand& src2, Condition cond) { 1580 addrmod1(cond | CMN | S, src1, r0, src2); 1581} 1582 1583 1584void Assembler::orr(Register dst, Register src1, const Operand& src2, 1585 SBit s, Condition cond) { 1586 addrmod1(cond | ORR | s, src1, dst, src2); 1587} 1588 1589 1590void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { 1591 // Don't allow nop instructions in the form mov rn, rn to be generated using 1592 // the mov instruction. They must be generated using nop(int/NopMarkerTypes) 1593 // or MarkCode(int/NopMarkerTypes) pseudo instructions. 1594 DCHECK(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); 1595 addrmod1(cond | MOV | s, r0, dst, src); 1596} 1597 1598 1599void Assembler::mov_label_offset(Register dst, Label* label) { 1600 if (label->is_bound()) { 1601 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag))); 1602 } else { 1603 // Emit the link to the label in the code stream followed by extra nop 1604 // instructions. 1605 // If the label is not linked, then start a new link chain by linking it to 1606 // itself, emitting pc_offset(). 1607 int link = label->is_linked() ? label->pos() : pc_offset(); 1608 label->link_to(pc_offset()); 1609 1610 // When the label is bound, these instructions will be patched with a 1611 // sequence of movw/movt or mov/orr/orr instructions. They will load the 1612 // destination register with the position of the label from the beginning 1613 // of the code. 1614 // 1615 // The link will be extracted from the first instruction and the destination 1616 // register from the second. 1617 // For ARMv7: 1618 // link 1619 // mov dst, dst 1620 // For ARMv6: 1621 // link 1622 // mov dst, dst 1623 // mov dst, dst 1624 // 1625 // When the label gets bound: target_at extracts the link and target_at_put 1626 // patches the instructions. 1627 CHECK(is_uint24(link)); 1628 BlockConstPoolScope block_const_pool(this); 1629 emit(link); 1630 nop(dst.code()); 1631 if (!CpuFeatures::IsSupported(ARMv7)) { 1632 nop(dst.code()); 1633 } 1634 } 1635} 1636 1637 1638void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { 1639 DCHECK(IsEnabled(ARMv7)); 1640 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); 1641} 1642 1643 1644void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { 1645 DCHECK(IsEnabled(ARMv7)); 1646 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); 1647} 1648 1649 1650void Assembler::bic(Register dst, Register src1, const Operand& src2, 1651 SBit s, Condition cond) { 1652 addrmod1(cond | BIC | s, src1, dst, src2); 1653} 1654 1655 1656void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) { 1657 addrmod1(cond | MVN | s, r0, dst, src); 1658} 1659 1660 1661// Multiply instructions. 1662void Assembler::mla(Register dst, Register src1, Register src2, Register srcA, 1663 SBit s, Condition cond) { 1664 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1665 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 | 1666 src2.code()*B8 | B7 | B4 | src1.code()); 1667} 1668 1669 1670void Assembler::mls(Register dst, Register src1, Register src2, Register srcA, 1671 Condition cond) { 1672 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1673 DCHECK(IsEnabled(ARMv7)); 1674 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 | 1675 src2.code()*B8 | B7 | B4 | src1.code()); 1676} 1677 1678 1679void Assembler::sdiv(Register dst, Register src1, Register src2, 1680 Condition cond) { 1681 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1682 DCHECK(IsEnabled(SUDIV)); 1683 emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 | 1684 src2.code()*B8 | B4 | src1.code()); 1685} 1686 1687 1688void Assembler::udiv(Register dst, Register src1, Register src2, 1689 Condition cond) { 1690 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1691 DCHECK(IsEnabled(SUDIV)); 1692 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xf * B12 | 1693 src2.code() * B8 | B4 | src1.code()); 1694} 1695 1696 1697void Assembler::mul(Register dst, Register src1, Register src2, SBit s, 1698 Condition cond) { 1699 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1700 // dst goes in bits 16-19 for this instruction! 1701 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code()); 1702} 1703 1704 1705void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA, 1706 Condition cond) { 1707 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); 1708 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 1709 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code()); 1710} 1711 1712 1713void Assembler::smmul(Register dst, Register src1, Register src2, 1714 Condition cond) { 1715 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); 1716 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 | 1717 src2.code() * B8 | B4 | src1.code()); 1718} 1719 1720 1721void Assembler::smlal(Register dstL, 1722 Register dstH, 1723 Register src1, 1724 Register src2, 1725 SBit s, 1726 Condition cond) { 1727 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1728 DCHECK(!dstL.is(dstH)); 1729 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1730 src2.code()*B8 | B7 | B4 | src1.code()); 1731} 1732 1733 1734void Assembler::smull(Register dstL, 1735 Register dstH, 1736 Register src1, 1737 Register src2, 1738 SBit s, 1739 Condition cond) { 1740 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1741 DCHECK(!dstL.is(dstH)); 1742 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 | 1743 src2.code()*B8 | B7 | B4 | src1.code()); 1744} 1745 1746 1747void Assembler::umlal(Register dstL, 1748 Register dstH, 1749 Register src1, 1750 Register src2, 1751 SBit s, 1752 Condition cond) { 1753 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1754 DCHECK(!dstL.is(dstH)); 1755 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 | 1756 src2.code()*B8 | B7 | B4 | src1.code()); 1757} 1758 1759 1760void Assembler::umull(Register dstL, 1761 Register dstH, 1762 Register src1, 1763 Register src2, 1764 SBit s, 1765 Condition cond) { 1766 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc)); 1767 DCHECK(!dstL.is(dstH)); 1768 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 | 1769 src2.code()*B8 | B7 | B4 | src1.code()); 1770} 1771 1772 1773// Miscellaneous arithmetic instructions. 1774void Assembler::clz(Register dst, Register src, Condition cond) { 1775 DCHECK(!dst.is(pc) && !src.is(pc)); 1776 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 | 1777 15*B8 | CLZ | src.code()); 1778} 1779 1780 1781// Saturating instructions. 1782 1783// Unsigned saturate. 1784void Assembler::usat(Register dst, 1785 int satpos, 1786 const Operand& src, 1787 Condition cond) { 1788 DCHECK(!dst.is(pc) && !src.rm_.is(pc)); 1789 DCHECK((satpos >= 0) && (satpos <= 31)); 1790 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL)); 1791 DCHECK(src.rs_.is(no_reg)); 1792 1793 int sh = 0; 1794 if (src.shift_op_ == ASR) { 1795 sh = 1; 1796 } 1797 1798 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 | 1799 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code()); 1800} 1801 1802 1803// Bitfield manipulation instructions. 1804 1805// Unsigned bit field extract. 1806// Extracts #width adjacent bits from position #lsb in a register, and 1807// writes them to the low bits of a destination register. 1808// ubfx dst, src, #lsb, #width 1809void Assembler::ubfx(Register dst, 1810 Register src, 1811 int lsb, 1812 int width, 1813 Condition cond) { 1814 DCHECK(IsEnabled(ARMv7)); 1815 DCHECK(!dst.is(pc) && !src.is(pc)); 1816 DCHECK((lsb >= 0) && (lsb <= 31)); 1817 DCHECK((width >= 1) && (width <= (32 - lsb))); 1818 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 | 1819 lsb*B7 | B6 | B4 | src.code()); 1820} 1821 1822 1823// Signed bit field extract. 1824// Extracts #width adjacent bits from position #lsb in a register, and 1825// writes them to the low bits of a destination register. The extracted 1826// value is sign extended to fill the destination register. 1827// sbfx dst, src, #lsb, #width 1828void Assembler::sbfx(Register dst, 1829 Register src, 1830 int lsb, 1831 int width, 1832 Condition cond) { 1833 DCHECK(IsEnabled(ARMv7)); 1834 DCHECK(!dst.is(pc) && !src.is(pc)); 1835 DCHECK((lsb >= 0) && (lsb <= 31)); 1836 DCHECK((width >= 1) && (width <= (32 - lsb))); 1837 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 | 1838 lsb*B7 | B6 | B4 | src.code()); 1839} 1840 1841 1842// Bit field clear. 1843// Sets #width adjacent bits at position #lsb in the destination register 1844// to zero, preserving the value of the other bits. 1845// bfc dst, #lsb, #width 1846void Assembler::bfc(Register dst, int lsb, int width, Condition cond) { 1847 DCHECK(IsEnabled(ARMv7)); 1848 DCHECK(!dst.is(pc)); 1849 DCHECK((lsb >= 0) && (lsb <= 31)); 1850 DCHECK((width >= 1) && (width <= (32 - lsb))); 1851 int msb = lsb + width - 1; 1852 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf); 1853} 1854 1855 1856// Bit field insert. 1857// Inserts #width adjacent bits from the low bits of the source register 1858// into position #lsb of the destination register. 1859// bfi dst, src, #lsb, #width 1860void Assembler::bfi(Register dst, 1861 Register src, 1862 int lsb, 1863 int width, 1864 Condition cond) { 1865 DCHECK(IsEnabled(ARMv7)); 1866 DCHECK(!dst.is(pc) && !src.is(pc)); 1867 DCHECK((lsb >= 0) && (lsb <= 31)); 1868 DCHECK((width >= 1) && (width <= (32 - lsb))); 1869 int msb = lsb + width - 1; 1870 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 1871 src.code()); 1872} 1873 1874 1875void Assembler::pkhbt(Register dst, 1876 Register src1, 1877 const Operand& src2, 1878 Condition cond ) { 1879 // Instruction details available in ARM DDI 0406C.b, A8.8.125. 1880 // cond(31-28) | 01101000(27-20) | Rn(19-16) | 1881 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0) 1882 DCHECK(!dst.is(pc)); 1883 DCHECK(!src1.is(pc)); 1884 DCHECK(!src2.rm().is(pc)); 1885 DCHECK(!src2.rm().is(no_reg)); 1886 DCHECK(src2.rs().is(no_reg)); 1887 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31)); 1888 DCHECK(src2.shift_op() == LSL); 1889 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 | 1890 src2.shift_imm_*B7 | B4 | src2.rm().code()); 1891} 1892 1893 1894void Assembler::pkhtb(Register dst, 1895 Register src1, 1896 const Operand& src2, 1897 Condition cond) { 1898 // Instruction details available in ARM DDI 0406C.b, A8.8.125. 1899 // cond(31-28) | 01101000(27-20) | Rn(19-16) | 1900 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0) 1901 DCHECK(!dst.is(pc)); 1902 DCHECK(!src1.is(pc)); 1903 DCHECK(!src2.rm().is(pc)); 1904 DCHECK(!src2.rm().is(no_reg)); 1905 DCHECK(src2.rs().is(no_reg)); 1906 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32)); 1907 DCHECK(src2.shift_op() == ASR); 1908 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_; 1909 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 | 1910 asr*B7 | B6 | B4 | src2.rm().code()); 1911} 1912 1913 1914void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) { 1915 // Instruction details available in ARM DDI 0406C.b, A8.8.233. 1916 // cond(31-28) | 01101010(27-20) | 1111(19-16) | 1917 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1918 DCHECK(!dst.is(pc)); 1919 DCHECK(!src.is(pc)); 1920 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1921 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 | 1922 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1923} 1924 1925 1926void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate, 1927 Condition cond) { 1928 // Instruction details available in ARM DDI 0406C.b, A8.8.233. 1929 // cond(31-28) | 01101010(27-20) | Rn(19-16) | 1930 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1931 DCHECK(!dst.is(pc)); 1932 DCHECK(!src1.is(pc)); 1933 DCHECK(!src2.is(pc)); 1934 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1935 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 | 1936 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1937} 1938 1939 1940void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) { 1941 // Instruction details available in ARM DDI 0406C.b, A8.8.235. 1942 // cond(31-28) | 01101011(27-20) | 1111(19-16) | 1943 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1944 DCHECK(!dst.is(pc)); 1945 DCHECK(!src.is(pc)); 1946 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1947 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 | 1948 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1949} 1950 1951 1952void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate, 1953 Condition cond) { 1954 // Instruction details available in ARM DDI 0406C.b, A8.8.235. 1955 // cond(31-28) | 01101011(27-20) | Rn(19-16) | 1956 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1957 DCHECK(!dst.is(pc)); 1958 DCHECK(!src1.is(pc)); 1959 DCHECK(!src2.is(pc)); 1960 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1961 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 | 1962 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1963} 1964 1965 1966void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) { 1967 // Instruction details available in ARM DDI 0406C.b, A8.8.274. 1968 // cond(31-28) | 01101110(27-20) | 1111(19-16) | 1969 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1970 DCHECK(!dst.is(pc)); 1971 DCHECK(!src.is(pc)); 1972 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1973 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 | 1974 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 1975} 1976 1977 1978void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate, 1979 Condition cond) { 1980 // Instruction details available in ARM DDI 0406C.b, A8.8.271. 1981 // cond(31-28) | 01101110(27-20) | Rn(19-16) | 1982 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1983 DCHECK(!dst.is(pc)); 1984 DCHECK(!src1.is(pc)); 1985 DCHECK(!src2.is(pc)); 1986 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1987 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 | 1988 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 1989} 1990 1991 1992void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) { 1993 // Instruction details available in ARM DDI 0406C.b, A8.8.275. 1994 // cond(31-28) | 01101100(27-20) | 1111(19-16) | 1995 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 1996 DCHECK(!dst.is(pc)); 1997 DCHECK(!src.is(pc)); 1998 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 1999 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 | 2000 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 2001} 2002 2003 2004void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) { 2005 // Instruction details available in ARM DDI 0406C.b, A8.8.276. 2006 // cond(31-28) | 01101111(27-20) | 1111(19-16) | 2007 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 2008 DCHECK(!dst.is(pc)); 2009 DCHECK(!src.is(pc)); 2010 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 2011 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 | 2012 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code()); 2013} 2014 2015 2016void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate, 2017 Condition cond) { 2018 // Instruction details available in ARM DDI 0406C.b, A8.8.273. 2019 // cond(31-28) | 01101111(27-20) | Rn(19-16) | 2020 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) 2021 DCHECK(!dst.is(pc)); 2022 DCHECK(!src1.is(pc)); 2023 DCHECK(!src2.is(pc)); 2024 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24); 2025 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 | 2026 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code()); 2027} 2028 2029 2030void Assembler::rbit(Register dst, Register src, Condition cond) { 2031 // Instruction details available in ARM DDI 0406C.b, A8.8.144. 2032 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0) 2033 DCHECK(IsEnabled(ARMv7)); 2034 DCHECK(!dst.is(pc)); 2035 DCHECK(!src.is(pc)); 2036 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code()); 2037} 2038 2039 2040// Status register access instructions. 2041void Assembler::mrs(Register dst, SRegister s, Condition cond) { 2042 DCHECK(!dst.is(pc)); 2043 emit(cond | B24 | s | 15*B16 | dst.code()*B12); 2044} 2045 2046 2047void Assembler::msr(SRegisterFieldMask fields, const Operand& src, 2048 Condition cond) { 2049 DCHECK((fields & 0x000f0000) != 0); // At least one field must be set. 2050 DCHECK(((fields & 0xfff0ffff) == CPSR) || ((fields & 0xfff0ffff) == SPSR)); 2051 Instr instr; 2052 if (!src.rm_.is_valid()) { 2053 // Immediate. 2054 uint32_t rotate_imm; 2055 uint32_t immed_8; 2056 if (src.must_output_reloc_info(this) || 2057 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { 2058 // Immediate operand cannot be encoded, load it first to register ip. 2059 move_32_bit_immediate(ip, src); 2060 msr(fields, Operand(ip), cond); 2061 return; 2062 } 2063 instr = I | rotate_imm*B8 | immed_8; 2064 } else { 2065 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed 2066 instr = src.rm_.code(); 2067 } 2068 emit(cond | instr | B24 | B21 | fields | 15*B12); 2069} 2070 2071 2072// Load/Store instructions. 2073void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { 2074 addrmod2(cond | B26 | L, dst, src); 2075} 2076 2077 2078void Assembler::str(Register src, const MemOperand& dst, Condition cond) { 2079 addrmod2(cond | B26, src, dst); 2080} 2081 2082 2083void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) { 2084 addrmod2(cond | B26 | B | L, dst, src); 2085} 2086 2087 2088void Assembler::strb(Register src, const MemOperand& dst, Condition cond) { 2089 addrmod2(cond | B26 | B, src, dst); 2090} 2091 2092 2093void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) { 2094 addrmod3(cond | L | B7 | H | B4, dst, src); 2095} 2096 2097 2098void Assembler::strh(Register src, const MemOperand& dst, Condition cond) { 2099 addrmod3(cond | B7 | H | B4, src, dst); 2100} 2101 2102 2103void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) { 2104 addrmod3(cond | L | B7 | S6 | B4, dst, src); 2105} 2106 2107 2108void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) { 2109 addrmod3(cond | L | B7 | S6 | H | B4, dst, src); 2110} 2111 2112 2113void Assembler::ldrd(Register dst1, Register dst2, 2114 const MemOperand& src, Condition cond) { 2115 DCHECK(src.rm().is(no_reg)); 2116 DCHECK(!dst1.is(lr)); // r14. 2117 DCHECK_EQ(0, dst1.code() % 2); 2118 DCHECK_EQ(dst1.code() + 1, dst2.code()); 2119 addrmod3(cond | B7 | B6 | B4, dst1, src); 2120} 2121 2122 2123void Assembler::strd(Register src1, Register src2, 2124 const MemOperand& dst, Condition cond) { 2125 DCHECK(dst.rm().is(no_reg)); 2126 DCHECK(!src1.is(lr)); // r14. 2127 DCHECK_EQ(0, src1.code() % 2); 2128 DCHECK_EQ(src1.code() + 1, src2.code()); 2129 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst); 2130} 2131 2132// Load/Store exclusive instructions. 2133void Assembler::ldrex(Register dst, Register src, Condition cond) { 2134 // Instruction details available in ARM DDI 0406C.b, A8.8.75. 2135 // cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) 2136 emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xf9f); 2137} 2138 2139void Assembler::strex(Register src1, Register src2, Register dst, 2140 Condition cond) { 2141 // Instruction details available in ARM DDI 0406C.b, A8.8.212. 2142 // cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | 2143 // Rt(3-0) 2144 emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xf9 * B4 | 2145 src2.code()); 2146} 2147 2148void Assembler::ldrexb(Register dst, Register src, Condition cond) { 2149 // Instruction details available in ARM DDI 0406C.b, A8.8.76. 2150 // cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) 2151 emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 | 2152 0xf9f); 2153} 2154 2155void Assembler::strexb(Register src1, Register src2, Register dst, 2156 Condition cond) { 2157 // Instruction details available in ARM DDI 0406C.b, A8.8.213. 2158 // cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | 2159 // Rt(3-0) 2160 emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 | 2161 0xf9 * B4 | src2.code()); 2162} 2163 2164void Assembler::ldrexh(Register dst, Register src, Condition cond) { 2165 // Instruction details available in ARM DDI 0406C.b, A8.8.78. 2166 // cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) 2167 emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 | 2168 dst.code() * B12 | 0xf9f); 2169} 2170 2171void Assembler::strexh(Register src1, Register src2, Register dst, 2172 Condition cond) { 2173 // Instruction details available in ARM DDI 0406C.b, A8.8.215. 2174 // cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | 2175 // Rt(3-0) 2176 emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 | 2177 0xf9 * B4 | src2.code()); 2178} 2179 2180// Preload instructions. 2181void Assembler::pld(const MemOperand& address) { 2182 // Instruction details available in ARM DDI 0406C.b, A8.8.128. 2183 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) | 2184 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) | 2185 DCHECK(address.rm().is(no_reg)); 2186 DCHECK(address.am() == Offset); 2187 int U = B23; 2188 int offset = address.offset(); 2189 if (offset < 0) { 2190 offset = -offset; 2191 U = 0; 2192 } 2193 DCHECK(offset < 4096); 2194 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 | 2195 0xf*B12 | offset); 2196} 2197 2198 2199// Load/Store multiple instructions. 2200void Assembler::ldm(BlockAddrMode am, 2201 Register base, 2202 RegList dst, 2203 Condition cond) { 2204 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable. 2205 DCHECK(base.is(sp) || (dst & sp.bit()) == 0); 2206 2207 addrmod4(cond | B27 | am | L, base, dst); 2208 2209 // Emit the constant pool after a function return implemented by ldm ..{..pc}. 2210 if (cond == al && (dst & pc.bit()) != 0) { 2211 // There is a slight chance that the ldm instruction was actually a call, 2212 // in which case it would be wrong to return into the constant pool; we 2213 // recognize this case by checking if the emission of the pool was blocked 2214 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is 2215 // the case, we emit a jump over the pool. 2216 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize); 2217 } 2218} 2219 2220 2221void Assembler::stm(BlockAddrMode am, 2222 Register base, 2223 RegList src, 2224 Condition cond) { 2225 addrmod4(cond | B27 | am, base, src); 2226} 2227 2228 2229// Exception-generating instructions and debugging support. 2230// Stops with a non-negative code less than kNumOfWatchedStops support 2231// enabling/disabling and a counter feature. See simulator-arm.h . 2232void Assembler::stop(const char* msg, Condition cond, int32_t code) { 2233#ifndef __arm__ 2234 DCHECK(code >= kDefaultStopCode); 2235 { 2236 // The Simulator will handle the stop instruction and get the message 2237 // address. It expects to find the address just after the svc instruction. 2238 BlockConstPoolScope block_const_pool(this); 2239 if (code >= 0) { 2240 svc(kStopCode + code, cond); 2241 } else { 2242 svc(kStopCode + kMaxStopCode, cond); 2243 } 2244 // Do not embed the message string address! We used to do this, but that 2245 // made snapshots created from position-independent executable builds 2246 // non-deterministic. 2247 // TODO(yangguo): remove this field entirely. 2248 nop(); 2249 } 2250#else // def __arm__ 2251 if (cond != al) { 2252 Label skip; 2253 b(&skip, NegateCondition(cond)); 2254 bkpt(0); 2255 bind(&skip); 2256 } else { 2257 bkpt(0); 2258 } 2259#endif // def __arm__ 2260} 2261 2262void Assembler::bkpt(uint32_t imm16) { 2263 DCHECK(is_uint16(imm16)); 2264 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf)); 2265} 2266 2267 2268void Assembler::svc(uint32_t imm24, Condition cond) { 2269 DCHECK(is_uint24(imm24)); 2270 emit(cond | 15*B24 | imm24); 2271} 2272 2273 2274void Assembler::dmb(BarrierOption option) { 2275 if (CpuFeatures::IsSupported(ARMv7)) { 2276 // Details available in ARM DDI 0406C.b, A8-378. 2277 emit(kSpecialCondition | 0x57ff * B12 | 5 * B4 | option); 2278 } else { 2279 // Details available in ARM DDI 0406C.b, B3-1750. 2280 // CP15DMB: CRn=c7, opc1=0, CRm=c10, opc2=5, Rt is ignored. 2281 mcr(p15, 0, r0, cr7, cr10, 5); 2282 } 2283} 2284 2285 2286void Assembler::dsb(BarrierOption option) { 2287 if (CpuFeatures::IsSupported(ARMv7)) { 2288 // Details available in ARM DDI 0406C.b, A8-380. 2289 emit(kSpecialCondition | 0x57ff * B12 | 4 * B4 | option); 2290 } else { 2291 // Details available in ARM DDI 0406C.b, B3-1750. 2292 // CP15DSB: CRn=c7, opc1=0, CRm=c10, opc2=4, Rt is ignored. 2293 mcr(p15, 0, r0, cr7, cr10, 4); 2294 } 2295} 2296 2297 2298void Assembler::isb(BarrierOption option) { 2299 if (CpuFeatures::IsSupported(ARMv7)) { 2300 // Details available in ARM DDI 0406C.b, A8-389. 2301 emit(kSpecialCondition | 0x57ff * B12 | 6 * B4 | option); 2302 } else { 2303 // Details available in ARM DDI 0406C.b, B3-1750. 2304 // CP15ISB: CRn=c7, opc1=0, CRm=c5, opc2=4, Rt is ignored. 2305 mcr(p15, 0, r0, cr7, cr5, 4); 2306 } 2307} 2308 2309 2310// Coprocessor instructions. 2311void Assembler::cdp(Coprocessor coproc, 2312 int opcode_1, 2313 CRegister crd, 2314 CRegister crn, 2315 CRegister crm, 2316 int opcode_2, 2317 Condition cond) { 2318 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2)); 2319 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 | 2320 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code()); 2321} 2322 2323void Assembler::cdp2(Coprocessor coproc, int opcode_1, CRegister crd, 2324 CRegister crn, CRegister crm, int opcode_2) { 2325 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition); 2326} 2327 2328 2329void Assembler::mcr(Coprocessor coproc, 2330 int opcode_1, 2331 Register rd, 2332 CRegister crn, 2333 CRegister crm, 2334 int opcode_2, 2335 Condition cond) { 2336 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2)); 2337 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 | 2338 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 2339} 2340 2341void Assembler::mcr2(Coprocessor coproc, int opcode_1, Register rd, 2342 CRegister crn, CRegister crm, int opcode_2) { 2343 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 2344} 2345 2346 2347void Assembler::mrc(Coprocessor coproc, 2348 int opcode_1, 2349 Register rd, 2350 CRegister crn, 2351 CRegister crm, 2352 int opcode_2, 2353 Condition cond) { 2354 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2)); 2355 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 | 2356 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code()); 2357} 2358 2359void Assembler::mrc2(Coprocessor coproc, int opcode_1, Register rd, 2360 CRegister crn, CRegister crm, int opcode_2) { 2361 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); 2362} 2363 2364 2365void Assembler::ldc(Coprocessor coproc, 2366 CRegister crd, 2367 const MemOperand& src, 2368 LFlag l, 2369 Condition cond) { 2370 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src); 2371} 2372 2373 2374void Assembler::ldc(Coprocessor coproc, 2375 CRegister crd, 2376 Register rn, 2377 int option, 2378 LFlag l, 2379 Condition cond) { 2380 // Unindexed addressing. 2381 DCHECK(is_uint8(option)); 2382 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 | 2383 coproc*B8 | (option & 255)); 2384} 2385 2386void Assembler::ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, 2387 LFlag l) { 2388 ldc(coproc, crd, src, l, kSpecialCondition); 2389} 2390 2391void Assembler::ldc2(Coprocessor coproc, CRegister crd, Register rn, int option, 2392 LFlag l) { 2393 ldc(coproc, crd, rn, option, l, kSpecialCondition); 2394} 2395 2396 2397// Support for VFP. 2398 2399void Assembler::vldr(const DwVfpRegister dst, 2400 const Register base, 2401 int offset, 2402 const Condition cond) { 2403 // Ddst = MEM(Rbase + offset). 2404 // Instruction details available in ARM DDI 0406C.b, A8-924. 2405 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) | 2406 // Vd(15-12) | 1011(11-8) | offset 2407 DCHECK(VfpRegisterIsAvailable(dst)); 2408 int u = 1; 2409 if (offset < 0) { 2410 CHECK(offset != kMinInt); 2411 offset = -offset; 2412 u = 0; 2413 } 2414 int vd, d; 2415 dst.split_code(&vd, &d); 2416 2417 DCHECK(offset >= 0); 2418 if ((offset % 4) == 0 && (offset / 4) < 256) { 2419 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 | 2420 0xB*B8 | ((offset / 4) & 255)); 2421 } else { 2422 // Larger offsets must be handled by computing the correct address 2423 // in the ip register. 2424 DCHECK(!base.is(ip)); 2425 if (u == 1) { 2426 add(ip, base, Operand(offset)); 2427 } else { 2428 sub(ip, base, Operand(offset)); 2429 } 2430 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8); 2431 } 2432} 2433 2434 2435void Assembler::vldr(const DwVfpRegister dst, 2436 const MemOperand& operand, 2437 const Condition cond) { 2438 DCHECK(VfpRegisterIsAvailable(dst)); 2439 DCHECK(operand.am_ == Offset); 2440 if (operand.rm().is_valid()) { 2441 add(ip, operand.rn(), 2442 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2443 vldr(dst, ip, 0, cond); 2444 } else { 2445 vldr(dst, operand.rn(), operand.offset(), cond); 2446 } 2447} 2448 2449 2450void Assembler::vldr(const SwVfpRegister dst, 2451 const Register base, 2452 int offset, 2453 const Condition cond) { 2454 // Sdst = MEM(Rbase + offset). 2455 // Instruction details available in ARM DDI 0406A, A8-628. 2456 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) | 2457 // Vdst(15-12) | 1010(11-8) | offset 2458 int u = 1; 2459 if (offset < 0) { 2460 offset = -offset; 2461 u = 0; 2462 } 2463 int sd, d; 2464 dst.split_code(&sd, &d); 2465 DCHECK(offset >= 0); 2466 2467 if ((offset % 4) == 0 && (offset / 4) < 256) { 2468 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 | 2469 0xA*B8 | ((offset / 4) & 255)); 2470 } else { 2471 // Larger offsets must be handled by computing the correct address 2472 // in the ip register. 2473 DCHECK(!base.is(ip)); 2474 if (u == 1) { 2475 add(ip, base, Operand(offset)); 2476 } else { 2477 sub(ip, base, Operand(offset)); 2478 } 2479 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 2480 } 2481} 2482 2483 2484void Assembler::vldr(const SwVfpRegister dst, 2485 const MemOperand& operand, 2486 const Condition cond) { 2487 DCHECK(operand.am_ == Offset); 2488 if (operand.rm().is_valid()) { 2489 add(ip, operand.rn(), 2490 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2491 vldr(dst, ip, 0, cond); 2492 } else { 2493 vldr(dst, operand.rn(), operand.offset(), cond); 2494 } 2495} 2496 2497 2498void Assembler::vstr(const DwVfpRegister src, 2499 const Register base, 2500 int offset, 2501 const Condition cond) { 2502 // MEM(Rbase + offset) = Dsrc. 2503 // Instruction details available in ARM DDI 0406C.b, A8-1082. 2504 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) | 2505 // Vd(15-12) | 1011(11-8) | (offset/4) 2506 DCHECK(VfpRegisterIsAvailable(src)); 2507 int u = 1; 2508 if (offset < 0) { 2509 CHECK(offset != kMinInt); 2510 offset = -offset; 2511 u = 0; 2512 } 2513 DCHECK(offset >= 0); 2514 int vd, d; 2515 src.split_code(&vd, &d); 2516 2517 if ((offset % 4) == 0 && (offset / 4) < 256) { 2518 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 | 2519 ((offset / 4) & 255)); 2520 } else { 2521 // Larger offsets must be handled by computing the correct address 2522 // in the ip register. 2523 DCHECK(!base.is(ip)); 2524 if (u == 1) { 2525 add(ip, base, Operand(offset)); 2526 } else { 2527 sub(ip, base, Operand(offset)); 2528 } 2529 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8); 2530 } 2531} 2532 2533 2534void Assembler::vstr(const DwVfpRegister src, 2535 const MemOperand& operand, 2536 const Condition cond) { 2537 DCHECK(VfpRegisterIsAvailable(src)); 2538 DCHECK(operand.am_ == Offset); 2539 if (operand.rm().is_valid()) { 2540 add(ip, operand.rn(), 2541 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2542 vstr(src, ip, 0, cond); 2543 } else { 2544 vstr(src, operand.rn(), operand.offset(), cond); 2545 } 2546} 2547 2548 2549void Assembler::vstr(const SwVfpRegister src, 2550 const Register base, 2551 int offset, 2552 const Condition cond) { 2553 // MEM(Rbase + offset) = SSrc. 2554 // Instruction details available in ARM DDI 0406A, A8-786. 2555 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) | 2556 // Vdst(15-12) | 1010(11-8) | (offset/4) 2557 int u = 1; 2558 if (offset < 0) { 2559 CHECK(offset != kMinInt); 2560 offset = -offset; 2561 u = 0; 2562 } 2563 int sd, d; 2564 src.split_code(&sd, &d); 2565 DCHECK(offset >= 0); 2566 if ((offset % 4) == 0 && (offset / 4) < 256) { 2567 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 | 2568 0xA*B8 | ((offset / 4) & 255)); 2569 } else { 2570 // Larger offsets must be handled by computing the correct address 2571 // in the ip register. 2572 DCHECK(!base.is(ip)); 2573 if (u == 1) { 2574 add(ip, base, Operand(offset)); 2575 } else { 2576 sub(ip, base, Operand(offset)); 2577 } 2578 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8); 2579 } 2580} 2581 2582 2583void Assembler::vstr(const SwVfpRegister src, 2584 const MemOperand& operand, 2585 const Condition cond) { 2586 DCHECK(operand.am_ == Offset); 2587 if (operand.rm().is_valid()) { 2588 add(ip, operand.rn(), 2589 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_)); 2590 vstr(src, ip, 0, cond); 2591 } else { 2592 vstr(src, operand.rn(), operand.offset(), cond); 2593 } 2594} 2595 2596void Assembler::vldm(BlockAddrMode am, Register base, DwVfpRegister first, 2597 DwVfpRegister last, Condition cond) { 2598 // Instruction details available in ARM DDI 0406C.b, A8-922. 2599 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 2600 // first(15-12) | 1011(11-8) | (count * 2) 2601 DCHECK_LE(first.code(), last.code()); 2602 DCHECK(VfpRegisterIsAvailable(last)); 2603 DCHECK(am == ia || am == ia_w || am == db_w); 2604 DCHECK(!base.is(pc)); 2605 2606 int sd, d; 2607 first.split_code(&sd, &d); 2608 int count = last.code() - first.code() + 1; 2609 DCHECK(count <= 16); 2610 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 2611 0xB*B8 | count*2); 2612} 2613 2614void Assembler::vstm(BlockAddrMode am, Register base, DwVfpRegister first, 2615 DwVfpRegister last, Condition cond) { 2616 // Instruction details available in ARM DDI 0406C.b, A8-1080. 2617 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 2618 // first(15-12) | 1011(11-8) | (count * 2) 2619 DCHECK_LE(first.code(), last.code()); 2620 DCHECK(VfpRegisterIsAvailable(last)); 2621 DCHECK(am == ia || am == ia_w || am == db_w); 2622 DCHECK(!base.is(pc)); 2623 2624 int sd, d; 2625 first.split_code(&sd, &d); 2626 int count = last.code() - first.code() + 1; 2627 DCHECK(count <= 16); 2628 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 2629 0xB*B8 | count*2); 2630} 2631 2632void Assembler::vldm(BlockAddrMode am, Register base, SwVfpRegister first, 2633 SwVfpRegister last, Condition cond) { 2634 // Instruction details available in ARM DDI 0406A, A8-626. 2635 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) | 2636 // first(15-12) | 1010(11-8) | (count/2) 2637 DCHECK_LE(first.code(), last.code()); 2638 DCHECK(am == ia || am == ia_w || am == db_w); 2639 DCHECK(!base.is(pc)); 2640 2641 int sd, d; 2642 first.split_code(&sd, &d); 2643 int count = last.code() - first.code() + 1; 2644 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 | 2645 0xA*B8 | count); 2646} 2647 2648void Assembler::vstm(BlockAddrMode am, Register base, SwVfpRegister first, 2649 SwVfpRegister last, Condition cond) { 2650 // Instruction details available in ARM DDI 0406A, A8-784. 2651 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) | 2652 // first(15-12) | 1011(11-8) | (count/2) 2653 DCHECK_LE(first.code(), last.code()); 2654 DCHECK(am == ia || am == ia_w || am == db_w); 2655 DCHECK(!base.is(pc)); 2656 2657 int sd, d; 2658 first.split_code(&sd, &d); 2659 int count = last.code() - first.code() + 1; 2660 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 | 2661 0xA*B8 | count); 2662} 2663 2664 2665static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) { 2666 uint64_t i; 2667 memcpy(&i, &d, 8); 2668 2669 *lo = i & 0xffffffff; 2670 *hi = i >> 32; 2671} 2672 2673 2674// Only works for little endian floating point formats. 2675// We don't support VFP on the mixed endian floating point platform. 2676static bool FitsVmovFPImmediate(double d, uint32_t* encoding) { 2677 // VMOV can accept an immediate of the form: 2678 // 2679 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7 2680 // 2681 // The immediate is encoded using an 8-bit quantity, comprised of two 2682 // 4-bit fields. For an 8-bit immediate of the form: 2683 // 2684 // [abcdefgh] 2685 // 2686 // where a is the MSB and h is the LSB, an immediate 64-bit double can be 2687 // created of the form: 2688 // 2689 // [aBbbbbbb,bbcdefgh,00000000,00000000, 2690 // 00000000,00000000,00000000,00000000] 2691 // 2692 // where B = ~b. 2693 // 2694 2695 uint32_t lo, hi; 2696 DoubleAsTwoUInt32(d, &lo, &hi); 2697 2698 // The most obvious constraint is the long block of zeroes. 2699 if ((lo != 0) || ((hi & 0xffff) != 0)) { 2700 return false; 2701 } 2702 2703 // Bits 61:54 must be all clear or all set. 2704 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) { 2705 return false; 2706 } 2707 2708 // Bit 62 must be NOT bit 61. 2709 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) { 2710 return false; 2711 } 2712 2713 // Create the encoded immediate in the form: 2714 // [00000000,0000abcd,00000000,0000efgh] 2715 *encoding = (hi >> 16) & 0xf; // Low nybble. 2716 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble. 2717 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble. 2718 2719 return true; 2720} 2721 2722 2723void Assembler::vmov(const SwVfpRegister dst, float imm) { 2724 uint32_t enc; 2725 if (CpuFeatures::IsSupported(VFPv3) && FitsVmovFPImmediate(imm, &enc)) { 2726 CpuFeatureScope scope(this, VFPv3); 2727 // The float can be encoded in the instruction. 2728 // 2729 // Sd = immediate 2730 // Instruction details available in ARM DDI 0406C.b, A8-936. 2731 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) | 2732 // Vd(15-12) | 101(11-9) | sz=0(8) | imm4L(3-0) 2733 int vd, d; 2734 dst.split_code(&vd, &d); 2735 emit(al | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | enc); 2736 } else { 2737 mov(ip, Operand(bit_cast<int32_t>(imm))); 2738 vmov(dst, ip); 2739 } 2740} 2741 2742 2743void Assembler::vmov(const DwVfpRegister dst, 2744 double imm, 2745 const Register scratch) { 2746 DCHECK(VfpRegisterIsAvailable(dst)); 2747 DCHECK(!scratch.is(ip)); 2748 uint32_t enc; 2749 // If the embedded constant pool is disabled, we can use the normal, inline 2750 // constant pool. If the embedded constant pool is enabled (via 2751 // FLAG_enable_embedded_constant_pool), we can only use it where the pool 2752 // pointer (pp) is valid. 2753 bool can_use_pool = 2754 !FLAG_enable_embedded_constant_pool || is_constant_pool_available(); 2755 if (CpuFeatures::IsSupported(VFPv3) && FitsVmovFPImmediate(imm, &enc)) { 2756 CpuFeatureScope scope(this, VFPv3); 2757 // The double can be encoded in the instruction. 2758 // 2759 // Dd = immediate 2760 // Instruction details available in ARM DDI 0406C.b, A8-936. 2761 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) | 2762 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0) 2763 int vd, d; 2764 dst.split_code(&vd, &d); 2765 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc); 2766 } else if (CpuFeatures::IsSupported(ARMv7) && FLAG_enable_vldr_imm && 2767 can_use_pool) { 2768 CpuFeatureScope scope(this, ARMv7); 2769 // TODO(jfb) Temporarily turned off until we have constant blinding or 2770 // some equivalent mitigation: an attacker can otherwise control 2771 // generated data which also happens to be executable, a Very Bad 2772 // Thing indeed. 2773 // Blinding gets tricky because we don't have xor, we probably 2774 // need to add/subtract without losing precision, which requires a 2775 // cookie value that Lithium is probably better positioned to 2776 // choose. 2777 // We could also add a few peepholes here like detecting 0.0 and 2778 // -0.0 and doing a vmov from the sequestered d14, forcing denorms 2779 // to zero (we set flush-to-zero), and normalizing NaN values. 2780 // We could also detect redundant values. 2781 // The code could also randomize the order of values, though 2782 // that's tricky because vldr has a limited reach. Furthermore 2783 // it breaks load locality. 2784 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm); 2785 if (access == ConstantPoolEntry::OVERFLOWED) { 2786 DCHECK(FLAG_enable_embedded_constant_pool); 2787 // Emit instructions to load constant pool offset. 2788 movw(ip, 0); 2789 movt(ip, 0); 2790 // Load from constant pool at offset. 2791 vldr(dst, MemOperand(pp, ip)); 2792 } else { 2793 DCHECK(access == ConstantPoolEntry::REGULAR); 2794 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0)); 2795 } 2796 } else { 2797 // Synthesise the double from ARM immediates. 2798 uint32_t lo, hi; 2799 DoubleAsTwoUInt32(imm, &lo, &hi); 2800 2801 if (lo == hi) { 2802 // Move the low and high parts of the double to a D register in one 2803 // instruction. 2804 mov(ip, Operand(lo)); 2805 vmov(dst, ip, ip); 2806 } else if (scratch.is(no_reg)) { 2807 mov(ip, Operand(lo)); 2808 vmov(dst, VmovIndexLo, ip); 2809 if (((lo & 0xffff) == (hi & 0xffff)) && 2810 CpuFeatures::IsSupported(ARMv7)) { 2811 CpuFeatureScope scope(this, ARMv7); 2812 movt(ip, hi >> 16); 2813 } else { 2814 mov(ip, Operand(hi)); 2815 } 2816 vmov(dst, VmovIndexHi, ip); 2817 } else { 2818 // Move the low and high parts of the double to a D register in one 2819 // instruction. 2820 mov(ip, Operand(lo)); 2821 mov(scratch, Operand(hi)); 2822 vmov(dst, ip, scratch); 2823 } 2824 } 2825} 2826 2827 2828void Assembler::vmov(const SwVfpRegister dst, 2829 const SwVfpRegister src, 2830 const Condition cond) { 2831 // Sd = Sm 2832 // Instruction details available in ARM DDI 0406B, A8-642. 2833 int sd, d, sm, m; 2834 dst.split_code(&sd, &d); 2835 src.split_code(&sm, &m); 2836 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm); 2837} 2838 2839 2840void Assembler::vmov(const DwVfpRegister dst, 2841 const DwVfpRegister src, 2842 const Condition cond) { 2843 // Dd = Dm 2844 // Instruction details available in ARM DDI 0406C.b, A8-938. 2845 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 2846 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 2847 DCHECK(VfpRegisterIsAvailable(dst)); 2848 DCHECK(VfpRegisterIsAvailable(src)); 2849 int vd, d; 2850 dst.split_code(&vd, &d); 2851 int vm, m; 2852 src.split_code(&vm, &m); 2853 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 | 2854 vm); 2855} 2856 2857void Assembler::vmov(const DwVfpRegister dst, 2858 const VmovIndex index, 2859 const Register src, 2860 const Condition cond) { 2861 // Dd[index] = Rt 2862 // Instruction details available in ARM DDI 0406C.b, A8-940. 2863 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) | 2864 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0) 2865 DCHECK(VfpRegisterIsAvailable(dst)); 2866 DCHECK(index.index == 0 || index.index == 1); 2867 int vd, d; 2868 dst.split_code(&vd, &d); 2869 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 | 2870 d*B7 | B4); 2871} 2872 2873 2874void Assembler::vmov(const Register dst, 2875 const VmovIndex index, 2876 const DwVfpRegister src, 2877 const Condition cond) { 2878 // Dd[index] = Rt 2879 // Instruction details available in ARM DDI 0406C.b, A8.8.342. 2880 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) | 2881 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0) 2882 DCHECK(VfpRegisterIsAvailable(src)); 2883 DCHECK(index.index == 0 || index.index == 1); 2884 int vn, n; 2885 src.split_code(&vn, &n); 2886 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 | 2887 0xB*B8 | n*B7 | B4); 2888} 2889 2890 2891void Assembler::vmov(const DwVfpRegister dst, 2892 const Register src1, 2893 const Register src2, 2894 const Condition cond) { 2895 // Dm = <Rt,Rt2>. 2896 // Instruction details available in ARM DDI 0406C.b, A8-948. 2897 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) | 2898 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2899 DCHECK(VfpRegisterIsAvailable(dst)); 2900 DCHECK(!src1.is(pc) && !src2.is(pc)); 2901 int vm, m; 2902 dst.split_code(&vm, &m); 2903 emit(cond | 0xC*B24 | B22 | src2.code()*B16 | 2904 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm); 2905} 2906 2907 2908void Assembler::vmov(const Register dst1, 2909 const Register dst2, 2910 const DwVfpRegister src, 2911 const Condition cond) { 2912 // <Rt,Rt2> = Dm. 2913 // Instruction details available in ARM DDI 0406C.b, A8-948. 2914 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) | 2915 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm 2916 DCHECK(VfpRegisterIsAvailable(src)); 2917 DCHECK(!dst1.is(pc) && !dst2.is(pc)); 2918 int vm, m; 2919 src.split_code(&vm, &m); 2920 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 | 2921 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm); 2922} 2923 2924 2925void Assembler::vmov(const SwVfpRegister dst, 2926 const Register src, 2927 const Condition cond) { 2928 // Sn = Rt. 2929 // Instruction details available in ARM DDI 0406A, A8-642. 2930 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) | 2931 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2932 DCHECK(!src.is(pc)); 2933 int sn, n; 2934 dst.split_code(&sn, &n); 2935 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4); 2936} 2937 2938 2939void Assembler::vmov(const Register dst, 2940 const SwVfpRegister src, 2941 const Condition cond) { 2942 // Rt = Sn. 2943 // Instruction details available in ARM DDI 0406A, A8-642. 2944 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) | 2945 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) 2946 DCHECK(!dst.is(pc)); 2947 int sn, n; 2948 src.split_code(&sn, &n); 2949 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4); 2950} 2951 2952// Type of data to read from or write to VFP register. 2953// Used as specifier in generic vcvt instruction. 2954enum VFPType { S32, U32, F32, F64 }; 2955 2956 2957static bool IsSignedVFPType(VFPType type) { 2958 switch (type) { 2959 case S32: 2960 return true; 2961 case U32: 2962 return false; 2963 default: 2964 UNREACHABLE(); 2965 return false; 2966 } 2967} 2968 2969 2970static bool IsIntegerVFPType(VFPType type) { 2971 switch (type) { 2972 case S32: 2973 case U32: 2974 return true; 2975 case F32: 2976 case F64: 2977 return false; 2978 default: 2979 UNREACHABLE(); 2980 return false; 2981 } 2982} 2983 2984 2985static bool IsDoubleVFPType(VFPType type) { 2986 switch (type) { 2987 case F32: 2988 return false; 2989 case F64: 2990 return true; 2991 default: 2992 UNREACHABLE(); 2993 return false; 2994 } 2995} 2996 2997 2998// Split five bit reg_code based on size of reg_type. 2999// 32-bit register codes are Vm:M 3000// 64-bit register codes are M:Vm 3001// where Vm is four bits, and M is a single bit. 3002static void SplitRegCode(VFPType reg_type, 3003 int reg_code, 3004 int* vm, 3005 int* m) { 3006 DCHECK((reg_code >= 0) && (reg_code <= 31)); 3007 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) { 3008 // 32 bit type. 3009 *m = reg_code & 0x1; 3010 *vm = reg_code >> 1; 3011 } else { 3012 // 64 bit type. 3013 *m = (reg_code & 0x10) >> 4; 3014 *vm = reg_code & 0x0F; 3015 } 3016} 3017 3018 3019// Encode vcvt.src_type.dst_type instruction. 3020static Instr EncodeVCVT(const VFPType dst_type, 3021 const int dst_code, 3022 const VFPType src_type, 3023 const int src_code, 3024 VFPConversionMode mode, 3025 const Condition cond) { 3026 DCHECK(src_type != dst_type); 3027 int D, Vd, M, Vm; 3028 SplitRegCode(src_type, src_code, &Vm, &M); 3029 SplitRegCode(dst_type, dst_code, &Vd, &D); 3030 3031 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) { 3032 // Conversion between IEEE floating point and 32-bit integer. 3033 // Instruction details available in ARM DDI 0406B, A8.6.295. 3034 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) | 3035 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3036 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type)); 3037 3038 int sz, opc2, op; 3039 3040 if (IsIntegerVFPType(dst_type)) { 3041 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4; 3042 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 3043 op = mode; 3044 } else { 3045 DCHECK(IsIntegerVFPType(src_type)); 3046 opc2 = 0x0; 3047 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0; 3048 op = IsSignedVFPType(src_type) ? 0x1 : 0x0; 3049 } 3050 3051 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 | 3052 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm); 3053 } else { 3054 // Conversion between IEEE double and single precision. 3055 // Instruction details available in ARM DDI 0406B, A8.6.298. 3056 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) | 3057 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3058 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; 3059 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 | 3060 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm); 3061 } 3062} 3063 3064 3065void Assembler::vcvt_f64_s32(const DwVfpRegister dst, 3066 const SwVfpRegister src, 3067 VFPConversionMode mode, 3068 const Condition cond) { 3069 DCHECK(VfpRegisterIsAvailable(dst)); 3070 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond)); 3071} 3072 3073 3074void Assembler::vcvt_f32_s32(const SwVfpRegister dst, 3075 const SwVfpRegister src, 3076 VFPConversionMode mode, 3077 const Condition cond) { 3078 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond)); 3079} 3080 3081 3082void Assembler::vcvt_f64_u32(const DwVfpRegister dst, 3083 const SwVfpRegister src, 3084 VFPConversionMode mode, 3085 const Condition cond) { 3086 DCHECK(VfpRegisterIsAvailable(dst)); 3087 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond)); 3088} 3089 3090 3091void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src, 3092 VFPConversionMode mode, const Condition cond) { 3093 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond)); 3094} 3095 3096 3097void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src, 3098 VFPConversionMode mode, const Condition cond) { 3099 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond)); 3100} 3101 3102 3103void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src, 3104 VFPConversionMode mode, const Condition cond) { 3105 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond)); 3106} 3107 3108 3109void Assembler::vcvt_s32_f64(const SwVfpRegister dst, 3110 const DwVfpRegister src, 3111 VFPConversionMode mode, 3112 const Condition cond) { 3113 DCHECK(VfpRegisterIsAvailable(src)); 3114 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond)); 3115} 3116 3117 3118void Assembler::vcvt_u32_f64(const SwVfpRegister dst, 3119 const DwVfpRegister src, 3120 VFPConversionMode mode, 3121 const Condition cond) { 3122 DCHECK(VfpRegisterIsAvailable(src)); 3123 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond)); 3124} 3125 3126 3127void Assembler::vcvt_f64_f32(const DwVfpRegister dst, 3128 const SwVfpRegister src, 3129 VFPConversionMode mode, 3130 const Condition cond) { 3131 DCHECK(VfpRegisterIsAvailable(dst)); 3132 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond)); 3133} 3134 3135 3136void Assembler::vcvt_f32_f64(const SwVfpRegister dst, 3137 const DwVfpRegister src, 3138 VFPConversionMode mode, 3139 const Condition cond) { 3140 DCHECK(VfpRegisterIsAvailable(src)); 3141 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond)); 3142} 3143 3144 3145void Assembler::vcvt_f64_s32(const DwVfpRegister dst, 3146 int fraction_bits, 3147 const Condition cond) { 3148 // Instruction details available in ARM DDI 0406C.b, A8-874. 3149 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) | 3150 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0) 3151 DCHECK(IsEnabled(VFPv3)); 3152 DCHECK(VfpRegisterIsAvailable(dst)); 3153 DCHECK(fraction_bits > 0 && fraction_bits <= 32); 3154 int vd, d; 3155 dst.split_code(&vd, &d); 3156 int imm5 = 32 - fraction_bits; 3157 int i = imm5 & 1; 3158 int imm4 = (imm5 >> 1) & 0xf; 3159 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 | 3160 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4); 3161} 3162 3163 3164void Assembler::vneg(const DwVfpRegister dst, 3165 const DwVfpRegister src, 3166 const Condition cond) { 3167 // Instruction details available in ARM DDI 0406C.b, A8-968. 3168 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) | 3169 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3170 DCHECK(VfpRegisterIsAvailable(dst)); 3171 DCHECK(VfpRegisterIsAvailable(src)); 3172 int vd, d; 3173 dst.split_code(&vd, &d); 3174 int vm, m; 3175 src.split_code(&vm, &m); 3176 3177 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 | 3178 m*B5 | vm); 3179} 3180 3181 3182void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src, 3183 const Condition cond) { 3184 // Instruction details available in ARM DDI 0406C.b, A8-968. 3185 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) | 3186 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3187 int vd, d; 3188 dst.split_code(&vd, &d); 3189 int vm, m; 3190 src.split_code(&vm, &m); 3191 3192 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 | 3193 B6 | m * B5 | vm); 3194} 3195 3196 3197void Assembler::vabs(const DwVfpRegister dst, 3198 const DwVfpRegister src, 3199 const Condition cond) { 3200 // Instruction details available in ARM DDI 0406C.b, A8-524. 3201 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 3202 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3203 DCHECK(VfpRegisterIsAvailable(dst)); 3204 DCHECK(VfpRegisterIsAvailable(src)); 3205 int vd, d; 3206 dst.split_code(&vd, &d); 3207 int vm, m; 3208 src.split_code(&vm, &m); 3209 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 | 3210 m*B5 | vm); 3211} 3212 3213 3214void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src, 3215 const Condition cond) { 3216 // Instruction details available in ARM DDI 0406C.b, A8-524. 3217 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) | 3218 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3219 int vd, d; 3220 dst.split_code(&vd, &d); 3221 int vm, m; 3222 src.split_code(&vm, &m); 3223 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 | 3224 m * B5 | vm); 3225} 3226 3227 3228void Assembler::vadd(const DwVfpRegister dst, 3229 const DwVfpRegister src1, 3230 const DwVfpRegister src2, 3231 const Condition cond) { 3232 // Dd = vadd(Dn, Dm) double precision floating point addition. 3233 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3234 // Instruction details available in ARM DDI 0406C.b, A8-830. 3235 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3236 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3237 DCHECK(VfpRegisterIsAvailable(dst)); 3238 DCHECK(VfpRegisterIsAvailable(src1)); 3239 DCHECK(VfpRegisterIsAvailable(src2)); 3240 int vd, d; 3241 dst.split_code(&vd, &d); 3242 int vn, n; 3243 src1.split_code(&vn, &n); 3244 int vm, m; 3245 src2.split_code(&vm, &m); 3246 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3247 n*B7 | m*B5 | vm); 3248} 3249 3250 3251void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1, 3252 const SwVfpRegister src2, const Condition cond) { 3253 // Sd = vadd(Sn, Sm) single precision floating point addition. 3254 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3255 // Instruction details available in ARM DDI 0406C.b, A8-830. 3256 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3257 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3258 int vd, d; 3259 dst.split_code(&vd, &d); 3260 int vn, n; 3261 src1.split_code(&vn, &n); 3262 int vm, m; 3263 src2.split_code(&vm, &m); 3264 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 3265 0x5 * B9 | n * B7 | m * B5 | vm); 3266} 3267 3268 3269void Assembler::vsub(const DwVfpRegister dst, 3270 const DwVfpRegister src1, 3271 const DwVfpRegister src2, 3272 const Condition cond) { 3273 // Dd = vsub(Dn, Dm) double precision floating point subtraction. 3274 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3275 // Instruction details available in ARM DDI 0406C.b, A8-1086. 3276 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3277 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3278 DCHECK(VfpRegisterIsAvailable(dst)); 3279 DCHECK(VfpRegisterIsAvailable(src1)); 3280 DCHECK(VfpRegisterIsAvailable(src2)); 3281 int vd, d; 3282 dst.split_code(&vd, &d); 3283 int vn, n; 3284 src1.split_code(&vn, &n); 3285 int vm, m; 3286 src2.split_code(&vm, &m); 3287 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3288 n*B7 | B6 | m*B5 | vm); 3289} 3290 3291 3292void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1, 3293 const SwVfpRegister src2, const Condition cond) { 3294 // Sd = vsub(Sn, Sm) single precision floating point subtraction. 3295 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3296 // Instruction details available in ARM DDI 0406C.b, A8-1086. 3297 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) | 3298 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3299 int vd, d; 3300 dst.split_code(&vd, &d); 3301 int vn, n; 3302 src1.split_code(&vn, &n); 3303 int vm, m; 3304 src2.split_code(&vm, &m); 3305 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 3306 0x5 * B9 | n * B7 | B6 | m * B5 | vm); 3307} 3308 3309 3310void Assembler::vmul(const DwVfpRegister dst, 3311 const DwVfpRegister src1, 3312 const DwVfpRegister src2, 3313 const Condition cond) { 3314 // Dd = vmul(Dn, Dm) double precision floating point multiplication. 3315 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3316 // Instruction details available in ARM DDI 0406C.b, A8-960. 3317 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) | 3318 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3319 DCHECK(VfpRegisterIsAvailable(dst)); 3320 DCHECK(VfpRegisterIsAvailable(src1)); 3321 DCHECK(VfpRegisterIsAvailable(src2)); 3322 int vd, d; 3323 dst.split_code(&vd, &d); 3324 int vn, n; 3325 src1.split_code(&vn, &n); 3326 int vm, m; 3327 src2.split_code(&vm, &m); 3328 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 | 3329 n*B7 | m*B5 | vm); 3330} 3331 3332 3333void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1, 3334 const SwVfpRegister src2, const Condition cond) { 3335 // Sd = vmul(Sn, Sm) single precision floating point multiplication. 3336 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3337 // Instruction details available in ARM DDI 0406C.b, A8-960. 3338 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) | 3339 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3340 int vd, d; 3341 dst.split_code(&vd, &d); 3342 int vn, n; 3343 src1.split_code(&vn, &n); 3344 int vm, m; 3345 src2.split_code(&vm, &m); 3346 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 | 3347 0x5 * B9 | n * B7 | m * B5 | vm); 3348} 3349 3350 3351void Assembler::vmla(const DwVfpRegister dst, 3352 const DwVfpRegister src1, 3353 const DwVfpRegister src2, 3354 const Condition cond) { 3355 // Instruction details available in ARM DDI 0406C.b, A8-932. 3356 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3357 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0) 3358 DCHECK(VfpRegisterIsAvailable(dst)); 3359 DCHECK(VfpRegisterIsAvailable(src1)); 3360 DCHECK(VfpRegisterIsAvailable(src2)); 3361 int vd, d; 3362 dst.split_code(&vd, &d); 3363 int vn, n; 3364 src1.split_code(&vn, &n); 3365 int vm, m; 3366 src2.split_code(&vm, &m); 3367 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 | 3368 vm); 3369} 3370 3371 3372void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1, 3373 const SwVfpRegister src2, const Condition cond) { 3374 // Instruction details available in ARM DDI 0406C.b, A8-932. 3375 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3376 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0) 3377 int vd, d; 3378 dst.split_code(&vd, &d); 3379 int vn, n; 3380 src1.split_code(&vn, &n); 3381 int vm, m; 3382 src2.split_code(&vm, &m); 3383 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3384 m * B5 | vm); 3385} 3386 3387 3388void Assembler::vmls(const DwVfpRegister dst, 3389 const DwVfpRegister src1, 3390 const DwVfpRegister src2, 3391 const Condition cond) { 3392 // Instruction details available in ARM DDI 0406C.b, A8-932. 3393 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3394 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0) 3395 DCHECK(VfpRegisterIsAvailable(dst)); 3396 DCHECK(VfpRegisterIsAvailable(src1)); 3397 DCHECK(VfpRegisterIsAvailable(src2)); 3398 int vd, d; 3399 dst.split_code(&vd, &d); 3400 int vn, n; 3401 src1.split_code(&vn, &n); 3402 int vm, m; 3403 src2.split_code(&vm, &m); 3404 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 | 3405 m*B5 | vm); 3406} 3407 3408 3409void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1, 3410 const SwVfpRegister src2, const Condition cond) { 3411 // Instruction details available in ARM DDI 0406C.b, A8-932. 3412 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3413 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0) 3414 int vd, d; 3415 dst.split_code(&vd, &d); 3416 int vn, n; 3417 src1.split_code(&vn, &n); 3418 int vm, m; 3419 src2.split_code(&vm, &m); 3420 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3421 B6 | m * B5 | vm); 3422} 3423 3424 3425void Assembler::vdiv(const DwVfpRegister dst, 3426 const DwVfpRegister src1, 3427 const DwVfpRegister src2, 3428 const Condition cond) { 3429 // Dd = vdiv(Dn, Dm) double precision floating point division. 3430 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm. 3431 // Instruction details available in ARM DDI 0406C.b, A8-882. 3432 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) | 3433 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3434 DCHECK(VfpRegisterIsAvailable(dst)); 3435 DCHECK(VfpRegisterIsAvailable(src1)); 3436 DCHECK(VfpRegisterIsAvailable(src2)); 3437 int vd, d; 3438 dst.split_code(&vd, &d); 3439 int vn, n; 3440 src1.split_code(&vn, &n); 3441 int vm, m; 3442 src2.split_code(&vm, &m); 3443 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 | 3444 vm); 3445} 3446 3447 3448void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1, 3449 const SwVfpRegister src2, const Condition cond) { 3450 // Sd = vdiv(Sn, Sm) single precision floating point division. 3451 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm. 3452 // Instruction details available in ARM DDI 0406C.b, A8-882. 3453 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) | 3454 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3455 int vd, d; 3456 dst.split_code(&vd, &d); 3457 int vn, n; 3458 src1.split_code(&vn, &n); 3459 int vm, m; 3460 src2.split_code(&vm, &m); 3461 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 | 3462 m * B5 | vm); 3463} 3464 3465 3466void Assembler::vcmp(const DwVfpRegister src1, 3467 const DwVfpRegister src2, 3468 const Condition cond) { 3469 // vcmp(Dd, Dm) double precision floating point comparison. 3470 // Instruction details available in ARM DDI 0406C.b, A8-864. 3471 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) | 3472 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3473 DCHECK(VfpRegisterIsAvailable(src1)); 3474 DCHECK(VfpRegisterIsAvailable(src2)); 3475 int vd, d; 3476 src1.split_code(&vd, &d); 3477 int vm, m; 3478 src2.split_code(&vm, &m); 3479 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 | 3480 m*B5 | vm); 3481} 3482 3483 3484void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2, 3485 const Condition cond) { 3486 // vcmp(Sd, Sm) single precision floating point comparison. 3487 // Instruction details available in ARM DDI 0406C.b, A8-864. 3488 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) | 3489 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3490 int vd, d; 3491 src1.split_code(&vd, &d); 3492 int vm, m; 3493 src2.split_code(&vm, &m); 3494 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 | 3495 0x5 * B9 | B6 | m * B5 | vm); 3496} 3497 3498 3499void Assembler::vcmp(const DwVfpRegister src1, 3500 const double src2, 3501 const Condition cond) { 3502 // vcmp(Dd, #0.0) double precision floating point comparison. 3503 // Instruction details available in ARM DDI 0406C.b, A8-864. 3504 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) | 3505 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0) 3506 DCHECK(VfpRegisterIsAvailable(src1)); 3507 DCHECK(src2 == 0.0); 3508 int vd, d; 3509 src1.split_code(&vd, &d); 3510 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6); 3511} 3512 3513 3514void Assembler::vcmp(const SwVfpRegister src1, const float src2, 3515 const Condition cond) { 3516 // vcmp(Sd, #0.0) single precision floating point comparison. 3517 // Instruction details available in ARM DDI 0406C.b, A8-864. 3518 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) | 3519 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0) 3520 DCHECK(src2 == 0.0); 3521 int vd, d; 3522 src1.split_code(&vd, &d); 3523 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 | 3524 0x5 * B9 | B6); 3525} 3526 3527void Assembler::vmaxnm(const DwVfpRegister dst, const DwVfpRegister src1, 3528 const DwVfpRegister src2) { 3529 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3530 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3531 DCHECK(IsEnabled(ARMv8)); 3532 int vd, d; 3533 dst.split_code(&vd, &d); 3534 int vn, n; 3535 src1.split_code(&vn, &n); 3536 int vm, m; 3537 src2.split_code(&vm, &m); 3538 3539 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 3540 0x5 * B9 | B8 | n * B7 | m * B5 | vm); 3541} 3542 3543void Assembler::vmaxnm(const SwVfpRegister dst, const SwVfpRegister src1, 3544 const SwVfpRegister src2) { 3545 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3546 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0) 3547 DCHECK(IsEnabled(ARMv8)); 3548 int vd, d; 3549 dst.split_code(&vd, &d); 3550 int vn, n; 3551 src1.split_code(&vn, &n); 3552 int vm, m; 3553 src2.split_code(&vm, &m); 3554 3555 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 3556 0x5 * B9 | n * B7 | m * B5 | vm); 3557} 3558 3559void Assembler::vminnm(const DwVfpRegister dst, const DwVfpRegister src1, 3560 const DwVfpRegister src2) { 3561 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3562 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3563 DCHECK(IsEnabled(ARMv8)); 3564 int vd, d; 3565 dst.split_code(&vd, &d); 3566 int vn, n; 3567 src1.split_code(&vn, &n); 3568 int vm, m; 3569 src2.split_code(&vm, &m); 3570 3571 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 3572 0x5 * B9 | B8 | n * B7 | B6 | m * B5 | vm); 3573} 3574 3575void Assembler::vminnm(const SwVfpRegister dst, const SwVfpRegister src1, 3576 const SwVfpRegister src2) { 3577 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) | 3578 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3579 DCHECK(IsEnabled(ARMv8)); 3580 int vd, d; 3581 dst.split_code(&vd, &d); 3582 int vn, n; 3583 src1.split_code(&vn, &n); 3584 int vm, m; 3585 src2.split_code(&vm, &m); 3586 3587 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 3588 0x5 * B9 | n * B7 | B6 | m * B5 | vm); 3589} 3590 3591void Assembler::vsel(Condition cond, const DwVfpRegister dst, 3592 const DwVfpRegister src1, const DwVfpRegister src2) { 3593 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) | 3594 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 3595 // 0(6) | M(5) | 0(4) | Vm(3-0) 3596 DCHECK(IsEnabled(ARMv8)); 3597 int vd, d; 3598 dst.split_code(&vd, &d); 3599 int vn, n; 3600 src1.split_code(&vn, &n); 3601 int vm, m; 3602 src2.split_code(&vm, &m); 3603 int sz = 1; 3604 3605 // VSEL has a special (restricted) condition encoding. 3606 // eq(0b0000)... -> 0b00 3607 // ge(0b1010)... -> 0b10 3608 // gt(0b1100)... -> 0b11 3609 // vs(0b0110)... -> 0b01 3610 // No other conditions are supported. 3611 int vsel_cond = (cond >> 30) & 0x3; 3612 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) { 3613 // We can implement some other conditions by swapping the inputs. 3614 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc)); 3615 std::swap(vn, vm); 3616 std::swap(n, m); 3617 } 3618 3619 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 | 3620 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm); 3621} 3622 3623void Assembler::vsel(Condition cond, const SwVfpRegister dst, 3624 const SwVfpRegister src1, const SwVfpRegister src2) { 3625 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) | 3626 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 3627 // 0(6) | M(5) | 0(4) | Vm(3-0) 3628 DCHECK(IsEnabled(ARMv8)); 3629 int vd, d; 3630 dst.split_code(&vd, &d); 3631 int vn, n; 3632 src1.split_code(&vn, &n); 3633 int vm, m; 3634 src2.split_code(&vm, &m); 3635 int sz = 0; 3636 3637 // VSEL has a special (restricted) condition encoding. 3638 // eq(0b0000)... -> 0b00 3639 // ge(0b1010)... -> 0b10 3640 // gt(0b1100)... -> 0b11 3641 // vs(0b0110)... -> 0b01 3642 // No other conditions are supported. 3643 int vsel_cond = (cond >> 30) & 0x3; 3644 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) { 3645 // We can implement some other conditions by swapping the inputs. 3646 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc)); 3647 std::swap(vn, vm); 3648 std::swap(n, m); 3649 } 3650 3651 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 | 3652 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm); 3653} 3654 3655void Assembler::vsqrt(const DwVfpRegister dst, 3656 const DwVfpRegister src, 3657 const Condition cond) { 3658 // Instruction details available in ARM DDI 0406C.b, A8-1058. 3659 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) | 3660 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0) 3661 DCHECK(VfpRegisterIsAvailable(dst)); 3662 DCHECK(VfpRegisterIsAvailable(src)); 3663 int vd, d; 3664 dst.split_code(&vd, &d); 3665 int vm, m; 3666 src.split_code(&vm, &m); 3667 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 | 3668 m*B5 | vm); 3669} 3670 3671 3672void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src, 3673 const Condition cond) { 3674 // Instruction details available in ARM DDI 0406C.b, A8-1058. 3675 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) | 3676 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0) 3677 int vd, d; 3678 dst.split_code(&vd, &d); 3679 int vm, m; 3680 src.split_code(&vm, &m); 3681 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 | 3682 0x3 * B6 | m * B5 | vm); 3683} 3684 3685 3686void Assembler::vmsr(Register dst, Condition cond) { 3687 // Instruction details available in ARM DDI 0406A, A8-652. 3688 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) | 3689 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 3690 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4); 3691} 3692 3693 3694void Assembler::vmrs(Register dst, Condition cond) { 3695 // Instruction details available in ARM DDI 0406A, A8-652. 3696 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) | 3697 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0) 3698 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4); 3699} 3700 3701 3702void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) { 3703 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3704 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3705 // M(5) | 0(4) | Vm(3-0) 3706 DCHECK(IsEnabled(ARMv8)); 3707 int vd, d; 3708 dst.split_code(&vd, &d); 3709 int vm, m; 3710 src.split_code(&vm, &m); 3711 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 | 3712 0x5 * B9 | B6 | m * B5 | vm); 3713} 3714 3715 3716void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) { 3717 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3718 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3719 // M(5) | 0(4) | Vm(3-0) 3720 DCHECK(IsEnabled(ARMv8)); 3721 int vd, d; 3722 dst.split_code(&vd, &d); 3723 int vm, m; 3724 src.split_code(&vm, &m); 3725 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 | 3726 0x5 * B9 | B8 | B6 | m * B5 | vm); 3727} 3728 3729 3730void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) { 3731 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3732 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3733 // M(5) | 0(4) | Vm(3-0) 3734 DCHECK(IsEnabled(ARMv8)); 3735 int vd, d; 3736 dst.split_code(&vd, &d); 3737 int vm, m; 3738 src.split_code(&vm, &m); 3739 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 | 3740 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3741} 3742 3743 3744void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) { 3745 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3746 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3747 // M(5) | 0(4) | Vm(3-0) 3748 DCHECK(IsEnabled(ARMv8)); 3749 int vd, d; 3750 dst.split_code(&vd, &d); 3751 int vm, m; 3752 src.split_code(&vm, &m); 3753 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 | 3754 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3755} 3756 3757 3758void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) { 3759 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3760 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3761 // M(5) | 0(4) | Vm(3-0) 3762 DCHECK(IsEnabled(ARMv8)); 3763 int vd, d; 3764 dst.split_code(&vd, &d); 3765 int vm, m; 3766 src.split_code(&vm, &m); 3767 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 | 3768 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3769} 3770 3771 3772void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) { 3773 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3774 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3775 // M(5) | 0(4) | Vm(3-0) 3776 DCHECK(IsEnabled(ARMv8)); 3777 int vd, d; 3778 dst.split_code(&vd, &d); 3779 int vm, m; 3780 src.split_code(&vm, &m); 3781 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 | 3782 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3783} 3784 3785 3786void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) { 3787 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3788 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) | 3789 // M(5) | 0(4) | Vm(3-0) 3790 DCHECK(IsEnabled(ARMv8)); 3791 int vd, d; 3792 dst.split_code(&vd, &d); 3793 int vm, m; 3794 src.split_code(&vm, &m); 3795 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 | 3796 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm); 3797} 3798 3799 3800void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) { 3801 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) | 3802 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) | 3803 // M(5) | 0(4) | Vm(3-0) 3804 DCHECK(IsEnabled(ARMv8)); 3805 int vd, d; 3806 dst.split_code(&vd, &d); 3807 int vm, m; 3808 src.split_code(&vm, &m); 3809 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 | 3810 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm); 3811} 3812 3813 3814void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src, 3815 const Condition cond) { 3816 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) | 3817 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3818 DCHECK(IsEnabled(ARMv8)); 3819 int vd, d; 3820 dst.split_code(&vd, &d); 3821 int vm, m; 3822 src.split_code(&vm, &m); 3823 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 | 3824 0x5 * B9 | B7 | B6 | m * B5 | vm); 3825} 3826 3827 3828void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src, 3829 const Condition cond) { 3830 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) | 3831 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) 3832 DCHECK(IsEnabled(ARMv8)); 3833 int vd, d; 3834 dst.split_code(&vd, &d); 3835 int vm, m; 3836 src.split_code(&vm, &m); 3837 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 | 3838 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm); 3839} 3840 3841 3842// Support for NEON. 3843 3844void Assembler::vld1(NeonSize size, 3845 const NeonListOperand& dst, 3846 const NeonMemOperand& src) { 3847 // Instruction details available in ARM DDI 0406C.b, A8.8.320. 3848 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) | 3849 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0) 3850 DCHECK(IsEnabled(NEON)); 3851 int vd, d; 3852 dst.base().split_code(&vd, &d); 3853 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 | 3854 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code()); 3855} 3856 3857 3858void Assembler::vst1(NeonSize size, 3859 const NeonListOperand& src, 3860 const NeonMemOperand& dst) { 3861 // Instruction details available in ARM DDI 0406C.b, A8.8.404. 3862 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) | 3863 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0) 3864 DCHECK(IsEnabled(NEON)); 3865 int vd, d; 3866 src.base().split_code(&vd, &d); 3867 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 | 3868 size*B6 | dst.align()*B4 | dst.rm().code()); 3869} 3870 3871 3872void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) { 3873 // Instruction details available in ARM DDI 0406C.b, A8.8.346. 3874 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) | 3875 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0) 3876 DCHECK(IsEnabled(NEON)); 3877 int vd, d; 3878 dst.split_code(&vd, &d); 3879 int vm, m; 3880 src.split_code(&vm, &m); 3881 int U = NeonU(dt); 3882 int imm3 = 1 << NeonSz(dt); 3883 emit(0xFU * B28 | B25 | U * B24 | B23 | d * B22 | imm3 * B19 | vd * B12 | 3884 0xA * B8 | m * B5 | B4 | vm); 3885} 3886 3887static int EncodeScalar(NeonDataType dt, int index) { 3888 int opc1_opc2 = 0; 3889 DCHECK_LE(0, index); 3890 switch (dt) { 3891 case NeonS8: 3892 case NeonU8: 3893 DCHECK_GT(8, index); 3894 opc1_opc2 = 0x8 | index; 3895 break; 3896 case NeonS16: 3897 case NeonU16: 3898 DCHECK_GT(4, index); 3899 opc1_opc2 = 0x1 | (index << 1); 3900 break; 3901 case NeonS32: 3902 case NeonU32: 3903 DCHECK_GT(2, index); 3904 opc1_opc2 = index << 2; 3905 break; 3906 default: 3907 UNREACHABLE(); 3908 break; 3909 } 3910 return (opc1_opc2 >> 2) * B21 | (opc1_opc2 & 0x3) * B5; 3911} 3912 3913void Assembler::vmov(NeonDataType dt, DwVfpRegister dst, int index, 3914 Register src) { 3915 // Instruction details available in ARM DDI 0406C.b, A8.8.940. 3916 // vmov ARM core register to scalar. 3917 DCHECK(dt == NeonS32 || dt == NeonU32 || IsEnabled(NEON)); 3918 int vd, d; 3919 dst.split_code(&vd, &d); 3920 int opc1_opc2 = EncodeScalar(dt, index); 3921 emit(0xEEu * B24 | vd * B16 | src.code() * B12 | 0xB * B8 | d * B7 | B4 | 3922 opc1_opc2); 3923} 3924 3925void Assembler::vmov(NeonDataType dt, Register dst, DwVfpRegister src, 3926 int index) { 3927 // Instruction details available in ARM DDI 0406C.b, A8.8.942. 3928 // vmov Arm scalar to core register. 3929 DCHECK(dt == NeonS32 || dt == NeonU32 || IsEnabled(NEON)); 3930 int vn, n; 3931 src.split_code(&vn, &n); 3932 int opc1_opc2 = EncodeScalar(dt, index); 3933 int u = NeonU(dt); 3934 emit(0xEEu * B24 | u * B23 | B20 | vn * B16 | dst.code() * B12 | 0xB * B8 | 3935 n * B7 | B4 | opc1_opc2); 3936} 3937 3938void Assembler::vmov(const QwNeonRegister dst, const QwNeonRegister src) { 3939 // Instruction details available in ARM DDI 0406C.b, A8-938. 3940 // vmov is encoded as vorr. 3941 vorr(dst, src, src); 3942} 3943 3944void Assembler::vmvn(const QwNeonRegister dst, const QwNeonRegister src) { 3945 DCHECK(IsEnabled(NEON)); 3946 // Instruction details available in ARM DDI 0406C.b, A8-966. 3947 DCHECK(VfpRegisterIsAvailable(dst)); 3948 DCHECK(VfpRegisterIsAvailable(src)); 3949 int vd, d; 3950 dst.split_code(&vd, &d); 3951 int vm, m; 3952 src.split_code(&vm, &m); 3953 emit(0x1E7U * B23 | d * B22 | 3 * B20 | vd * B12 | 0x17 * B6 | m * B5 | vm); 3954} 3955 3956void Assembler::vswp(DwVfpRegister dst, DwVfpRegister src) { 3957 // Instruction details available in ARM DDI 0406C.b, A8.8.418. 3958 // 1111(31-28) | 00111(27-23) | D(22) | 110010(21-16) | 3959 // Vd(15-12) | 000000(11-6) | M(5) | 0(4) | Vm(3-0) 3960 DCHECK(IsEnabled(NEON)); 3961 int vd, d; 3962 dst.split_code(&vd, &d); 3963 int vm, m; 3964 src.split_code(&vm, &m); 3965 emit(0xFU * B28 | 7 * B23 | d * B22 | 0x32 * B16 | vd * B12 | m * B5 | vm); 3966} 3967 3968void Assembler::vswp(QwNeonRegister dst, QwNeonRegister src) { 3969 // Instruction details available in ARM DDI 0406C.b, A8.8.418. 3970 // 1111(31-28) | 00111(27-23) | D(22) | 110010(21-16) | 3971 // Vd(15-12) | 000000(11-6) | M(5) | 0(4) | Vm(3-0) 3972 DCHECK(IsEnabled(NEON)); 3973 int vd, d; 3974 dst.split_code(&vd, &d); 3975 int vm, m; 3976 src.split_code(&vm, &m); 3977 emit(0xFU * B28 | 7 * B23 | d * B22 | 0x32 * B16 | vd * B12 | B6 | m * B5 | 3978 vm); 3979} 3980 3981void Assembler::vdup(NeonSize size, const QwNeonRegister dst, 3982 const Register src) { 3983 DCHECK(IsEnabled(NEON)); 3984 // Instruction details available in ARM DDI 0406C.b, A8-886. 3985 int B = 0, E = 0; 3986 switch (size) { 3987 case Neon8: 3988 B = 1; 3989 break; 3990 case Neon16: 3991 E = 1; 3992 break; 3993 case Neon32: 3994 break; 3995 default: 3996 UNREACHABLE(); 3997 break; 3998 } 3999 int vd, d; 4000 dst.split_code(&vd, &d); 4001 4002 emit(al | 0x1D * B23 | B * B22 | B21 | vd * B16 | src.code() * B12 | 4003 0xB * B8 | d * B7 | E * B5 | B4); 4004} 4005 4006void Assembler::vdup(const QwNeonRegister dst, const SwVfpRegister src) { 4007 DCHECK(IsEnabled(NEON)); 4008 // Instruction details available in ARM DDI 0406C.b, A8-884. 4009 int index = src.code() & 1; 4010 int d_reg = src.code() / 2; 4011 int imm4 = 4 | index << 3; // esize = 32, index in bit 3. 4012 int vd, d; 4013 dst.split_code(&vd, &d); 4014 int vm, m; 4015 DwVfpRegister::from_code(d_reg).split_code(&vm, &m); 4016 4017 emit(0x1E7U * B23 | d * B22 | 0x3 * B20 | imm4 * B16 | vd * B12 | 0x18 * B7 | 4018 B6 | m * B5 | vm); 4019} 4020 4021// Encode NEON vcvt.src_type.dst_type instruction. 4022static Instr EncodeNeonVCVT(const VFPType dst_type, const QwNeonRegister dst, 4023 const VFPType src_type, const QwNeonRegister src) { 4024 DCHECK(src_type != dst_type); 4025 DCHECK(src_type == F32 || dst_type == F32); 4026 // Instruction details available in ARM DDI 0406C.b, A8.8.868. 4027 int vd, d; 4028 dst.split_code(&vd, &d); 4029 int vm, m; 4030 src.split_code(&vm, &m); 4031 4032 int op = 0; 4033 if (src_type == F32) { 4034 DCHECK(dst_type == S32 || dst_type == U32); 4035 op = dst_type == U32 ? 3 : 2; 4036 } else { 4037 DCHECK(src_type == S32 || src_type == U32); 4038 op = src_type == U32 ? 1 : 0; 4039 } 4040 4041 return 0x1E7U * B23 | d * B22 | 0x3B * B16 | vd * B12 | 0x3 * B9 | op * B7 | 4042 B6 | m * B5 | vm; 4043} 4044 4045void Assembler::vcvt_f32_s32(const QwNeonRegister dst, 4046 const QwNeonRegister src) { 4047 DCHECK(IsEnabled(NEON)); 4048 DCHECK(VfpRegisterIsAvailable(dst)); 4049 DCHECK(VfpRegisterIsAvailable(src)); 4050 emit(EncodeNeonVCVT(F32, dst, S32, src)); 4051} 4052 4053void Assembler::vcvt_f32_u32(const QwNeonRegister dst, 4054 const QwNeonRegister src) { 4055 DCHECK(IsEnabled(NEON)); 4056 DCHECK(VfpRegisterIsAvailable(dst)); 4057 DCHECK(VfpRegisterIsAvailable(src)); 4058 emit(EncodeNeonVCVT(F32, dst, U32, src)); 4059} 4060 4061void Assembler::vcvt_s32_f32(const QwNeonRegister dst, 4062 const QwNeonRegister src) { 4063 DCHECK(IsEnabled(NEON)); 4064 DCHECK(VfpRegisterIsAvailable(dst)); 4065 DCHECK(VfpRegisterIsAvailable(src)); 4066 emit(EncodeNeonVCVT(S32, dst, F32, src)); 4067} 4068 4069void Assembler::vcvt_u32_f32(const QwNeonRegister dst, 4070 const QwNeonRegister src) { 4071 DCHECK(IsEnabled(NEON)); 4072 DCHECK(VfpRegisterIsAvailable(dst)); 4073 DCHECK(VfpRegisterIsAvailable(src)); 4074 emit(EncodeNeonVCVT(U32, dst, F32, src)); 4075} 4076 4077// op is instr->Bits(11, 7). 4078static Instr EncodeNeonUnaryOp(int op, bool is_float, NeonSize size, 4079 const QwNeonRegister dst, 4080 const QwNeonRegister src) { 4081 DCHECK_IMPLIES(is_float, size == Neon32); 4082 int vd, d; 4083 dst.split_code(&vd, &d); 4084 int vm, m; 4085 src.split_code(&vm, &m); 4086 int F = is_float ? 1 : 0; 4087 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | size * B18 | B16 | vd * B12 | 4088 F * B10 | B8 | op * B7 | B6 | m * B5 | vm; 4089} 4090 4091void Assembler::vabs(const QwNeonRegister dst, const QwNeonRegister src) { 4092 // Qd = vabs.f<size>(Qn, Qm) SIMD floating point absolute value. 4093 // Instruction details available in ARM DDI 0406C.b, A8.8.824. 4094 DCHECK(IsEnabled(NEON)); 4095 emit(EncodeNeonUnaryOp(0x6, true, Neon32, dst, src)); 4096} 4097 4098void Assembler::vabs(NeonSize size, const QwNeonRegister dst, 4099 const QwNeonRegister src) { 4100 // Qd = vabs.s<size>(Qn, Qm) SIMD integer absolute value. 4101 // Instruction details available in ARM DDI 0406C.b, A8.8.824. 4102 DCHECK(IsEnabled(NEON)); 4103 emit(EncodeNeonUnaryOp(0x6, false, size, dst, src)); 4104} 4105 4106void Assembler::vneg(const QwNeonRegister dst, const QwNeonRegister src) { 4107 // Qd = vabs.f<size>(Qn, Qm) SIMD floating point negate. 4108 // Instruction details available in ARM DDI 0406C.b, A8.8.968. 4109 DCHECK(IsEnabled(NEON)); 4110 emit(EncodeNeonUnaryOp(0x7, true, Neon32, dst, src)); 4111} 4112 4113void Assembler::vneg(NeonSize size, const QwNeonRegister dst, 4114 const QwNeonRegister src) { 4115 // Qd = vabs.s<size>(Qn, Qm) SIMD integer negate. 4116 // Instruction details available in ARM DDI 0406C.b, A8.8.968. 4117 DCHECK(IsEnabled(NEON)); 4118 emit(EncodeNeonUnaryOp(0x7, false, size, dst, src)); 4119} 4120 4121void Assembler::veor(DwVfpRegister dst, DwVfpRegister src1, 4122 DwVfpRegister src2) { 4123 // Dd = veor(Dn, Dm) 64 bit integer exclusive OR. 4124 // Instruction details available in ARM DDI 0406C.b, A8.8.888. 4125 DCHECK(IsEnabled(NEON)); 4126 int vd, d; 4127 dst.split_code(&vd, &d); 4128 int vn, n; 4129 src1.split_code(&vn, &n); 4130 int vm, m; 4131 src2.split_code(&vm, &m); 4132 emit(0x1E6U * B23 | d * B22 | vn * B16 | vd * B12 | B8 | n * B7 | m * B5 | 4133 B4 | vm); 4134} 4135 4136enum BinaryBitwiseOp { VAND, VBIC, VBIF, VBIT, VBSL, VEOR, VORR, VORN }; 4137 4138static Instr EncodeNeonBinaryBitwiseOp(BinaryBitwiseOp op, 4139 const QwNeonRegister dst, 4140 const QwNeonRegister src1, 4141 const QwNeonRegister src2) { 4142 int op_encoding = 0; 4143 switch (op) { 4144 case VBIC: 4145 op_encoding = 0x1 * B20; 4146 break; 4147 case VBIF: 4148 op_encoding = B24 | 0x3 * B20; 4149 break; 4150 case VBIT: 4151 op_encoding = B24 | 0x2 * B20; 4152 break; 4153 case VBSL: 4154 op_encoding = B24 | 0x1 * B20; 4155 break; 4156 case VEOR: 4157 op_encoding = B24; 4158 break; 4159 case VORR: 4160 op_encoding = 0x2 * B20; 4161 break; 4162 case VORN: 4163 op_encoding = 0x3 * B20; 4164 break; 4165 case VAND: 4166 // op_encoding is 0. 4167 break; 4168 default: 4169 UNREACHABLE(); 4170 break; 4171 } 4172 int vd, d; 4173 dst.split_code(&vd, &d); 4174 int vn, n; 4175 src1.split_code(&vn, &n); 4176 int vm, m; 4177 src2.split_code(&vm, &m); 4178 return 0x1E4U * B23 | op_encoding | d * B22 | vn * B16 | vd * B12 | B8 | 4179 n * B7 | B6 | m * B5 | B4 | vm; 4180} 4181 4182void Assembler::vand(QwNeonRegister dst, QwNeonRegister src1, 4183 QwNeonRegister src2) { 4184 // Qd = vand(Qn, Qm) SIMD AND. 4185 // Instruction details available in ARM DDI 0406C.b, A8.8.836. 4186 DCHECK(IsEnabled(NEON)); 4187 emit(EncodeNeonBinaryBitwiseOp(VAND, dst, src1, src2)); 4188} 4189 4190void Assembler::vbsl(QwNeonRegister dst, const QwNeonRegister src1, 4191 const QwNeonRegister src2) { 4192 DCHECK(IsEnabled(NEON)); 4193 // Qd = vbsl(Qn, Qm) SIMD bitwise select. 4194 // Instruction details available in ARM DDI 0406C.b, A8-844. 4195 emit(EncodeNeonBinaryBitwiseOp(VBSL, dst, src1, src2)); 4196} 4197 4198void Assembler::veor(QwNeonRegister dst, QwNeonRegister src1, 4199 QwNeonRegister src2) { 4200 // Qd = veor(Qn, Qm) SIMD exclusive OR. 4201 // Instruction details available in ARM DDI 0406C.b, A8.8.888. 4202 DCHECK(IsEnabled(NEON)); 4203 emit(EncodeNeonBinaryBitwiseOp(VEOR, dst, src1, src2)); 4204} 4205 4206void Assembler::vorr(QwNeonRegister dst, QwNeonRegister src1, 4207 QwNeonRegister src2) { 4208 // Qd = vorr(Qn, Qm) SIMD OR. 4209 // Instruction details available in ARM DDI 0406C.b, A8.8.976. 4210 DCHECK(IsEnabled(NEON)); 4211 emit(EncodeNeonBinaryBitwiseOp(VORR, dst, src1, src2)); 4212} 4213 4214enum FPBinOp { 4215 VADDF, 4216 VSUBF, 4217 VMULF, 4218 VMINF, 4219 VMAXF, 4220 VRECPS, 4221 VRSQRTS, 4222 VCEQF, 4223 VCGEF, 4224 VCGTF 4225}; 4226 4227static Instr EncodeNeonBinOp(FPBinOp op, QwNeonRegister dst, 4228 QwNeonRegister src1, QwNeonRegister src2) { 4229 int op_encoding = 0; 4230 switch (op) { 4231 case VADDF: 4232 op_encoding = 0xD * B8; 4233 break; 4234 case VSUBF: 4235 op_encoding = B21 | 0xD * B8; 4236 break; 4237 case VMULF: 4238 op_encoding = B24 | 0xD * B8 | B4; 4239 break; 4240 case VMINF: 4241 op_encoding = B21 | 0xF * B8; 4242 break; 4243 case VMAXF: 4244 op_encoding = 0xF * B8; 4245 break; 4246 case VRECPS: 4247 op_encoding = 0xF * B8 | B4; 4248 break; 4249 case VRSQRTS: 4250 op_encoding = B21 | 0xF * B8 | B4; 4251 break; 4252 case VCEQF: 4253 op_encoding = 0xE * B8; 4254 break; 4255 case VCGEF: 4256 op_encoding = B24 | 0xE * B8; 4257 break; 4258 case VCGTF: 4259 op_encoding = B24 | B21 | 0xE * B8; 4260 break; 4261 default: 4262 UNREACHABLE(); 4263 break; 4264 } 4265 int vd, d; 4266 dst.split_code(&vd, &d); 4267 int vn, n; 4268 src1.split_code(&vn, &n); 4269 int vm, m; 4270 src2.split_code(&vm, &m); 4271 return 0x1E4U * B23 | d * B22 | vn * B16 | vd * B12 | n * B7 | B6 | m * B5 | 4272 vm | op_encoding; 4273} 4274 4275enum IntegerBinOp { 4276 VADD, 4277 VQADD, 4278 VSUB, 4279 VQSUB, 4280 VMUL, 4281 VMIN, 4282 VMAX, 4283 VTST, 4284 VCEQ, 4285 VCGE, 4286 VCGT 4287}; 4288 4289static Instr EncodeNeonBinOp(IntegerBinOp op, NeonDataType dt, 4290 const QwNeonRegister dst, 4291 const QwNeonRegister src1, 4292 const QwNeonRegister src2) { 4293 int op_encoding = 0; 4294 switch (op) { 4295 case VADD: 4296 op_encoding = 0x8 * B8; 4297 break; 4298 case VQADD: 4299 op_encoding = B4; 4300 break; 4301 case VSUB: 4302 op_encoding = B24 | 0x8 * B8; 4303 break; 4304 case VQSUB: 4305 op_encoding = 0x2 * B8 | B4; 4306 break; 4307 case VMUL: 4308 op_encoding = 0x9 * B8 | B4; 4309 break; 4310 case VMIN: 4311 op_encoding = 0x6 * B8 | B4; 4312 break; 4313 case VMAX: 4314 op_encoding = 0x6 * B8; 4315 break; 4316 case VTST: 4317 op_encoding = 0x8 * B8 | B4; 4318 break; 4319 case VCEQ: 4320 op_encoding = B24 | 0x8 * B8 | B4; 4321 break; 4322 case VCGE: 4323 op_encoding = 0x3 * B8 | B4; 4324 break; 4325 case VCGT: 4326 op_encoding = 0x3 * B8; 4327 break; 4328 default: 4329 UNREACHABLE(); 4330 break; 4331 } 4332 int vd, d; 4333 dst.split_code(&vd, &d); 4334 int vn, n; 4335 src1.split_code(&vn, &n); 4336 int vm, m; 4337 src2.split_code(&vm, &m); 4338 int size = NeonSz(dt); 4339 int u = NeonU(dt); 4340 return 0x1E4U * B23 | u * B24 | d * B22 | size * B20 | vn * B16 | vd * B12 | 4341 n * B7 | B6 | m * B5 | vm | op_encoding; 4342} 4343 4344static Instr EncodeNeonBinOp(IntegerBinOp op, NeonSize size, 4345 const QwNeonRegister dst, 4346 const QwNeonRegister src1, 4347 const QwNeonRegister src2) { 4348 // Map NeonSize values to the signed values in NeonDataType, so the U bit 4349 // will be 0. 4350 return EncodeNeonBinOp(op, static_cast<NeonDataType>(size), dst, src1, src2); 4351} 4352 4353void Assembler::vadd(QwNeonRegister dst, QwNeonRegister src1, 4354 QwNeonRegister src2) { 4355 DCHECK(IsEnabled(NEON)); 4356 // Qd = vadd(Qn, Qm) SIMD floating point addition. 4357 // Instruction details available in ARM DDI 0406C.b, A8-830. 4358 emit(EncodeNeonBinOp(VADDF, dst, src1, src2)); 4359} 4360 4361void Assembler::vadd(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 4362 QwNeonRegister src2) { 4363 DCHECK(IsEnabled(NEON)); 4364 // Qd = vadd(Qn, Qm) SIMD integer addition. 4365 // Instruction details available in ARM DDI 0406C.b, A8-828. 4366 emit(EncodeNeonBinOp(VADD, size, dst, src1, src2)); 4367} 4368 4369void Assembler::vqadd(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4370 QwNeonRegister src2) { 4371 DCHECK(IsEnabled(NEON)); 4372 // Qd = vqadd(Qn, Qm) SIMD integer saturating addition. 4373 // Instruction details available in ARM DDI 0406C.b, A8-996. 4374 emit(EncodeNeonBinOp(VQADD, dt, dst, src1, src2)); 4375} 4376 4377void Assembler::vsub(QwNeonRegister dst, QwNeonRegister src1, 4378 QwNeonRegister src2) { 4379 DCHECK(IsEnabled(NEON)); 4380 // Qd = vsub(Qn, Qm) SIMD floating point subtraction. 4381 // Instruction details available in ARM DDI 0406C.b, A8-1086. 4382 emit(EncodeNeonBinOp(VSUBF, dst, src1, src2)); 4383} 4384 4385void Assembler::vsub(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 4386 QwNeonRegister src2) { 4387 DCHECK(IsEnabled(NEON)); 4388 // Qd = vsub(Qn, Qm) SIMD integer subtraction. 4389 // Instruction details available in ARM DDI 0406C.b, A8-1084. 4390 emit(EncodeNeonBinOp(VSUB, size, dst, src1, src2)); 4391} 4392 4393void Assembler::vqsub(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4394 QwNeonRegister src2) { 4395 DCHECK(IsEnabled(NEON)); 4396 // Qd = vqsub(Qn, Qm) SIMD integer saturating subtraction. 4397 // Instruction details available in ARM DDI 0406C.b, A8-1020. 4398 emit(EncodeNeonBinOp(VQSUB, dt, dst, src1, src2)); 4399} 4400 4401void Assembler::vmul(QwNeonRegister dst, QwNeonRegister src1, 4402 QwNeonRegister src2) { 4403 DCHECK(IsEnabled(NEON)); 4404 // Qd = vadd(Qn, Qm) SIMD floating point multiply. 4405 // Instruction details available in ARM DDI 0406C.b, A8-958. 4406 emit(EncodeNeonBinOp(VMULF, dst, src1, src2)); 4407} 4408 4409void Assembler::vmul(NeonSize size, QwNeonRegister dst, 4410 const QwNeonRegister src1, const QwNeonRegister src2) { 4411 DCHECK(IsEnabled(NEON)); 4412 // Qd = vadd(Qn, Qm) SIMD integer multiply. 4413 // Instruction details available in ARM DDI 0406C.b, A8-960. 4414 emit(EncodeNeonBinOp(VMUL, size, dst, src1, src2)); 4415} 4416 4417void Assembler::vmin(const QwNeonRegister dst, const QwNeonRegister src1, 4418 const QwNeonRegister src2) { 4419 DCHECK(IsEnabled(NEON)); 4420 // Qd = vmin(Qn, Qm) SIMD floating point MIN. 4421 // Instruction details available in ARM DDI 0406C.b, A8-928. 4422 emit(EncodeNeonBinOp(VMINF, dst, src1, src2)); 4423} 4424 4425void Assembler::vmin(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4426 QwNeonRegister src2) { 4427 DCHECK(IsEnabled(NEON)); 4428 // Qd = vmin(Qn, Qm) SIMD integer MIN. 4429 // Instruction details available in ARM DDI 0406C.b, A8-926. 4430 emit(EncodeNeonBinOp(VMIN, dt, dst, src1, src2)); 4431} 4432 4433void Assembler::vmax(QwNeonRegister dst, QwNeonRegister src1, 4434 QwNeonRegister src2) { 4435 DCHECK(IsEnabled(NEON)); 4436 // Qd = vmax(Qn, Qm) SIMD floating point MAX. 4437 // Instruction details available in ARM DDI 0406C.b, A8-928. 4438 emit(EncodeNeonBinOp(VMAXF, dst, src1, src2)); 4439} 4440 4441void Assembler::vmax(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4442 QwNeonRegister src2) { 4443 DCHECK(IsEnabled(NEON)); 4444 // Qd = vmax(Qn, Qm) SIMD integer MAX. 4445 // Instruction details available in ARM DDI 0406C.b, A8-926. 4446 emit(EncodeNeonBinOp(VMAX, dt, dst, src1, src2)); 4447} 4448 4449enum NeonShiftOp { VSHL, VSHR }; 4450 4451static Instr EncodeNeonShiftOp(NeonShiftOp op, NeonDataType dt, 4452 QwNeonRegister dst, QwNeonRegister src, 4453 int shift) { 4454 int vd, d; 4455 dst.split_code(&vd, &d); 4456 int vm, m; 4457 src.split_code(&vm, &m); 4458 int size_in_bits = kBitsPerByte << NeonSz(dt); 4459 int op_encoding = 0; 4460 int imm6 = 0; 4461 if (op == VSHL) { 4462 DCHECK(shift >= 0 && size_in_bits > shift); 4463 imm6 = size_in_bits + shift; 4464 op_encoding = 0x5 * B8; 4465 } else { 4466 DCHECK_EQ(VSHR, op); 4467 DCHECK(shift > 0 && size_in_bits >= shift); 4468 imm6 = 2 * size_in_bits - shift; 4469 op_encoding = NeonU(dt) * B24; 4470 } 4471 return 0x1E5U * B23 | d * B22 | imm6 * B16 | vd * B12 | B6 | m * B5 | B4 | 4472 vm | op_encoding; 4473} 4474 4475void Assembler::vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, 4476 int shift) { 4477 DCHECK(IsEnabled(NEON)); 4478 // Qd = vshl(Qm, bits) SIMD shift left immediate. 4479 // Instruction details available in ARM DDI 0406C.b, A8-1046. 4480 emit(EncodeNeonShiftOp(VSHL, dt, dst, src, shift)); 4481} 4482 4483void Assembler::vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, 4484 int shift) { 4485 DCHECK(IsEnabled(NEON)); 4486 // Qd = vshl(Qm, bits) SIMD shift right immediate. 4487 // Instruction details available in ARM DDI 0406C.b, A8-1052. 4488 emit(EncodeNeonShiftOp(VSHR, dt, dst, src, shift)); 4489} 4490 4491static Instr EncodeNeonEstimateOp(bool is_rsqrt, QwNeonRegister dst, 4492 QwNeonRegister src) { 4493 int vd, d; 4494 dst.split_code(&vd, &d); 4495 int vm, m; 4496 src.split_code(&vm, &m); 4497 int rsqrt = is_rsqrt ? 1 : 0; 4498 return 0x1E7U * B23 | d * B22 | 0x3B * B16 | vd * B12 | 0x5 * B8 | 4499 rsqrt * B7 | B6 | m * B5 | vm; 4500} 4501 4502void Assembler::vrecpe(QwNeonRegister dst, QwNeonRegister src) { 4503 DCHECK(IsEnabled(NEON)); 4504 // Qd = vrecpe(Qm) SIMD reciprocal estimate. 4505 // Instruction details available in ARM DDI 0406C.b, A8-1024. 4506 emit(EncodeNeonEstimateOp(false, dst, src)); 4507} 4508 4509void Assembler::vrsqrte(QwNeonRegister dst, QwNeonRegister src) { 4510 DCHECK(IsEnabled(NEON)); 4511 // Qd = vrsqrte(Qm) SIMD reciprocal square root estimate. 4512 // Instruction details available in ARM DDI 0406C.b, A8-1038. 4513 emit(EncodeNeonEstimateOp(true, dst, src)); 4514} 4515 4516void Assembler::vrecps(QwNeonRegister dst, QwNeonRegister src1, 4517 QwNeonRegister src2) { 4518 DCHECK(IsEnabled(NEON)); 4519 // Qd = vrecps(Qn, Qm) SIMD reciprocal refinement step. 4520 // Instruction details available in ARM DDI 0406C.b, A8-1026. 4521 emit(EncodeNeonBinOp(VRECPS, dst, src1, src2)); 4522} 4523 4524void Assembler::vrsqrts(QwNeonRegister dst, QwNeonRegister src1, 4525 QwNeonRegister src2) { 4526 DCHECK(IsEnabled(NEON)); 4527 // Qd = vrsqrts(Qn, Qm) SIMD reciprocal square root refinement step. 4528 // Instruction details available in ARM DDI 0406C.b, A8-1040. 4529 emit(EncodeNeonBinOp(VRSQRTS, dst, src1, src2)); 4530} 4531 4532void Assembler::vtst(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 4533 QwNeonRegister src2) { 4534 DCHECK(IsEnabled(NEON)); 4535 // Qd = vtst(Qn, Qm) SIMD test integer operands. 4536 // Instruction details available in ARM DDI 0406C.b, A8-1098. 4537 emit(EncodeNeonBinOp(VTST, size, dst, src1, src2)); 4538} 4539 4540void Assembler::vceq(QwNeonRegister dst, QwNeonRegister src1, 4541 QwNeonRegister src2) { 4542 DCHECK(IsEnabled(NEON)); 4543 // Qd = vceq(Qn, Qm) SIMD floating point compare equal. 4544 // Instruction details available in ARM DDI 0406C.b, A8-844. 4545 emit(EncodeNeonBinOp(VCEQF, dst, src1, src2)); 4546} 4547 4548void Assembler::vceq(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 4549 QwNeonRegister src2) { 4550 DCHECK(IsEnabled(NEON)); 4551 // Qd = vceq(Qn, Qm) SIMD integer compare equal. 4552 // Instruction details available in ARM DDI 0406C.b, A8-844. 4553 emit(EncodeNeonBinOp(VCEQ, size, dst, src1, src2)); 4554} 4555 4556void Assembler::vcge(QwNeonRegister dst, QwNeonRegister src1, 4557 QwNeonRegister src2) { 4558 DCHECK(IsEnabled(NEON)); 4559 // Qd = vcge(Qn, Qm) SIMD floating point compare greater or equal. 4560 // Instruction details available in ARM DDI 0406C.b, A8-848. 4561 emit(EncodeNeonBinOp(VCGEF, dst, src1, src2)); 4562} 4563 4564void Assembler::vcge(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4565 QwNeonRegister src2) { 4566 DCHECK(IsEnabled(NEON)); 4567 // Qd = vcge(Qn, Qm) SIMD integer compare greater or equal. 4568 // Instruction details available in ARM DDI 0406C.b, A8-848. 4569 emit(EncodeNeonBinOp(VCGE, dt, dst, src1, src2)); 4570} 4571 4572void Assembler::vcgt(QwNeonRegister dst, QwNeonRegister src1, 4573 QwNeonRegister src2) { 4574 DCHECK(IsEnabled(NEON)); 4575 // Qd = vcgt(Qn, Qm) SIMD floating point compare greater than. 4576 // Instruction details available in ARM DDI 0406C.b, A8-852. 4577 emit(EncodeNeonBinOp(VCGTF, dst, src1, src2)); 4578} 4579 4580void Assembler::vcgt(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 4581 QwNeonRegister src2) { 4582 DCHECK(IsEnabled(NEON)); 4583 // Qd = vcgt(Qn, Qm) SIMD integer compare greater than. 4584 // Instruction details available in ARM DDI 0406C.b, A8-852. 4585 emit(EncodeNeonBinOp(VCGT, dt, dst, src1, src2)); 4586} 4587 4588void Assembler::vext(QwNeonRegister dst, const QwNeonRegister src1, 4589 const QwNeonRegister src2, int bytes) { 4590 DCHECK(IsEnabled(NEON)); 4591 // Qd = vext(Qn, Qm) SIMD byte extract. 4592 // Instruction details available in ARM DDI 0406C.b, A8-890. 4593 int vd, d; 4594 dst.split_code(&vd, &d); 4595 int vn, n; 4596 src1.split_code(&vn, &n); 4597 int vm, m; 4598 src2.split_code(&vm, &m); 4599 DCHECK_GT(16, bytes); 4600 emit(0x1E5U * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | bytes * B8 | 4601 n * B7 | B6 | m * B5 | vm); 4602} 4603 4604void Assembler::vzip(NeonSize size, QwNeonRegister dst, 4605 const QwNeonRegister src) { 4606 DCHECK(IsEnabled(NEON)); 4607 // Qd = vzip.<size>(Qn, Qm) SIMD zip (interleave). 4608 // Instruction details available in ARM DDI 0406C.b, A8-1102. 4609 int vd, d; 4610 dst.split_code(&vd, &d); 4611 int vm, m; 4612 src.split_code(&vm, &m); 4613 int sz = static_cast<int>(size); 4614 emit(0x1E7U * B23 | d * B22 | 0x3 * B20 | sz * B18 | 2 * B16 | vd * B12 | 4615 0x3 * B7 | B6 | m * B5 | vm); 4616} 4617 4618static Instr EncodeNeonVREV(NeonSize op_size, NeonSize size, 4619 const QwNeonRegister dst, 4620 const QwNeonRegister src) { 4621 // Qd = vrev<op_size>.<size>(Qn, Qm) SIMD scalar reverse. 4622 // Instruction details available in ARM DDI 0406C.b, A8-1028. 4623 DCHECK_GT(op_size, static_cast<int>(size)); 4624 int vd, d; 4625 dst.split_code(&vd, &d); 4626 int vm, m; 4627 src.split_code(&vm, &m); 4628 int sz = static_cast<int>(size); 4629 int op = static_cast<int>(Neon64) - static_cast<int>(op_size); 4630 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | sz * B18 | vd * B12 | op * B7 | 4631 B6 | m * B5 | vm; 4632} 4633 4634void Assembler::vrev16(NeonSize size, const QwNeonRegister dst, 4635 const QwNeonRegister src) { 4636 DCHECK(IsEnabled(NEON)); 4637 emit(EncodeNeonVREV(Neon16, size, dst, src)); 4638} 4639 4640void Assembler::vrev32(NeonSize size, const QwNeonRegister dst, 4641 const QwNeonRegister src) { 4642 DCHECK(IsEnabled(NEON)); 4643 emit(EncodeNeonVREV(Neon32, size, dst, src)); 4644} 4645 4646void Assembler::vrev64(NeonSize size, const QwNeonRegister dst, 4647 const QwNeonRegister src) { 4648 DCHECK(IsEnabled(NEON)); 4649 emit(EncodeNeonVREV(Neon64, size, dst, src)); 4650} 4651 4652// Encode NEON vtbl / vtbx instruction. 4653static Instr EncodeNeonVTB(const DwVfpRegister dst, const NeonListOperand& list, 4654 const DwVfpRegister index, bool vtbx) { 4655 // Dd = vtbl(table, Dm) SIMD vector permute, zero at out of range indices. 4656 // Instruction details available in ARM DDI 0406C.b, A8-1094. 4657 // Dd = vtbx(table, Dm) SIMD vector permute, skip out of range indices. 4658 // Instruction details available in ARM DDI 0406C.b, A8-1094. 4659 int vd, d; 4660 dst.split_code(&vd, &d); 4661 int vn, n; 4662 list.base().split_code(&vn, &n); 4663 int vm, m; 4664 index.split_code(&vm, &m); 4665 int op = vtbx ? 1 : 0; // vtbl = 0, vtbx = 1. 4666 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 0x2 * B10 | 4667 list.length() * B8 | n * B7 | op * B6 | m * B5 | vm; 4668} 4669 4670void Assembler::vtbl(const DwVfpRegister dst, const NeonListOperand& list, 4671 const DwVfpRegister index) { 4672 DCHECK(IsEnabled(NEON)); 4673 emit(EncodeNeonVTB(dst, list, index, false)); 4674} 4675 4676void Assembler::vtbx(const DwVfpRegister dst, const NeonListOperand& list, 4677 const DwVfpRegister index) { 4678 DCHECK(IsEnabled(NEON)); 4679 emit(EncodeNeonVTB(dst, list, index, true)); 4680} 4681 4682// Pseudo instructions. 4683void Assembler::nop(int type) { 4684 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes 4685 // some of the CPU's pipeline and has to issue. Older ARM chips simply used 4686 // MOV Rx, Rx as NOP and it performs better even in newer CPUs. 4687 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode 4688 // a type. 4689 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop. 4690 emit(al | 13*B21 | type*B12 | type); 4691} 4692 4693 4694bool Assembler::IsMovT(Instr instr) { 4695 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions 4696 ((kNumRegisters-1)*B12) | // mask out register 4697 EncodeMovwImmediate(0xFFFF)); // mask out immediate value 4698 return instr == kMovtPattern; 4699} 4700 4701 4702bool Assembler::IsMovW(Instr instr) { 4703 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions 4704 ((kNumRegisters-1)*B12) | // mask out destination 4705 EncodeMovwImmediate(0xFFFF)); // mask out immediate value 4706 return instr == kMovwPattern; 4707} 4708 4709 4710Instr Assembler::GetMovTPattern() { return kMovtPattern; } 4711 4712 4713Instr Assembler::GetMovWPattern() { return kMovwPattern; } 4714 4715 4716Instr Assembler::EncodeMovwImmediate(uint32_t immediate) { 4717 DCHECK(immediate < 0x10000); 4718 return ((immediate & 0xf000) << 4) | (immediate & 0xfff); 4719} 4720 4721 4722Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) { 4723 instruction &= ~EncodeMovwImmediate(0xffff); 4724 return instruction | EncodeMovwImmediate(immediate); 4725} 4726 4727 4728int Assembler::DecodeShiftImm(Instr instr) { 4729 int rotate = Instruction::RotateValue(instr) * 2; 4730 int immed8 = Instruction::Immed8Value(instr); 4731 return base::bits::RotateRight32(immed8, rotate); 4732} 4733 4734 4735Instr Assembler::PatchShiftImm(Instr instr, int immed) { 4736 uint32_t rotate_imm = 0; 4737 uint32_t immed_8 = 0; 4738 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL); 4739 DCHECK(immed_fits); 4740 USE(immed_fits); 4741 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8; 4742} 4743 4744 4745bool Assembler::IsNop(Instr instr, int type) { 4746 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop. 4747 // Check for mov rx, rx where x = type. 4748 return instr == (al | 13*B21 | type*B12 | type); 4749} 4750 4751 4752bool Assembler::IsMovImmed(Instr instr) { 4753 return (instr & kMovImmedMask) == kMovImmedPattern; 4754} 4755 4756 4757bool Assembler::IsOrrImmed(Instr instr) { 4758 return (instr & kOrrImmedMask) == kOrrImmedPattern; 4759} 4760 4761 4762// static 4763bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { 4764 uint32_t dummy1; 4765 uint32_t dummy2; 4766 return fits_shifter(imm32, &dummy1, &dummy2, NULL); 4767} 4768 4769 4770bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) { 4771 return is_uint12(abs(imm32)); 4772} 4773 4774 4775// Debugging. 4776void Assembler::RecordConstPool(int size) { 4777 // We only need this for debugger support, to correctly compute offsets in the 4778 // code. 4779 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size)); 4780} 4781 4782 4783void Assembler::GrowBuffer() { 4784 if (!own_buffer_) FATAL("external code buffer is too small"); 4785 4786 // Compute new buffer size. 4787 CodeDesc desc; // the new buffer 4788 if (buffer_size_ < 1 * MB) { 4789 desc.buffer_size = 2*buffer_size_; 4790 } else { 4791 desc.buffer_size = buffer_size_ + 1*MB; 4792 } 4793 CHECK_GT(desc.buffer_size, 0); // no overflow 4794 4795 // Set up new buffer. 4796 desc.buffer = NewArray<byte>(desc.buffer_size); 4797 4798 desc.instr_size = pc_offset(); 4799 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 4800 desc.origin = this; 4801 4802 // Copy the data. 4803 int pc_delta = desc.buffer - buffer_; 4804 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); 4805 MemMove(desc.buffer, buffer_, desc.instr_size); 4806 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), 4807 desc.reloc_size); 4808 4809 // Switch buffers. 4810 DeleteArray(buffer_); 4811 buffer_ = desc.buffer; 4812 buffer_size_ = desc.buffer_size; 4813 pc_ += pc_delta; 4814 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 4815 reloc_info_writer.last_pc() + pc_delta); 4816 4817 // None of our relocation types are pc relative pointing outside the code 4818 // buffer nor pc absolute pointing inside the code buffer, so there is no need 4819 // to relocate any emitted relocation entries. 4820} 4821 4822 4823void Assembler::db(uint8_t data) { 4824 // db is used to write raw data. The constant pool should be emitted or 4825 // blocked before using db. 4826 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty()); 4827 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty()); 4828 CheckBuffer(); 4829 *reinterpret_cast<uint8_t*>(pc_) = data; 4830 pc_ += sizeof(uint8_t); 4831} 4832 4833 4834void Assembler::dd(uint32_t data) { 4835 // dd is used to write raw data. The constant pool should be emitted or 4836 // blocked before using dd. 4837 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty()); 4838 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty()); 4839 CheckBuffer(); 4840 *reinterpret_cast<uint32_t*>(pc_) = data; 4841 pc_ += sizeof(uint32_t); 4842} 4843 4844 4845void Assembler::dq(uint64_t value) { 4846 // dq is used to write raw data. The constant pool should be emitted or 4847 // blocked before using dq. 4848 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty()); 4849 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty()); 4850 CheckBuffer(); 4851 *reinterpret_cast<uint64_t*>(pc_) = value; 4852 pc_ += sizeof(uint64_t); 4853} 4854 4855 4856void Assembler::emit_code_stub_address(Code* stub) { 4857 CheckBuffer(); 4858 *reinterpret_cast<uint32_t*>(pc_) = 4859 reinterpret_cast<uint32_t>(stub->instruction_start()); 4860 pc_ += sizeof(uint32_t); 4861} 4862 4863 4864void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 4865 if (RelocInfo::IsNone(rmode) || 4866 // Don't record external references unless the heap will be serialized. 4867 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() && 4868 !emit_debug_code())) { 4869 return; 4870 } 4871 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here 4872 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { 4873 data = RecordedAstId().ToInt(); 4874 ClearRecordedAstId(); 4875 } 4876 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL); 4877 reloc_info_writer.Write(&rinfo); 4878} 4879 4880 4881ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, 4882 RelocInfo::Mode rmode, 4883 intptr_t value) { 4884 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::CONST_POOL && 4885 rmode != RelocInfo::NONE64); 4886 bool sharing_ok = RelocInfo::IsNone(rmode) || 4887 !(serializer_enabled() || rmode < RelocInfo::CELL); 4888 if (FLAG_enable_embedded_constant_pool) { 4889 return constant_pool_builder_.AddEntry(position, value, sharing_ok); 4890 } else { 4891 DCHECK(pending_32_bit_constants_.size() < kMaxNumPending32Constants); 4892 if (pending_32_bit_constants_.empty()) { 4893 first_const_pool_32_use_ = position; 4894 } 4895 ConstantPoolEntry entry(position, value, sharing_ok); 4896 pending_32_bit_constants_.push_back(entry); 4897 4898 // Make sure the constant pool is not emitted in place of the next 4899 // instruction for which we just recorded relocation info. 4900 BlockConstPoolFor(1); 4901 return ConstantPoolEntry::REGULAR; 4902 } 4903} 4904 4905 4906ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, 4907 double value) { 4908 if (FLAG_enable_embedded_constant_pool) { 4909 return constant_pool_builder_.AddEntry(position, value); 4910 } else { 4911 DCHECK(pending_64_bit_constants_.size() < kMaxNumPending64Constants); 4912 if (pending_64_bit_constants_.empty()) { 4913 first_const_pool_64_use_ = position; 4914 } 4915 ConstantPoolEntry entry(position, value); 4916 pending_64_bit_constants_.push_back(entry); 4917 4918 // Make sure the constant pool is not emitted in place of the next 4919 // instruction for which we just recorded relocation info. 4920 BlockConstPoolFor(1); 4921 return ConstantPoolEntry::REGULAR; 4922 } 4923} 4924 4925 4926void Assembler::BlockConstPoolFor(int instructions) { 4927 if (FLAG_enable_embedded_constant_pool) { 4928 // Should be a no-op if using an embedded constant pool. 4929 DCHECK(pending_32_bit_constants_.empty()); 4930 DCHECK(pending_64_bit_constants_.empty()); 4931 return; 4932 } 4933 4934 int pc_limit = pc_offset() + instructions * kInstrSize; 4935 if (no_const_pool_before_ < pc_limit) { 4936 // Max pool start (if we need a jump and an alignment). 4937#ifdef DEBUG 4938 int start = pc_limit + kInstrSize + 2 * kPointerSize; 4939 DCHECK(pending_32_bit_constants_.empty() || 4940 (start - first_const_pool_32_use_ + 4941 pending_64_bit_constants_.size() * kDoubleSize < 4942 kMaxDistToIntPool)); 4943 DCHECK(pending_64_bit_constants_.empty() || 4944 (start - first_const_pool_64_use_ < kMaxDistToFPPool)); 4945#endif 4946 no_const_pool_before_ = pc_limit; 4947 } 4948 4949 if (next_buffer_check_ < no_const_pool_before_) { 4950 next_buffer_check_ = no_const_pool_before_; 4951 } 4952} 4953 4954 4955void Assembler::CheckConstPool(bool force_emit, bool require_jump) { 4956 if (FLAG_enable_embedded_constant_pool) { 4957 // Should be a no-op if using an embedded constant pool. 4958 DCHECK(pending_32_bit_constants_.empty()); 4959 DCHECK(pending_64_bit_constants_.empty()); 4960 return; 4961 } 4962 4963 // Some short sequence of instruction mustn't be broken up by constant pool 4964 // emission, such sequences are protected by calls to BlockConstPoolFor and 4965 // BlockConstPoolScope. 4966 if (is_const_pool_blocked()) { 4967 // Something is wrong if emission is forced and blocked at the same time. 4968 DCHECK(!force_emit); 4969 return; 4970 } 4971 4972 // There is nothing to do if there are no pending constant pool entries. 4973 if (pending_32_bit_constants_.empty() && pending_64_bit_constants_.empty()) { 4974 // Calculate the offset of the next check. 4975 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 4976 return; 4977 } 4978 4979 // Check that the code buffer is large enough before emitting the constant 4980 // pool (include the jump over the pool and the constant pool marker and 4981 // the gap to the relocation information). 4982 int jump_instr = require_jump ? kInstrSize : 0; 4983 int size_up_to_marker = jump_instr + kInstrSize; 4984 int estimated_size_after_marker = 4985 pending_32_bit_constants_.size() * kPointerSize; 4986 bool has_int_values = !pending_32_bit_constants_.empty(); 4987 bool has_fp_values = !pending_64_bit_constants_.empty(); 4988 bool require_64_bit_align = false; 4989 if (has_fp_values) { 4990 require_64_bit_align = 4991 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker), 4992 kDoubleAlignment); 4993 if (require_64_bit_align) { 4994 estimated_size_after_marker += kInstrSize; 4995 } 4996 estimated_size_after_marker += 4997 pending_64_bit_constants_.size() * kDoubleSize; 4998 } 4999 int estimated_size = size_up_to_marker + estimated_size_after_marker; 5000 5001 // We emit a constant pool when: 5002 // * requested to do so by parameter force_emit (e.g. after each function). 5003 // * the distance from the first instruction accessing the constant pool to 5004 // any of the constant pool entries will exceed its limit the next 5005 // time the pool is checked. This is overly restrictive, but we don't emit 5006 // constant pool entries in-order so it's conservatively correct. 5007 // * the instruction doesn't require a jump after itself to jump over the 5008 // constant pool, and we're getting close to running out of range. 5009 if (!force_emit) { 5010 DCHECK(has_fp_values || has_int_values); 5011 bool need_emit = false; 5012 if (has_fp_values) { 5013 // The 64-bit constants are always emitted before the 32-bit constants, so 5014 // we can ignore the effect of the 32-bit constants on estimated_size. 5015 int dist64 = pc_offset() + estimated_size - 5016 pending_32_bit_constants_.size() * kPointerSize - 5017 first_const_pool_64_use_; 5018 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) || 5019 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) { 5020 need_emit = true; 5021 } 5022 } 5023 if (has_int_values) { 5024 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_; 5025 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) || 5026 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) { 5027 need_emit = true; 5028 } 5029 } 5030 if (!need_emit) return; 5031 } 5032 5033 // Deduplicate constants. 5034 int size_after_marker = estimated_size_after_marker; 5035 for (size_t i = 0; i < pending_64_bit_constants_.size(); i++) { 5036 ConstantPoolEntry& entry = pending_64_bit_constants_[i]; 5037 DCHECK(!entry.is_merged()); 5038 for (size_t j = 0; j < i; j++) { 5039 if (entry.value64() == pending_64_bit_constants_[j].value64()) { 5040 DCHECK(!pending_64_bit_constants_[j].is_merged()); 5041 entry.set_merged_index(j); 5042 size_after_marker -= kDoubleSize; 5043 break; 5044 } 5045 } 5046 } 5047 5048 for (size_t i = 0; i < pending_32_bit_constants_.size(); i++) { 5049 ConstantPoolEntry& entry = pending_32_bit_constants_[i]; 5050 DCHECK(!entry.is_merged()); 5051 if (!entry.sharing_ok()) continue; 5052 for (size_t j = 0; j < i; j++) { 5053 if (entry.value() == pending_32_bit_constants_[j].value()) { 5054 DCHECK(!pending_32_bit_constants_[j].is_merged()); 5055 entry.set_merged_index(j); 5056 size_after_marker -= kPointerSize; 5057 break; 5058 } 5059 } 5060 } 5061 5062 int size = size_up_to_marker + size_after_marker; 5063 5064 int needed_space = size + kGap; 5065 while (buffer_space() <= needed_space) GrowBuffer(); 5066 5067 { 5068 // Block recursive calls to CheckConstPool. 5069 BlockConstPoolScope block_const_pool(this); 5070 RecordComment("[ Constant Pool"); 5071 RecordConstPool(size); 5072 5073 Label size_check; 5074 bind(&size_check); 5075 5076 // Emit jump over constant pool if necessary. 5077 Label after_pool; 5078 if (require_jump) { 5079 b(&after_pool); 5080 } 5081 5082 // Put down constant pool marker "Undefined instruction". 5083 // The data size helps disassembly know what to print. 5084 emit(kConstantPoolMarker | 5085 EncodeConstantPoolLength(size_after_marker / kPointerSize)); 5086 5087 if (require_64_bit_align) { 5088 emit(kConstantPoolMarker); 5089 } 5090 5091 // Emit 64-bit constant pool entries first: their range is smaller than 5092 // 32-bit entries. 5093 for (size_t i = 0; i < pending_64_bit_constants_.size(); i++) { 5094 ConstantPoolEntry& entry = pending_64_bit_constants_[i]; 5095 5096 Instr instr = instr_at(entry.position()); 5097 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0. 5098 DCHECK((IsVldrDPcImmediateOffset(instr) && 5099 GetVldrDRegisterImmediateOffset(instr) == 0)); 5100 5101 int delta = pc_offset() - entry.position() - kPcLoadDelta; 5102 DCHECK(is_uint10(delta)); 5103 5104 if (entry.is_merged()) { 5105 ConstantPoolEntry& merged = 5106 pending_64_bit_constants_[entry.merged_index()]; 5107 DCHECK(entry.value64() == merged.value64()); 5108 Instr merged_instr = instr_at(merged.position()); 5109 DCHECK(IsVldrDPcImmediateOffset(merged_instr)); 5110 delta = GetVldrDRegisterImmediateOffset(merged_instr); 5111 delta += merged.position() - entry.position(); 5112 } 5113 instr_at_put(entry.position(), 5114 SetVldrDRegisterImmediateOffset(instr, delta)); 5115 if (!entry.is_merged()) { 5116 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment)); 5117 dq(entry.value64()); 5118 } 5119 } 5120 5121 // Emit 32-bit constant pool entries. 5122 for (size_t i = 0; i < pending_32_bit_constants_.size(); i++) { 5123 ConstantPoolEntry& entry = pending_32_bit_constants_[i]; 5124 Instr instr = instr_at(entry.position()); 5125 5126 // 64-bit loads shouldn't get here. 5127 DCHECK(!IsVldrDPcImmediateOffset(instr)); 5128 DCHECK(!IsMovW(instr)); 5129 DCHECK(IsLdrPcImmediateOffset(instr) && 5130 GetLdrRegisterImmediateOffset(instr) == 0); 5131 5132 int delta = pc_offset() - entry.position() - kPcLoadDelta; 5133 DCHECK(is_uint12(delta)); 5134 // 0 is the smallest delta: 5135 // ldr rd, [pc, #0] 5136 // constant pool marker 5137 // data 5138 5139 if (entry.is_merged()) { 5140 DCHECK(entry.sharing_ok()); 5141 ConstantPoolEntry& merged = 5142 pending_32_bit_constants_[entry.merged_index()]; 5143 DCHECK(entry.value() == merged.value()); 5144 Instr merged_instr = instr_at(merged.position()); 5145 DCHECK(IsLdrPcImmediateOffset(merged_instr)); 5146 delta = GetLdrRegisterImmediateOffset(merged_instr); 5147 delta += merged.position() - entry.position(); 5148 } 5149 instr_at_put(entry.position(), 5150 SetLdrRegisterImmediateOffset(instr, delta)); 5151 if (!entry.is_merged()) { 5152 emit(entry.value()); 5153 } 5154 } 5155 5156 pending_32_bit_constants_.clear(); 5157 pending_64_bit_constants_.clear(); 5158 first_const_pool_32_use_ = -1; 5159 first_const_pool_64_use_ = -1; 5160 5161 RecordComment("]"); 5162 5163 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check)); 5164 5165 if (after_pool.is_linked()) { 5166 bind(&after_pool); 5167 } 5168 } 5169 5170 // Since a constant pool was just emitted, move the check offset forward by 5171 // the standard interval. 5172 next_buffer_check_ = pc_offset() + kCheckPoolInterval; 5173} 5174 5175 5176void Assembler::PatchConstantPoolAccessInstruction( 5177 int pc_offset, int offset, ConstantPoolEntry::Access access, 5178 ConstantPoolEntry::Type type) { 5179 DCHECK(FLAG_enable_embedded_constant_pool); 5180 Address pc = buffer_ + pc_offset; 5181 5182 // Patch vldr/ldr instruction with correct offset. 5183 Instr instr = instr_at(pc); 5184 if (access == ConstantPoolEntry::OVERFLOWED) { 5185 if (CpuFeatures::IsSupported(ARMv7)) { 5186 CpuFeatureScope scope(this, ARMv7); 5187 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0]. 5188 Instr next_instr = instr_at(pc + kInstrSize); 5189 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0)); 5190 DCHECK((IsMovT(next_instr) && 5191 Instruction::ImmedMovwMovtValue(next_instr) == 0)); 5192 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff)); 5193 instr_at_put(pc + kInstrSize, 5194 PatchMovwImmediate(next_instr, offset >> 16)); 5195 } else { 5196 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0]. 5197 Instr instr_2 = instr_at(pc + kInstrSize); 5198 Instr instr_3 = instr_at(pc + 2 * kInstrSize); 5199 Instr instr_4 = instr_at(pc + 3 * kInstrSize); 5200 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0)); 5201 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) && 5202 GetRn(instr_2).is(GetRd(instr_2))); 5203 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) && 5204 GetRn(instr_3).is(GetRd(instr_3))); 5205 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) && 5206 GetRn(instr_4).is(GetRd(instr_4))); 5207 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask))); 5208 instr_at_put(pc + kInstrSize, 5209 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8)))); 5210 instr_at_put(pc + 2 * kInstrSize, 5211 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16)))); 5212 instr_at_put(pc + 3 * kInstrSize, 5213 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24)))); 5214 } 5215 } else if (type == ConstantPoolEntry::DOUBLE) { 5216 // Instruction to patch must be 'vldr rd, [pp, #0]'. 5217 DCHECK((IsVldrDPpImmediateOffset(instr) && 5218 GetVldrDRegisterImmediateOffset(instr) == 0)); 5219 DCHECK(is_uint10(offset)); 5220 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset)); 5221 } else { 5222 // Instruction to patch must be 'ldr rd, [pp, #0]'. 5223 DCHECK((IsLdrPpImmediateOffset(instr) && 5224 GetLdrRegisterImmediateOffset(instr) == 0)); 5225 DCHECK(is_uint12(offset)); 5226 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset)); 5227 } 5228} 5229 5230 5231} // namespace internal 5232} // namespace v8 5233 5234#endif // V8_TARGET_ARCH_ARM 5235