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 // A light-weight ARM Assembler 38 // Generates user mode instructions for the ARM architecture up to version 5 39 40 #ifndef V8_CODEGEN_ARM_ASSEMBLER_ARM_H_ 41 #define V8_CODEGEN_ARM_ASSEMBLER_ARM_H_ 42 43 #include <stdio.h> 44 45 #include <memory> 46 47 #include "src/base/numbers/double.h" 48 #include "src/base/small-vector.h" 49 #include "src/codegen/arm/constants-arm.h" 50 #include "src/codegen/arm/register-arm.h" 51 #include "src/codegen/assembler.h" 52 #include "src/codegen/constant-pool.h" 53 #include "src/codegen/machine-type.h" 54 #include "src/utils/boxed-float.h" 55 56 namespace v8 { 57 namespace internal { 58 59 class SafepointTableBuilder; 60 61 // Coprocessor number 62 enum Coprocessor { 63 p0 = 0, 64 p1 = 1, 65 p2 = 2, 66 p3 = 3, 67 p4 = 4, 68 p5 = 5, 69 p6 = 6, 70 p7 = 7, 71 p8 = 8, 72 p9 = 9, 73 p10 = 10, 74 p11 = 11, 75 p12 = 12, 76 p13 = 13, 77 p14 = 14, 78 p15 = 15 79 }; 80 81 // ----------------------------------------------------------------------------- 82 // Machine instruction Operands 83 84 // Class Operand represents a shifter operand in data processing instructions 85 class V8_EXPORT_PRIVATE Operand { 86 public: 87 // immediate Operand(int32_t immediate, RelocInfo::Mode rmode = RelocInfo::NO_INFO)88 V8_INLINE explicit Operand(int32_t immediate, 89 RelocInfo::Mode rmode = RelocInfo::NO_INFO) 90 : rmode_(rmode) { 91 value_.immediate = immediate; 92 } 93 V8_INLINE static Operand Zero(); 94 V8_INLINE explicit Operand(const ExternalReference& f); 95 explicit Operand(Handle<HeapObject> handle); 96 V8_INLINE explicit Operand(Smi value); 97 98 // rm 99 V8_INLINE explicit Operand(Register rm); 100 101 // rm <shift_op> shift_imm 102 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm); SmiUntag(Register rm)103 V8_INLINE static Operand SmiUntag(Register rm) { 104 return Operand(rm, ASR, kSmiTagSize); 105 } PointerOffsetFromSmiKey(Register key)106 V8_INLINE static Operand PointerOffsetFromSmiKey(Register key) { 107 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 108 return Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize); 109 } DoubleOffsetFromSmiKey(Register key)110 V8_INLINE static Operand DoubleOffsetFromSmiKey(Register key) { 111 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kDoubleSizeLog2); 112 return Operand(key, LSL, kDoubleSizeLog2 - kSmiTagSize); 113 } 114 115 // rm <shift_op> rs 116 explicit Operand(Register rm, ShiftOp shift_op, Register rs); 117 118 static Operand EmbeddedNumber(double number); // Smi or HeapNumber. 119 static Operand EmbeddedStringConstant(const StringConstantBase* str); 120 121 // Return true if this is a register operand. IsRegister() const122 bool IsRegister() const { 123 return rm_.is_valid() && rs_ == no_reg && shift_op_ == LSL && 124 shift_imm_ == 0; 125 } 126 // Return true if this is a register operand shifted with an immediate. IsImmediateShiftedRegister() const127 bool IsImmediateShiftedRegister() const { 128 return rm_.is_valid() && !rs_.is_valid(); 129 } 130 // Return true if this is a register operand shifted with a register. IsRegisterShiftedRegister() const131 bool IsRegisterShiftedRegister() const { 132 return rm_.is_valid() && rs_.is_valid(); 133 } 134 135 // Return the number of actual instructions required to implement the given 136 // instruction for this particular operand. This can be a single instruction, 137 // if no load into a scratch register is necessary, or anything between 2 and 138 // 4 instructions when we need to load from the constant pool (depending upon 139 // whether the constant pool entry is in the small or extended section). If 140 // the instruction this operand is used for is a MOV or MVN instruction the 141 // actual instruction to use is required for this calculation. For other 142 // instructions instr is ignored. 143 // 144 // The value returned is only valid as long as no entries are added to the 145 // constant pool between this call and the actual instruction being emitted. 146 int InstructionsRequired(const Assembler* assembler, Instr instr = 0) const; 147 bool MustOutputRelocInfo(const Assembler* assembler) const; 148 immediate() const149 inline int32_t immediate() const { 150 DCHECK(IsImmediate()); 151 DCHECK(!IsHeapObjectRequest()); 152 return value_.immediate; 153 } IsImmediate() const154 bool IsImmediate() const { return !rm_.is_valid(); } 155 heap_object_request() const156 HeapObjectRequest heap_object_request() const { 157 DCHECK(IsHeapObjectRequest()); 158 return value_.heap_object_request; 159 } IsHeapObjectRequest() const160 bool IsHeapObjectRequest() const { 161 DCHECK_IMPLIES(is_heap_object_request_, IsImmediate()); 162 DCHECK_IMPLIES(is_heap_object_request_, 163 rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT || 164 rmode_ == RelocInfo::CODE_TARGET); 165 return is_heap_object_request_; 166 } 167 rm() const168 Register rm() const { return rm_; } rs() const169 Register rs() const { return rs_; } shift_op() const170 ShiftOp shift_op() const { return shift_op_; } 171 172 private: 173 Register rm_ = no_reg; 174 Register rs_ = no_reg; 175 ShiftOp shift_op_; 176 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg 177 union Value { Value()178 Value() {} 179 HeapObjectRequest heap_object_request; // if is_heap_object_request_ 180 int32_t immediate; // otherwise 181 } value_; // valid if rm_ == no_reg 182 bool is_heap_object_request_ = false; 183 RelocInfo::Mode rmode_; 184 185 friend class Assembler; 186 }; 187 188 // Class MemOperand represents a memory operand in load and store instructions 189 class V8_EXPORT_PRIVATE MemOperand { 190 public: 191 // [rn +/- offset] Offset/NegOffset 192 // [rn +/- offset]! PreIndex/NegPreIndex 193 // [rn], +/- offset PostIndex/NegPostIndex 194 // offset is any signed 32-bit value; offset is first loaded to a scratch 195 // register if it does not fit the addressing mode (12-bit unsigned and sign 196 // bit) 197 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset); 198 199 // [rn +/- rm] Offset/NegOffset 200 // [rn +/- rm]! PreIndex/NegPreIndex 201 // [rn], +/- rm PostIndex/NegPostIndex 202 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset); 203 204 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset 205 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex 206 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex 207 explicit MemOperand(Register rn, Register rm, ShiftOp shift_op, int shift_imm, 208 AddrMode am = Offset); PointerAddressFromSmiKey(Register array, Register key, AddrMode am = Offset)209 V8_INLINE static MemOperand PointerAddressFromSmiKey(Register array, 210 Register key, 211 AddrMode am = Offset) { 212 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 213 return MemOperand(array, key, LSL, kPointerSizeLog2 - kSmiTagSize, am); 214 } 215 set_offset(int32_t offset)216 void set_offset(int32_t offset) { 217 DCHECK(rm_ == no_reg); 218 offset_ = offset; 219 } 220 offset() const221 uint32_t offset() const { 222 DCHECK(rm_ == no_reg); 223 return offset_; 224 } 225 rn() const226 Register rn() const { return rn_; } rm() const227 Register rm() const { return rm_; } am() const228 AddrMode am() const { return am_; } 229 OffsetIsUint12Encodable() const230 bool OffsetIsUint12Encodable() const { 231 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_); 232 } 233 234 private: 235 Register rn_; // base 236 Register rm_; // register offset 237 int32_t offset_; // valid if rm_ == no_reg 238 ShiftOp shift_op_; 239 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg 240 AddrMode am_; // bits P, U, and W 241 242 friend class Assembler; 243 }; 244 245 // Class NeonMemOperand represents a memory operand in load and 246 // store NEON instructions 247 class V8_EXPORT_PRIVATE NeonMemOperand { 248 public: 249 // [rn {:align}] Offset 250 // [rn {:align}]! PostIndex 251 explicit NeonMemOperand(Register rn, AddrMode am = Offset, int align = 0); 252 253 // [rn {:align}], rm PostIndex 254 explicit NeonMemOperand(Register rn, Register rm, int align = 0); 255 rn() const256 Register rn() const { return rn_; } rm() const257 Register rm() const { return rm_; } align() const258 int align() const { return align_; } 259 260 private: 261 void SetAlignment(int align); 262 263 Register rn_; // base 264 Register rm_; // register increment 265 int align_; 266 }; 267 268 // Class NeonListOperand represents a list of NEON registers 269 class NeonListOperand { 270 public: NeonListOperand(DoubleRegister base, int register_count = 1)271 explicit NeonListOperand(DoubleRegister base, int register_count = 1) 272 : base_(base), register_count_(register_count) {} NeonListOperand(QwNeonRegister q_reg)273 explicit NeonListOperand(QwNeonRegister q_reg) 274 : base_(q_reg.low()), register_count_(2) {} base() const275 DoubleRegister base() const { return base_; } register_count()276 int register_count() { return register_count_; } length() const277 int length() const { return register_count_ - 1; } type() const278 NeonListType type() const { 279 switch (register_count_) { 280 default: 281 UNREACHABLE(); 282 // Fall through. 283 case 1: 284 return nlt_1; 285 case 2: 286 return nlt_2; 287 case 3: 288 return nlt_3; 289 case 4: 290 return nlt_4; 291 } 292 } 293 294 private: 295 DoubleRegister base_; 296 int register_count_; 297 }; 298 299 class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { 300 public: 301 // Create an assembler. Instructions and relocation information are emitted 302 // into a buffer, with the instructions starting from the beginning and the 303 // relocation information starting from the end of the buffer. See CodeDesc 304 // for a detailed comment on the layout (globals.h). 305 // 306 // If the provided buffer is nullptr, the assembler allocates and grows its 307 // own buffer. Otherwise it takes ownership of the provided buffer. 308 explicit Assembler(const AssemblerOptions&, 309 std::unique_ptr<AssemblerBuffer> = {}); 310 311 ~Assembler() override; 312 313 void AbortedCodeGeneration() override { 314 pending_32_bit_constants_.clear(); 315 first_const_pool_32_use_ = -1; 316 } 317 318 // GetCode emits any pending (non-emitted) code and fills the descriptor desc. 319 static constexpr int kNoHandlerTable = 0; 320 static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr; 321 void GetCode(Isolate* isolate, CodeDesc* desc, 322 SafepointTableBuilder* safepoint_table_builder, 323 int handler_table_offset); 324 325 // Convenience wrapper for code without safepoint or handler tables. GetCode(Isolate* isolate, CodeDesc* desc)326 void GetCode(Isolate* isolate, CodeDesc* desc) { 327 GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable); 328 } 329 330 // Label operations & relative jumps (PPUM Appendix D) 331 // 332 // Takes a branch opcode (cc) and a label (L) and generates 333 // either a backward branch or a forward branch and links it 334 // to the label fixup chain. Usage: 335 // 336 // Label L; // unbound label 337 // j(cc, &L); // forward branch to unbound label 338 // bind(&L); // bind label to the current pc 339 // j(cc, &L); // backward branch to bound label 340 // bind(&L); // illegal: a label may be bound only once 341 // 342 // Note: The same Label can be used for forward and backward branches 343 // but it may be bound only once. 344 345 void bind(Label* L); // binds an unbound label L to the current code position 346 347 // Returns the branch offset to the given label from the current code position 348 // Links the label to the current position if it is still unbound 349 // Manages the jump elimination optimization if the second parameter is true. 350 int branch_offset(Label* L); 351 352 // Returns true if the given pc address is the start of a constant pool load 353 // instruction sequence. 354 V8_INLINE static bool is_constant_pool_load(Address pc); 355 356 // Return the address in the constant pool of the code target address used by 357 // the branch/call instruction at pc, or the object in a mov. 358 V8_INLINE static Address constant_pool_entry_address(Address pc, 359 Address constant_pool); 360 361 // Read/Modify the code target address in the branch/call instruction at pc. 362 // The isolate argument is unused (and may be nullptr) when skipping flushing. 363 V8_INLINE static Address target_address_at(Address pc, Address constant_pool); 364 V8_INLINE static void set_target_address_at( 365 Address pc, Address constant_pool, Address target, 366 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 367 368 // This sets the branch destination (which is in the constant pool on ARM). 369 // This is for calls and branches within generated code. 370 inline static void deserialization_set_special_target_at( 371 Address constant_pool_entry, Code code, Address target); 372 373 // Get the size of the special target encoded at 'location'. 374 inline static int deserialization_special_target_size(Address location); 375 376 // This sets the internal reference at the pc. 377 inline static void deserialization_set_target_internal_reference_at( 378 Address pc, Address target, 379 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE); 380 381 // Here we are patching the address in the constant pool, not the actual call 382 // instruction. The address in the constant pool is the same size as a 383 // pointer. 384 static constexpr int kSpecialTargetSize = kPointerSize; 385 GetScratchRegisterList()386 RegList* GetScratchRegisterList() { return &scratch_register_list_; } GetScratchVfpRegisterList()387 VfpRegList* GetScratchVfpRegisterList() { 388 return &scratch_vfp_register_list_; 389 } 390 391 // --------------------------------------------------------------------------- 392 // Code generation 393 394 // Insert the smallest number of nop instructions 395 // possible to align the pc offset to a multiple 396 // of m. m must be a power of 2 (>= 4). 397 void Align(int m); 398 // Insert the smallest number of zero bytes possible to align the pc offset 399 // to a mulitple of m. m must be a power of 2 (>= 2). 400 void DataAlign(int m); 401 // Aligns code to something that's optimal for a jump target for the platform. 402 void CodeTargetAlign(); LoopHeaderAlign()403 void LoopHeaderAlign() { CodeTargetAlign(); } 404 405 // Branch instructions 406 void b(int branch_offset, Condition cond = al, 407 RelocInfo::Mode rmode = RelocInfo::NO_INFO); 408 void bl(int branch_offset, Condition cond = al, 409 RelocInfo::Mode rmode = RelocInfo::NO_INFO); 410 void blx(int branch_offset); // v5 and above 411 void blx(Register target, Condition cond = al); // v5 and above 412 void bx(Register target, Condition cond = al); // v5 and above, plus v4t 413 414 // Convenience branch instructions using labels 415 void b(Label* L, Condition cond = al); b(Condition cond, Label* L)416 void b(Condition cond, Label* L) { b(L, cond); } 417 void bl(Label* L, Condition cond = al); bl(Condition cond, Label* L)418 void bl(Condition cond, Label* L) { bl(L, cond); } 419 void blx(Label* L); // v5 and above 420 421 // Data-processing instructions 422 423 void and_(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 424 Condition cond = al); 425 void and_(Register dst, Register src1, Register src2, SBit s = LeaveCC, 426 Condition cond = al); 427 428 void eor(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 429 Condition cond = al); 430 void eor(Register dst, Register src1, Register src2, SBit s = LeaveCC, 431 Condition cond = al); 432 433 void sub(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 434 Condition cond = al); 435 void sub(Register dst, Register src1, Register src2, SBit s = LeaveCC, 436 Condition cond = al); 437 438 void rsb(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 439 Condition cond = al); 440 441 void add(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 442 Condition cond = al); 443 void add(Register dst, Register src1, Register src2, SBit s = LeaveCC, 444 Condition cond = al); 445 446 void adc(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 447 Condition cond = al); 448 449 void sbc(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 450 Condition cond = al); 451 452 void rsc(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 453 Condition cond = al); 454 455 void tst(Register src1, const Operand& src2, Condition cond = al); 456 void tst(Register src1, Register src2, Condition cond = al); 457 458 void teq(Register src1, const Operand& src2, Condition cond = al); 459 460 void cmp(Register src1, const Operand& src2, Condition cond = al); 461 void cmp(Register src1, Register src2, Condition cond = al); 462 463 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al); 464 465 void cmn(Register src1, const Operand& src2, Condition cond = al); 466 467 void orr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 468 Condition cond = al); 469 void orr(Register dst, Register src1, Register src2, SBit s = LeaveCC, 470 Condition cond = al); 471 472 void mov(Register dst, const Operand& src, SBit s = LeaveCC, 473 Condition cond = al); 474 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al); 475 476 // Load the position of the label relative to the generated code object 477 // pointer in a register. 478 void mov_label_offset(Register dst, Label* label); 479 480 // ARMv7 instructions for loading a 32 bit immediate in two instructions. 481 // The constant for movw and movt should be in the range 0-0xffff. 482 void movw(Register reg, uint32_t immediate, Condition cond = al); 483 void movt(Register reg, uint32_t immediate, Condition cond = al); 484 485 void bic(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 486 Condition cond = al); 487 488 void mvn(Register dst, const Operand& src, SBit s = LeaveCC, 489 Condition cond = al); 490 491 // Shift instructions 492 493 void asr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 494 Condition cond = al); 495 496 void lsl(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 497 Condition cond = al); 498 499 void lsr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, 500 Condition cond = al); 501 502 // Multiply instructions 503 504 void mla(Register dst, Register src1, Register src2, Register srcA, 505 SBit s = LeaveCC, Condition cond = al); 506 507 void mls(Register dst, Register src1, Register src2, Register srcA, 508 Condition cond = al); 509 510 void sdiv(Register dst, Register src1, Register src2, Condition cond = al); 511 512 void udiv(Register dst, Register src1, Register src2, Condition cond = al); 513 514 void mul(Register dst, Register src1, Register src2, SBit s = LeaveCC, 515 Condition cond = al); 516 517 void smmla(Register dst, Register src1, Register src2, Register srcA, 518 Condition cond = al); 519 520 void smmul(Register dst, Register src1, Register src2, Condition cond = al); 521 522 void smlal(Register dstL, Register dstH, Register src1, Register src2, 523 SBit s = LeaveCC, Condition cond = al); 524 525 void smull(Register dstL, Register dstH, Register src1, Register src2, 526 SBit s = LeaveCC, Condition cond = al); 527 528 void umlal(Register dstL, Register dstH, Register src1, Register src2, 529 SBit s = LeaveCC, Condition cond = al); 530 531 void umull(Register dstL, Register dstH, Register src1, Register src2, 532 SBit s = LeaveCC, Condition cond = al); 533 534 // Miscellaneous arithmetic instructions 535 536 void clz(Register dst, Register src, Condition cond = al); // v5 and above 537 538 // Saturating instructions. v6 and above. 539 540 // Unsigned saturate. 541 // 542 // Saturate an optionally shifted signed value to an unsigned range. 543 // 544 // usat dst, #satpos, src 545 // usat dst, #satpos, src, lsl #sh 546 // usat dst, #satpos, src, asr #sh 547 // 548 // Register dst will contain: 549 // 550 // 0, if s < 0 551 // (1 << satpos) - 1, if s > ((1 << satpos) - 1) 552 // s, otherwise 553 // 554 // where s is the contents of src after shifting (if used.) 555 void usat(Register dst, int satpos, const Operand& src, Condition cond = al); 556 557 // Bitfield manipulation instructions. v7 and above. 558 559 void ubfx(Register dst, Register src, int lsb, int width, 560 Condition cond = al); 561 562 void sbfx(Register dst, Register src, int lsb, int width, 563 Condition cond = al); 564 565 void bfc(Register dst, int lsb, int width, Condition cond = al); 566 567 void bfi(Register dst, Register src, int lsb, int width, Condition cond = al); 568 569 void pkhbt(Register dst, Register src1, const Operand& src2, 570 Condition cond = al); 571 572 void pkhtb(Register dst, Register src1, const Operand& src2, 573 Condition cond = al); 574 575 void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al); 576 void sxtab(Register dst, Register src1, Register src2, int rotate = 0, 577 Condition cond = al); 578 void sxth(Register dst, Register src, int rotate = 0, Condition cond = al); 579 void sxtah(Register dst, Register src1, Register src2, int rotate = 0, 580 Condition cond = al); 581 582 void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al); 583 void uxtab(Register dst, Register src1, Register src2, int rotate = 0, 584 Condition cond = al); 585 void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al); 586 void uxth(Register dst, Register src, int rotate = 0, Condition cond = al); 587 void uxtah(Register dst, Register src1, Register src2, int rotate = 0, 588 Condition cond = al); 589 590 // Reverse the bits in a register. 591 void rbit(Register dst, Register src, Condition cond = al); 592 void rev(Register dst, Register src, Condition cond = al); 593 594 // Status register access instructions 595 596 void mrs(Register dst, SRegister s, Condition cond = al); 597 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al); 598 599 // Load/Store instructions 600 void ldr(Register dst, const MemOperand& src, Condition cond = al); 601 void str(Register src, const MemOperand& dst, Condition cond = al); 602 void ldrb(Register dst, const MemOperand& src, Condition cond = al); 603 void strb(Register src, const MemOperand& dst, Condition cond = al); 604 void ldrh(Register dst, const MemOperand& src, Condition cond = al); 605 void strh(Register src, const MemOperand& dst, Condition cond = al); 606 void ldrsb(Register dst, const MemOperand& src, Condition cond = al); 607 void ldrsh(Register dst, const MemOperand& src, Condition cond = al); 608 void ldrd(Register dst1, Register dst2, const MemOperand& src, 609 Condition cond = al); 610 void strd(Register src1, Register src2, const MemOperand& dst, 611 Condition cond = al); 612 613 // Load literal from a pc relative address. 614 void ldr_pcrel(Register dst, int imm12, Condition cond = al); 615 616 // Load/Store exclusive instructions 617 void ldrex(Register dst, Register src, Condition cond = al); 618 void strex(Register src1, Register src2, Register dst, Condition cond = al); 619 void ldrexb(Register dst, Register src, Condition cond = al); 620 void strexb(Register src1, Register src2, Register dst, Condition cond = al); 621 void ldrexh(Register dst, Register src, Condition cond = al); 622 void strexh(Register src1, Register src2, Register dst, Condition cond = al); 623 void ldrexd(Register dst1, Register dst2, Register src, Condition cond = al); 624 void strexd(Register res, Register src1, Register src2, Register dst, 625 Condition cond = al); 626 627 // Preload instructions 628 void pld(const MemOperand& address); 629 630 // Load/Store multiple instructions 631 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al); 632 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); 633 634 // Exception-generating instructions and debugging support 635 void stop(Condition cond = al, int32_t code = kDefaultStopCode); 636 637 void bkpt(uint32_t imm16); // v5 and above 638 void svc(uint32_t imm24, Condition cond = al); 639 640 // Synchronization instructions. 641 // On ARMv6, an equivalent CP15 operation will be used. 642 void dmb(BarrierOption option); 643 void dsb(BarrierOption option); 644 void isb(BarrierOption option); 645 646 // Conditional speculation barrier. 647 void csdb(); 648 649 // Coprocessor instructions 650 651 void cdp(Coprocessor coproc, int opcode_1, CRegister crd, CRegister crn, 652 CRegister crm, int opcode_2, Condition cond = al); 653 654 void cdp2(Coprocessor coproc, int opcode_1, CRegister crd, CRegister crn, 655 CRegister crm, 656 int opcode_2); // v5 and above 657 658 void mcr(Coprocessor coproc, int opcode_1, Register rd, CRegister crn, 659 CRegister crm, int opcode_2 = 0, Condition cond = al); 660 661 void mcr2(Coprocessor coproc, int opcode_1, Register rd, CRegister crn, 662 CRegister crm, 663 int opcode_2 = 0); // v5 and above 664 665 void mrc(Coprocessor coproc, int opcode_1, Register rd, CRegister crn, 666 CRegister crm, int opcode_2 = 0, Condition cond = al); 667 668 void mrc2(Coprocessor coproc, int opcode_1, Register rd, CRegister crn, 669 CRegister crm, 670 int opcode_2 = 0); // v5 and above 671 672 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src, 673 LFlag l = Short, Condition cond = al); 674 void ldc(Coprocessor coproc, CRegister crd, Register base, int option, 675 LFlag l = Short, Condition cond = al); 676 677 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, 678 LFlag l = Short); // v5 and above 679 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option, 680 LFlag l = Short); // v5 and above 681 682 // Support for VFP. 683 // All these APIs support S0 to S31 and D0 to D31. 684 685 void vldr(const DwVfpRegister dst, const Register base, int offset, 686 const Condition cond = al); 687 void vldr(const DwVfpRegister dst, const MemOperand& src, 688 const Condition cond = al); 689 690 void vldr(const SwVfpRegister dst, const Register base, int offset, 691 const Condition cond = al); 692 void vldr(const SwVfpRegister dst, const MemOperand& src, 693 const Condition cond = al); 694 695 void vstr(const DwVfpRegister src, const Register base, int offset, 696 const Condition cond = al); 697 void vstr(const DwVfpRegister src, const MemOperand& dst, 698 const Condition cond = al); 699 700 void vstr(const SwVfpRegister src, const Register base, int offset, 701 const Condition cond = al); 702 void vstr(const SwVfpRegister src, const MemOperand& dst, 703 const Condition cond = al); 704 705 void vldm(BlockAddrMode am, Register base, DwVfpRegister first, 706 DwVfpRegister last, Condition cond = al); 707 708 void vstm(BlockAddrMode am, Register base, DwVfpRegister first, 709 DwVfpRegister last, Condition cond = al); 710 711 void vldm(BlockAddrMode am, Register base, SwVfpRegister first, 712 SwVfpRegister last, Condition cond = al); 713 714 void vstm(BlockAddrMode am, Register base, SwVfpRegister first, 715 SwVfpRegister last, Condition cond = al); 716 717 void vmov(const SwVfpRegister dst, Float32 imm); 718 void vmov(const DwVfpRegister dst, base::Double imm, 719 const Register extra_scratch = no_reg); 720 void vmov(const SwVfpRegister dst, const SwVfpRegister src, 721 const Condition cond = al); 722 void vmov(const DwVfpRegister dst, const DwVfpRegister src, 723 const Condition cond = al); 724 void vmov(const DwVfpRegister dst, const Register src1, const Register src2, 725 const Condition cond = al); 726 void vmov(const Register dst1, const Register dst2, const DwVfpRegister src, 727 const Condition cond = al); 728 void vmov(const SwVfpRegister dst, const Register src, 729 const Condition cond = al); 730 void vmov(const Register dst, const SwVfpRegister src, 731 const Condition cond = al); 732 void vcvt_f64_s32(const DwVfpRegister dst, const SwVfpRegister src, 733 VFPConversionMode mode = kDefaultRoundToZero, 734 const Condition cond = al); 735 void vcvt_f32_s32(const SwVfpRegister dst, const SwVfpRegister src, 736 VFPConversionMode mode = kDefaultRoundToZero, 737 const Condition cond = al); 738 void vcvt_f64_u32(const DwVfpRegister dst, const SwVfpRegister src, 739 VFPConversionMode mode = kDefaultRoundToZero, 740 const Condition cond = al); 741 void vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src, 742 VFPConversionMode mode = kDefaultRoundToZero, 743 const Condition cond = al); 744 void vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src, 745 VFPConversionMode mode = kDefaultRoundToZero, 746 const Condition cond = al); 747 void vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src, 748 VFPConversionMode mode = kDefaultRoundToZero, 749 const Condition cond = al); 750 void vcvt_s32_f64(const SwVfpRegister dst, const DwVfpRegister src, 751 VFPConversionMode mode = kDefaultRoundToZero, 752 const Condition cond = al); 753 void vcvt_u32_f64(const SwVfpRegister dst, const DwVfpRegister src, 754 VFPConversionMode mode = kDefaultRoundToZero, 755 const Condition cond = al); 756 void vcvt_f64_f32(const DwVfpRegister dst, const SwVfpRegister src, 757 VFPConversionMode mode = kDefaultRoundToZero, 758 const Condition cond = al); 759 void vcvt_f32_f64(const SwVfpRegister dst, const DwVfpRegister src, 760 VFPConversionMode mode = kDefaultRoundToZero, 761 const Condition cond = al); 762 void vcvt_f64_s32(const DwVfpRegister dst, int fraction_bits, 763 const Condition cond = al); 764 765 void vmrs(const Register dst, const Condition cond = al); 766 void vmsr(const Register dst, const Condition cond = al); 767 768 void vneg(const DwVfpRegister dst, const DwVfpRegister src, 769 const Condition cond = al); 770 void vneg(const SwVfpRegister dst, const SwVfpRegister src, 771 const Condition cond = al); 772 void vabs(const DwVfpRegister dst, const DwVfpRegister src, 773 const Condition cond = al); 774 void vabs(const SwVfpRegister dst, const SwVfpRegister src, 775 const Condition cond = al); 776 void vadd(const DwVfpRegister dst, const DwVfpRegister src1, 777 const DwVfpRegister src2, const Condition cond = al); 778 void vadd(const SwVfpRegister dst, const SwVfpRegister src1, 779 const SwVfpRegister src2, const Condition cond = al); 780 void vsub(const DwVfpRegister dst, const DwVfpRegister src1, 781 const DwVfpRegister src2, const Condition cond = al); 782 void vsub(const SwVfpRegister dst, const SwVfpRegister src1, 783 const SwVfpRegister src2, const Condition cond = al); 784 void vmul(const DwVfpRegister dst, const DwVfpRegister src1, 785 const DwVfpRegister src2, const Condition cond = al); 786 void vmul(const SwVfpRegister dst, const SwVfpRegister src1, 787 const SwVfpRegister src2, const Condition cond = al); 788 void vmla(const DwVfpRegister dst, const DwVfpRegister src1, 789 const DwVfpRegister src2, const Condition cond = al); 790 void vmla(const SwVfpRegister dst, const SwVfpRegister src1, 791 const SwVfpRegister src2, const Condition cond = al); 792 void vmls(const DwVfpRegister dst, const DwVfpRegister src1, 793 const DwVfpRegister src2, const Condition cond = al); 794 void vmls(const SwVfpRegister dst, const SwVfpRegister src1, 795 const SwVfpRegister src2, const Condition cond = al); 796 void vdiv(const DwVfpRegister dst, const DwVfpRegister src1, 797 const DwVfpRegister src2, const Condition cond = al); 798 void vdiv(const SwVfpRegister dst, const SwVfpRegister src1, 799 const SwVfpRegister src2, const Condition cond = al); 800 void vcmp(const DwVfpRegister src1, const DwVfpRegister src2, 801 const Condition cond = al); 802 void vcmp(const SwVfpRegister src1, const SwVfpRegister src2, 803 const Condition cond = al); 804 void vcmp(const DwVfpRegister src1, const double src2, 805 const Condition cond = al); 806 void vcmp(const SwVfpRegister src1, const float src2, 807 const Condition cond = al); 808 809 void vmaxnm(const DwVfpRegister dst, const DwVfpRegister src1, 810 const DwVfpRegister src2); 811 void vmaxnm(const SwVfpRegister dst, const SwVfpRegister src1, 812 const SwVfpRegister src2); 813 void vminnm(const DwVfpRegister dst, const DwVfpRegister src1, 814 const DwVfpRegister src2); 815 void vminnm(const SwVfpRegister dst, const SwVfpRegister src1, 816 const SwVfpRegister src2); 817 818 // VSEL supports cond in {eq, ne, ge, lt, gt, le, vs, vc}. 819 void vsel(const Condition cond, const DwVfpRegister dst, 820 const DwVfpRegister src1, const DwVfpRegister src2); 821 void vsel(const Condition cond, const SwVfpRegister dst, 822 const SwVfpRegister src1, const SwVfpRegister src2); 823 824 void vsqrt(const DwVfpRegister dst, const DwVfpRegister src, 825 const Condition cond = al); 826 void vsqrt(const SwVfpRegister dst, const SwVfpRegister src, 827 const Condition cond = al); 828 829 // ARMv8 rounding instructions (Scalar). 830 void vrinta(const SwVfpRegister dst, const SwVfpRegister src); 831 void vrinta(const DwVfpRegister dst, const DwVfpRegister src); 832 void vrintn(const SwVfpRegister dst, const SwVfpRegister src); 833 void vrintn(const DwVfpRegister dst, const DwVfpRegister src); 834 void vrintm(const SwVfpRegister dst, const SwVfpRegister src); 835 void vrintm(const DwVfpRegister dst, const DwVfpRegister src); 836 void vrintp(const SwVfpRegister dst, const SwVfpRegister src); 837 void vrintp(const DwVfpRegister dst, const DwVfpRegister src); 838 void vrintz(const SwVfpRegister dst, const SwVfpRegister src, 839 const Condition cond = al); 840 void vrintz(const DwVfpRegister dst, const DwVfpRegister src, 841 const Condition cond = al); 842 843 // Support for NEON. 844 845 // All these APIs support D0 to D31 and Q0 to Q15. 846 void vld1(NeonSize size, const NeonListOperand& dst, 847 const NeonMemOperand& src); 848 // vld1s(ingle element to one lane). 849 void vld1s(NeonSize size, const NeonListOperand& dst, uint8_t index, 850 const NeonMemOperand& src); 851 void vld1r(NeonSize size, const NeonListOperand& dst, 852 const NeonMemOperand& src); 853 void vst1(NeonSize size, const NeonListOperand& src, 854 const NeonMemOperand& dst); 855 // vst1s(single element from one lane). 856 void vst1s(NeonSize size, const NeonListOperand& src, uint8_t index, 857 const NeonMemOperand& dst); 858 // dt represents the narrower type 859 void vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src); 860 // dst_dt represents the narrower type, src_dt represents the src type. 861 void vqmovn(NeonDataType dst_dt, NeonDataType src_dt, DwVfpRegister dst, 862 QwNeonRegister src); 863 864 // Only unconditional core <-> scalar moves are currently supported. 865 void vmov(NeonDataType dt, DwVfpRegister dst, int index, Register src); 866 void vmov(NeonDataType dt, Register dst, DwVfpRegister src, int index); 867 868 void vmov(DwVfpRegister dst, uint64_t imm); 869 void vmov(QwNeonRegister dst, uint64_t imm); 870 void vmov(QwNeonRegister dst, QwNeonRegister src); 871 void vdup(NeonSize size, QwNeonRegister dst, Register src); 872 void vdup(NeonSize size, QwNeonRegister dst, DwVfpRegister src, int index); 873 void vdup(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int index); 874 875 void vcvt_f32_s32(QwNeonRegister dst, QwNeonRegister src); 876 void vcvt_f32_u32(QwNeonRegister dst, QwNeonRegister src); 877 void vcvt_s32_f32(QwNeonRegister dst, QwNeonRegister src); 878 void vcvt_u32_f32(QwNeonRegister dst, QwNeonRegister src); 879 880 void vmvn(QwNeonRegister dst, QwNeonRegister src); 881 void vswp(DwVfpRegister dst, DwVfpRegister src); 882 void vswp(QwNeonRegister dst, QwNeonRegister src); 883 void vabs(QwNeonRegister dst, QwNeonRegister src); 884 void vabs(NeonSize size, QwNeonRegister dst, QwNeonRegister src); 885 void vneg(QwNeonRegister dst, QwNeonRegister src); 886 void vneg(NeonSize size, QwNeonRegister dst, QwNeonRegister src); 887 888 void vand(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 889 void vbic(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 890 void veor(DwVfpRegister dst, DwVfpRegister src1, DwVfpRegister src2); 891 void veor(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 892 void vbsl(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 893 void vorr(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 894 void vorn(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 895 void vadd(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 896 void vadd(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 897 QwNeonRegister src2); 898 void vqadd(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 899 QwNeonRegister src2); 900 void vsub(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 901 void vsub(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 902 QwNeonRegister src2); 903 void vqsub(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 904 QwNeonRegister src2); 905 void vmlal(NeonDataType size, QwNeonRegister dst, DwVfpRegister src1, 906 DwVfpRegister src2); 907 void vmul(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 908 void vmul(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 909 QwNeonRegister src2); 910 void vmull(NeonDataType size, QwNeonRegister dst, DwVfpRegister src1, 911 DwVfpRegister src2); 912 void vmin(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 913 void vmin(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 914 QwNeonRegister src2); 915 void vmax(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 916 void vmax(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 917 QwNeonRegister src2); 918 void vpadd(DwVfpRegister dst, DwVfpRegister src1, DwVfpRegister src2); 919 void vpadd(NeonSize size, DwVfpRegister dst, DwVfpRegister src1, 920 DwVfpRegister src2); 921 void vpmin(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1, 922 DwVfpRegister src2); 923 void vpmax(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1, 924 DwVfpRegister src2); 925 926 void vpadal(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src); 927 void vpaddl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src); 928 void vqrdmulh(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 929 QwNeonRegister src2); 930 931 // ARMv8 rounding instructions (NEON). 932 void vrintm(NeonDataType dt, const QwNeonRegister dst, 933 const QwNeonRegister src); 934 void vrintn(NeonDataType dt, const QwNeonRegister dst, 935 const QwNeonRegister src); 936 void vrintp(NeonDataType dt, const QwNeonRegister dst, 937 const QwNeonRegister src); 938 void vrintz(NeonDataType dt, const QwNeonRegister dst, 939 const QwNeonRegister src); 940 941 void vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift); 942 void vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, 943 QwNeonRegister shift); 944 void vshr(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src, int shift); 945 void vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift); 946 void vsli(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift); 947 void vsri(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift); 948 void vsra(NeonDataType size, DwVfpRegister dst, DwVfpRegister src, int imm); 949 950 // vrecpe and vrsqrte only support floating point lanes. 951 void vrecpe(QwNeonRegister dst, QwNeonRegister src); 952 void vrsqrte(QwNeonRegister dst, QwNeonRegister src); 953 void vrecps(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 954 void vrsqrts(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 955 void vtst(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 956 QwNeonRegister src2); 957 void vceq(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 958 void vceq(NeonSize size, QwNeonRegister dst, QwNeonRegister src1, 959 QwNeonRegister src2); 960 void vceq(NeonSize size, QwNeonRegister dst, QwNeonRegister src, int value); 961 void vcge(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 962 void vcge(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 963 QwNeonRegister src2); 964 void vcgt(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 965 void vcgt(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 966 QwNeonRegister src2); 967 void vclt(NeonSize size, QwNeonRegister dst, QwNeonRegister src, int value); 968 void vrhadd(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1, 969 QwNeonRegister src2); 970 void vext(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2, 971 int bytes); 972 void vzip(NeonSize size, DwVfpRegister src1, DwVfpRegister src2); 973 void vzip(NeonSize size, QwNeonRegister src1, QwNeonRegister src2); 974 void vuzp(NeonSize size, DwVfpRegister src1, DwVfpRegister src2); 975 void vuzp(NeonSize size, QwNeonRegister src1, QwNeonRegister src2); 976 void vrev16(NeonSize size, QwNeonRegister dst, QwNeonRegister src); 977 void vrev32(NeonSize size, QwNeonRegister dst, QwNeonRegister src); 978 void vrev64(NeonSize size, QwNeonRegister dst, QwNeonRegister src); 979 void vtrn(NeonSize size, DwVfpRegister src1, DwVfpRegister src2); 980 void vtrn(NeonSize size, QwNeonRegister src1, QwNeonRegister src2); 981 void vtbl(DwVfpRegister dst, const NeonListOperand& list, 982 DwVfpRegister index); 983 void vtbx(DwVfpRegister dst, const NeonListOperand& list, 984 DwVfpRegister index); 985 986 void vcnt(QwNeonRegister dst, QwNeonRegister src); 987 988 // Pseudo instructions 989 990 // Different nop operations are used by the code generator to detect certain 991 // states of the generated code. 992 enum NopMarkerTypes { 993 NON_MARKING_NOP = 0, 994 DEBUG_BREAK_NOP, 995 // IC markers. 996 PROPERTY_ACCESS_INLINED, 997 PROPERTY_ACCESS_INLINED_CONTEXT, 998 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, 999 // Helper values. 1000 LAST_CODE_MARKER, 1001 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED 1002 }; 1003 1004 void nop(int type = 0); // 0 is the default non-marking type. 1005 push(Register src, Condition cond = al)1006 void push(Register src, Condition cond = al) { 1007 str(src, MemOperand(sp, 4, NegPreIndex), cond); 1008 } 1009 pop(Register dst, Condition cond = al)1010 void pop(Register dst, Condition cond = al) { 1011 ldr(dst, MemOperand(sp, 4, PostIndex), cond); 1012 } 1013 1014 void pop(); 1015 vpush(QwNeonRegister src, Condition cond = al)1016 void vpush(QwNeonRegister src, Condition cond = al) { 1017 vstm(db_w, sp, src.low(), src.high(), cond); 1018 } 1019 vpush(DwVfpRegister src, Condition cond = al)1020 void vpush(DwVfpRegister src, Condition cond = al) { 1021 vstm(db_w, sp, src, src, cond); 1022 } 1023 vpush(SwVfpRegister src, Condition cond = al)1024 void vpush(SwVfpRegister src, Condition cond = al) { 1025 vstm(db_w, sp, src, src, cond); 1026 } 1027 vpop(DwVfpRegister dst, Condition cond = al)1028 void vpop(DwVfpRegister dst, Condition cond = al) { 1029 vldm(ia_w, sp, dst, dst, cond); 1030 } 1031 1032 // Jump unconditionally to given label. jmp(Label* L)1033 void jmp(Label* L) { b(L, al); } 1034 1035 // Check the code size generated from label to here. SizeOfCodeGeneratedSince(Label* label)1036 int SizeOfCodeGeneratedSince(Label* label) { 1037 return pc_offset() - label->pos(); 1038 } 1039 1040 // Check the number of instructions generated from label to here. InstructionsGeneratedSince(Label* label)1041 int InstructionsGeneratedSince(Label* label) { 1042 return SizeOfCodeGeneratedSince(label) / kInstrSize; 1043 } 1044 1045 // Check whether an immediate fits an addressing mode 1 instruction. 1046 static bool ImmediateFitsAddrMode1Instruction(int32_t imm32); 1047 1048 // Check whether an immediate fits an addressing mode 2 instruction. 1049 bool ImmediateFitsAddrMode2Instruction(int32_t imm32); 1050 1051 // Class for scoping postponing the constant pool generation. 1052 class V8_NODISCARD BlockConstPoolScope { 1053 public: BlockConstPoolScope(Assembler* assem)1054 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) { 1055 assem_->StartBlockConstPool(); 1056 } ~BlockConstPoolScope()1057 ~BlockConstPoolScope() { assem_->EndBlockConstPool(); } 1058 1059 private: 1060 Assembler* const assem_; 1061 1062 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope); 1063 }; 1064 1065 // Unused on this architecture. MaybeEmitOutOfLineConstantPool()1066 void MaybeEmitOutOfLineConstantPool() {} 1067 1068 // Record a deoptimization reason that can be used by a log or cpu profiler. 1069 // Use --trace-deopt to enable. 1070 void RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id, 1071 SourcePosition position, int id); 1072 1073 // Record the emission of a constant pool. 1074 // 1075 // The emission of constant pool depends on the size of the code generated and 1076 // the number of RelocInfo recorded. 1077 // The Debug mechanism needs to map code offsets between two versions of a 1078 // function, compiled with and without debugger support (see for example 1079 // Debug::PrepareForBreakPoints()). 1080 // Compiling functions with debugger support generates additional code 1081 // (DebugCodegen::GenerateSlot()). This may affect the emission of the 1082 // constant pools and cause the version of the code with debugger support to 1083 // have constant pools generated in different places. 1084 // Recording the position and size of emitted constant pools allows to 1085 // correctly compute the offset mappings between the different versions of a 1086 // function in all situations. 1087 // 1088 // The parameter indicates the size of the constant pool (in bytes), including 1089 // the marker and branch over the data. 1090 void RecordConstPool(int size); 1091 1092 // Writes a single byte or word of data in the code stream. Used 1093 // for inline tables, e.g., jump-tables. CheckConstantPool() should be 1094 // called before any use of db/dd/dq/dp to ensure that constant pools 1095 // are not emitted as part of the tables generated. 1096 void db(uint8_t data); 1097 void dd(uint32_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO); 1098 void dq(uint64_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO); dp(uintptr_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO)1099 void dp(uintptr_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO) { 1100 dd(data, rmode); 1101 } 1102 1103 // Read/patch instructions instr_at(int pos)1104 Instr instr_at(int pos) { 1105 return *reinterpret_cast<Instr*>(buffer_start_ + pos); 1106 } instr_at_put(int pos, Instr instr)1107 void instr_at_put(int pos, Instr instr) { 1108 *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr; 1109 } instr_at(Address pc)1110 static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); } instr_at_put(Address pc, Instr instr)1111 static void instr_at_put(Address pc, Instr instr) { 1112 *reinterpret_cast<Instr*>(pc) = instr; 1113 } 1114 static Condition GetCondition(Instr instr); 1115 static bool IsLdrRegisterImmediate(Instr instr); 1116 static bool IsVldrDRegisterImmediate(Instr instr); 1117 static int GetLdrRegisterImmediateOffset(Instr instr); 1118 static int GetVldrDRegisterImmediateOffset(Instr instr); 1119 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset); 1120 static Instr SetVldrDRegisterImmediateOffset(Instr instr, int offset); 1121 static bool IsStrRegisterImmediate(Instr instr); 1122 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset); 1123 static bool IsAddRegisterImmediate(Instr instr); 1124 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset); 1125 static Register GetRd(Instr instr); 1126 static Register GetRn(Instr instr); 1127 static Register GetRm(Instr instr); 1128 static bool IsPush(Instr instr); 1129 static bool IsPop(Instr instr); 1130 static bool IsStrRegFpOffset(Instr instr); 1131 static bool IsLdrRegFpOffset(Instr instr); 1132 static bool IsStrRegFpNegOffset(Instr instr); 1133 static bool IsLdrRegFpNegOffset(Instr instr); 1134 static bool IsLdrPcImmediateOffset(Instr instr); 1135 static bool IsBOrBlPcImmediateOffset(Instr instr); 1136 static bool IsVldrDPcImmediateOffset(Instr instr); 1137 static bool IsBlxReg(Instr instr); 1138 static bool IsBlxIp(Instr instr); 1139 static bool IsTstImmediate(Instr instr); 1140 static bool IsCmpRegister(Instr instr); 1141 static bool IsCmpImmediate(Instr instr); 1142 static Register GetCmpImmediateRegister(Instr instr); 1143 static int GetCmpImmediateRawImmediate(Instr instr); 1144 static bool IsNop(Instr instr, int type = NON_MARKING_NOP); 1145 static bool IsMovImmed(Instr instr); 1146 static bool IsOrrImmed(Instr instr); 1147 static bool IsMovT(Instr instr); 1148 static Instr GetMovTPattern(); 1149 static bool IsMovW(Instr instr); 1150 static Instr GetMovWPattern(); 1151 static Instr EncodeMovwImmediate(uint32_t immediate); 1152 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate); 1153 static int DecodeShiftImm(Instr instr); 1154 static Instr PatchShiftImm(Instr instr, int immed); 1155 1156 // Constants are accessed via pc relative addressing, which can reach −4095 to 1157 // 4095 for integer PC-relative loads, and −1020 to 1020 for floating-point 1158 // PC-relative loads, thereby defining a maximum distance between the 1159 // instruction and the accessed constant. Additionally, PC-relative loads 1160 // start at a delta from the actual load instruction's PC, so we can add this 1161 // on to the (positive) distance. 1162 static constexpr int kMaxDistToPcRelativeConstant = 1163 4095 + Instruction::kPcLoadDelta; 1164 // The constant pool needs to be jumped over, and has a marker, so the actual 1165 // distance from the instruction and start of the constant pool has to include 1166 // space for these two instructions. 1167 static constexpr int kMaxDistToIntPool = 1168 kMaxDistToPcRelativeConstant - 2 * kInstrSize; 1169 // Experimentally derived as sufficient for ~95% of compiles. 1170 static constexpr int kTypicalNumPending32Constants = 32; 1171 // The maximum number of pending constants is reached by a sequence of only 1172 // constant loads, which limits it to the number of constant loads that can 1173 // fit between the first constant load and the distance to the constant pool. 1174 static constexpr int kMaxNumPending32Constants = 1175 kMaxDistToIntPool / kInstrSize; 1176 1177 // Postpone the generation of the constant pool for the specified number of 1178 // instructions. 1179 void BlockConstPoolFor(int instructions); 1180 1181 // Check if is time to emit a constant pool. 1182 void CheckConstPool(bool force_emit, bool require_jump); 1183 MaybeCheckConstPool()1184 V8_INLINE void MaybeCheckConstPool() { 1185 if (V8_UNLIKELY(pc_offset() >= constant_pool_deadline_)) { 1186 CheckConstPool(false, true); 1187 } 1188 } 1189 1190 // Move a 32-bit immediate into a register, potentially via the constant pool. 1191 void Move32BitImmediate(Register rd, const Operand& x, Condition cond = al); 1192 1193 // Get the code target object for a pc-relative call or jump. 1194 V8_INLINE Handle<Code> relative_code_target_object_handle_at( 1195 Address pc_) const; 1196 1197 protected: buffer_space() const1198 int buffer_space() const { return reloc_info_writer.pos() - pc_; } 1199 1200 // Decode branch instruction at pos and return branch target pos 1201 int target_at(int pos); 1202 1203 // Patch branch instruction at pos to branch to given branch target pos 1204 void target_at_put(int pos, int target_pos); 1205 1206 // Prevent contant pool emission until EndBlockConstPool is called. 1207 // Calls to this function can be nested but must be followed by an equal 1208 // number of call to EndBlockConstpool. StartBlockConstPool()1209 void StartBlockConstPool() { 1210 if (const_pool_blocked_nesting_++ == 0) { 1211 // Prevent constant pool checks happening by resetting the deadline. 1212 constant_pool_deadline_ = kMaxInt; 1213 } 1214 } 1215 1216 // Resume constant pool emission. Needs to be called as many times as 1217 // StartBlockConstPool to have an effect. EndBlockConstPool()1218 void EndBlockConstPool() { 1219 if (--const_pool_blocked_nesting_ == 0) { 1220 if (first_const_pool_32_use_ >= 0) { 1221 #ifdef DEBUG 1222 // Check the constant pool hasn't been blocked for too long. 1223 DCHECK_LE(pc_offset(), first_const_pool_32_use_ + kMaxDistToIntPool); 1224 #endif 1225 // Reset the constant pool check back to the deadline. 1226 constant_pool_deadline_ = first_const_pool_32_use_ + kCheckPoolDeadline; 1227 } 1228 } 1229 } 1230 is_const_pool_blocked() const1231 bool is_const_pool_blocked() const { 1232 return (const_pool_blocked_nesting_ > 0) || 1233 (pc_offset() < no_const_pool_before_); 1234 } 1235 has_pending_constants() const1236 bool has_pending_constants() const { 1237 bool result = !pending_32_bit_constants_.empty(); 1238 DCHECK_EQ(result, first_const_pool_32_use_ != -1); 1239 return result; 1240 } 1241 VfpRegisterIsAvailable(DwVfpRegister reg)1242 bool VfpRegisterIsAvailable(DwVfpRegister reg) { 1243 DCHECK(reg.is_valid()); 1244 return IsEnabled(VFP32DREGS) || 1245 (reg.code() < LowDwVfpRegister::kNumRegisters); 1246 } 1247 VfpRegisterIsAvailable(QwNeonRegister reg)1248 bool VfpRegisterIsAvailable(QwNeonRegister reg) { 1249 DCHECK(reg.is_valid()); 1250 return IsEnabled(VFP32DREGS) || 1251 (reg.code() < LowDwVfpRegister::kNumRegisters / 2); 1252 } 1253 1254 inline void emit(Instr x); 1255 1256 // Code generation 1257 // The relocation writer's position is at least kGap bytes below the end of 1258 // the generated instructions. This is so that multi-instruction sequences do 1259 // not have to check for overflow. The same is true for writes of large 1260 // relocation info entries. 1261 static constexpr int kGap = 32; 1262 STATIC_ASSERT(AssemblerBase::kMinimalBufferSize >= 2 * kGap); 1263 1264 // Relocation info generation 1265 // Each relocation is encoded as a variable size value 1266 static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize; 1267 RelocInfoWriter reloc_info_writer; 1268 1269 // ConstantPoolEntry records are used during code generation as temporary 1270 // containers for constants and code target addresses until they are emitted 1271 // to the constant pool. These records are temporarily stored in a separate 1272 // buffer until a constant pool is emitted. 1273 // If every instruction in a long sequence is accessing the pool, we need one 1274 // pending relocation entry per instruction. 1275 1276 // The buffers of pending constant pool entries. 1277 base::SmallVector<ConstantPoolEntry, kTypicalNumPending32Constants> 1278 pending_32_bit_constants_; 1279 1280 // Scratch registers available for use by the Assembler. 1281 RegList scratch_register_list_; 1282 VfpRegList scratch_vfp_register_list_; 1283 1284 private: 1285 // Avoid overflows for displacements etc. 1286 static const int kMaximalBufferSize = 512 * MB; 1287 1288 // Constant pool generation 1289 // Pools are emitted in the instruction stream, preferably after unconditional 1290 // jumps or after returns from functions (in dead code locations). 1291 // If a long code sequence does not contain unconditional jumps, it is 1292 // necessary to emit the constant pool before the pool gets too far from the 1293 // location it is accessed from. In this case, we emit a jump over the emitted 1294 // constant pool. 1295 // Constants in the pool may be addresses of functions that gets relocated; 1296 // if so, a relocation info entry is associated to the constant pool entry. 1297 1298 // Repeated checking whether the constant pool should be emitted is rather 1299 // expensive. Instead, we check once a deadline is hit; the deadline being 1300 // when there is a possibility that MaybeCheckConstPool won't be called before 1301 // kMaxDistToIntPoolWithHeader is exceeded. Since MaybeCheckConstPool is 1302 // called in CheckBuffer, this means that kGap is an upper bound on this 1303 // check. Use 2 * kGap just to give it some slack around BlockConstPoolScopes. 1304 static constexpr int kCheckPoolDeadline = kMaxDistToIntPool - 2 * kGap; 1305 1306 // pc offset of the upcoming constant pool deadline. Equivalent to 1307 // first_const_pool_32_use_ + kCheckPoolDeadline. 1308 int constant_pool_deadline_; 1309 1310 // Emission of the constant pool may be blocked in some code sequences. 1311 int const_pool_blocked_nesting_; // Block emission if this is not zero. 1312 int no_const_pool_before_; // Block emission before this pc offset. 1313 1314 // Keep track of the first instruction requiring a constant pool entry 1315 // since the previous constant pool was emitted. 1316 int first_const_pool_32_use_; 1317 1318 // The bound position, before this we cannot do instruction elimination. 1319 int last_bound_pos_; 1320 1321 V8_INLINE void CheckBuffer(); 1322 void GrowBuffer(); 1323 1324 // Instruction generation 1325 void AddrMode1(Instr instr, Register rd, Register rn, const Operand& x); 1326 // Attempt to encode operand |x| for instruction |instr| and return true on 1327 // success. The result will be encoded in |instr| directly. This method may 1328 // change the opcode if deemed beneficial, for instance, MOV may be turned 1329 // into MVN, ADD into SUB, AND into BIC, ...etc. The only reason this method 1330 // may fail is that the operand is an immediate that cannot be encoded. 1331 bool AddrMode1TryEncodeOperand(Instr* instr, const Operand& x); 1332 1333 void AddrMode2(Instr instr, Register rd, const MemOperand& x); 1334 void AddrMode3(Instr instr, Register rd, const MemOperand& x); 1335 void AddrMode4(Instr instr, Register rn, RegList rl); 1336 void AddrMode5(Instr instr, CRegister crd, const MemOperand& x); 1337 1338 // Labels 1339 void print(const Label* L); 1340 void bind_to(Label* L, int pos); 1341 void next(Label* L); 1342 1343 // Record reloc info for current pc_ 1344 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 1345 void ConstantPoolAddEntry(int position, RelocInfo::Mode rmode, 1346 intptr_t value); 1347 void AllocateAndInstallRequestedHeapObjects(Isolate* isolate); 1348 1349 int WriteCodeComments(); 1350 1351 friend class RelocInfo; 1352 friend class BlockConstPoolScope; 1353 friend class EnsureSpace; 1354 friend class UseScratchRegisterScope; 1355 }; 1356 1357 class EnsureSpace { 1358 public: 1359 V8_INLINE explicit EnsureSpace(Assembler* assembler); 1360 }; 1361 1362 class PatchingAssembler : public Assembler { 1363 public: 1364 PatchingAssembler(const AssemblerOptions& options, byte* address, 1365 int instructions); 1366 ~PatchingAssembler(); 1367 1368 void Emit(Address addr); 1369 void PadWithNops(); 1370 }; 1371 1372 // This scope utility allows scratch registers to be managed safely. The 1373 // Assembler's GetScratchRegisterList() is used as a pool of scratch 1374 // registers. These registers can be allocated on demand, and will be returned 1375 // at the end of the scope. 1376 // 1377 // When the scope ends, the Assembler's list will be restored to its original 1378 // state, even if the list is modified by some other means. Note that this scope 1379 // can be nested but the destructors need to run in the opposite order as the 1380 // constructors. We do not have assertions for this. 1381 class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope { 1382 public: 1383 explicit UseScratchRegisterScope(Assembler* assembler); 1384 ~UseScratchRegisterScope(); 1385 1386 // Take a register from the list and return it. 1387 Register Acquire(); AcquireS()1388 SwVfpRegister AcquireS() { return AcquireVfp<SwVfpRegister>(); } AcquireLowD()1389 LowDwVfpRegister AcquireLowD() { return AcquireVfp<LowDwVfpRegister>(); } AcquireD()1390 DwVfpRegister AcquireD() { 1391 DwVfpRegister reg = AcquireVfp<DwVfpRegister>(); 1392 DCHECK(assembler_->VfpRegisterIsAvailable(reg)); 1393 return reg; 1394 } AcquireQ()1395 QwNeonRegister AcquireQ() { 1396 QwNeonRegister reg = AcquireVfp<QwNeonRegister>(); 1397 DCHECK(assembler_->VfpRegisterIsAvailable(reg)); 1398 return reg; 1399 } 1400 1401 // Check if we have registers available to acquire. CanAcquire() const1402 bool CanAcquire() const { 1403 return !assembler_->GetScratchRegisterList()->is_empty(); 1404 } CanAcquireD() const1405 bool CanAcquireD() const { return CanAcquireVfp<DwVfpRegister>(); } 1406 Include(const Register& reg1, const Register& reg2 = no_reg)1407 void Include(const Register& reg1, const Register& reg2 = no_reg) { 1408 RegList* available = assembler_->GetScratchRegisterList(); 1409 DCHECK_NOT_NULL(available); 1410 DCHECK(!available->has(reg1)); 1411 DCHECK(!available->has(reg2)); 1412 available->set(reg1); 1413 available->set(reg2); 1414 } Exclude(const Register& reg1, const Register& reg2 = no_reg)1415 void Exclude(const Register& reg1, const Register& reg2 = no_reg) { 1416 RegList* available = assembler_->GetScratchRegisterList(); 1417 DCHECK_NOT_NULL(available); 1418 DCHECK(available->has(reg1)); 1419 DCHECK_IMPLIES(reg2.is_valid(), available->has(reg2)); 1420 available->clear(RegList{reg1, reg2}); 1421 } 1422 1423 private: 1424 friend class Assembler; 1425 friend class TurboAssembler; 1426 1427 template <typename T> 1428 bool CanAcquireVfp() const; 1429 1430 template <typename T> 1431 T AcquireVfp(); 1432 1433 Assembler* assembler_; 1434 // Available scratch registers at the start of this scope. 1435 RegList old_available_; 1436 VfpRegList old_available_vfp_; 1437 }; 1438 1439 // Helper struct for load lane and store lane to indicate which opcode to use 1440 // and what memory size to be encoded in the opcode, and the new lane index. 1441 class LoadStoreLaneParams { 1442 public: 1443 bool low_op; 1444 NeonSize sz; 1445 uint8_t laneidx; 1446 // The register mapping on ARM (1 Q to 2 D), means that loading/storing high 1447 // lanes of a Q register is equivalent to loading/storing the high D reg, 1448 // modulo number of lanes in a D reg. This constructor decides, based on the 1449 // laneidx and load/store size, whether the low or high D reg is accessed, and 1450 // what the new lane index is. 1451 LoadStoreLaneParams(MachineRepresentation rep, uint8_t laneidx); 1452 1453 private: LoadStoreLaneParams(uint8_t laneidx, NeonSize sz, int lanes)1454 LoadStoreLaneParams(uint8_t laneidx, NeonSize sz, int lanes) 1455 : low_op(laneidx < lanes), sz(sz), laneidx(laneidx % lanes) {} 1456 }; 1457 1458 } // namespace internal 1459 } // namespace v8 1460 1461 #endif // V8_CODEGEN_ARM_ASSEMBLER_ARM_H_ 1462