1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. 4 * Copyright (c) 2015, Linaro Ltd. All rights reserved. 5 * Copyright (c) 2015-2018, Azul Systems, Inc. All rights reserved. 6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7 * 8 * This code is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License version 2 only, as 10 * published by the Free Software Foundation. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 * 26 */ 27 28 #ifndef CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP 29 #define CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP 30 31 #include "asm/register.hpp" 32 #include "vm_version_aarch32.hpp" 33 34 // Definitions of various symbolic names for machine registers 35 36 // Here we define how many integer and double precision floating point 37 // registers are used for passing parameters by the C and Java calling 38 // conventions. Each double precision floating point register can be used 39 // as two single precision registers. 40 41 class Argument { 42 public: 43 enum { 44 n_int_register_parameters_c = 4, // c_rarg0, c_rarg1, c_rarg2, c_rarg3 45 #ifdef HARD_FLOAT_CC 46 n_float_register_parameters_c = 8, // c_farg0, c_farg1, ..., c_farg7 47 #else // HARD_FLOAT_CC 48 n_float_register_parameters_c = 0, // 0 registers used to pass arguments 49 #endif // HARD_FLOAT_CC 50 n_int_register_parameters_j = 4, // j_rarg0, j_rarg1, j_rarg2, j_rarg3 51 #ifdef HARD_FLOAT_CC 52 n_float_register_parameters_j = 8 // j_farg0, j_farg1, ..., j_farg7 53 #else // HARD_FLOAT_CC 54 n_float_register_parameters_j = 0 // 0 registers used to pass arguments 55 #endif // HARD_FLOAT_CC 56 }; 57 }; 58 59 // Symbolic names for the register arguments used by the C calling convention 60 // (the calling convention for C runtime calls and calls to JNI native 61 // methods) 62 63 REGISTER_DECLARATION(Register, c_rarg0, r0); 64 REGISTER_DECLARATION(Register, c_rarg1, r1); 65 REGISTER_DECLARATION(Register, c_rarg2, r2); 66 REGISTER_DECLARATION(Register, c_rarg3, r3); 67 68 // Symbolic names for the register arguments used by the Java calling 69 // convention (the calling convention for calls to compiled Java methods) 70 71 // In contrary to most ports we don't shift java argument registers by 1. Although 72 // it helps to avoid extra argument copy when invoking JNI methods it brings a 73 // lot more complexity into C2 port and prevents from using ldrd/strd instructions 74 // when dealing with jlong values. 75 // 76 // |-----------------------------------| 77 // | c_rarg0 c_rarg1 c_rarg2 c_rarg3 | 78 // |-----------------------------------| 79 // | r0 r1 r2 r3 | 80 // |-----------------------------------| 81 // | j_rarg0 j_rarg1 j_rarg2 j_rarg3 | 82 // |-----------------------------------| 83 84 REGISTER_DECLARATION(Register, j_rarg0, c_rarg0); 85 REGISTER_DECLARATION(Register, j_rarg1, c_rarg1); 86 REGISTER_DECLARATION(Register, j_rarg2, c_rarg2); 87 REGISTER_DECLARATION(Register, j_rarg3, c_rarg3); 88 89 // Common register aliases used in assembler code 90 91 // These registers are used to hold VM data either temporarily within a method 92 // or across method calls. According to AAPCS, r0-r3 and r12 are caller-saved, 93 // the rest are callee-saved. 94 95 // These 4 aliases are used in the template interpreter only. 96 97 REGISTER_DECLARATION(Register, rdispatch, r4); // Address of dispatch table 98 REGISTER_DECLARATION(Register, rbcp, r5); // Bytecode pointer 99 REGISTER_DECLARATION(Register, rlocals, r6); // Address of local variables section of current frame 100 REGISTER_DECLARATION(Register, rcpool, r7); // Address of constant pool cache 101 102 // The following aliases are used in all VM components. 103 104 REGISTER_DECLARATION(Register, rmethod, r8); // Address of current method 105 REGISTER_DECLARATION(Register, rscratch1, r9); // Scratch register 106 REGISTER_DECLARATION(Register, rthread, r10); // Address of current thread 107 REGISTER_DECLARATION(Register, rfp, r11); // Frame pointer 108 REGISTER_DECLARATION(Register, rscratch2, r12); // Scratch register 109 REGISTER_DECLARATION(Register, sp, r13); // Stack pointer 110 REGISTER_DECLARATION(Register, lr, r14); // Link register 111 REGISTER_DECLARATION(Register, r15_pc, r15); // Program counter 112 113 114 extern "C" void entry(CodeBuffer *cb); 115 116 117 #define assert_cond(ARG1) assert(ARG1, #ARG1) 118 119 class Assembler; 120 121 class Instruction_aarch32 { 122 unsigned insn; 123 #ifdef ASSERT 124 unsigned bits; 125 #endif 126 Assembler *assem; 127 128 public: 129 130 Instruction_aarch32(class Assembler *as) { 131 #ifdef ASSERT 132 bits = 0; 133 #endif 134 insn = 0; 135 assem = as; 136 } 137 138 inline ~Instruction_aarch32(); 139 140 unsigned &get_insn() { return insn; } 141 #ifdef ASSERT 142 unsigned &get_bits() { return bits; } 143 #endif 144 145 static inline int32_t extend(unsigned val, int hi = 31, int lo = 0) { 146 union { 147 unsigned u; 148 int n; 149 }; 150 151 u = val << (31 - hi); 152 n = n >> (31 - hi + lo); 153 return n; 154 } 155 156 static inline uint32_t extract(uint32_t val, int msb, int lsb) { 157 int nbits = msb - lsb + 1; 158 assert_cond(msb >= lsb); 159 uint32_t mask = (1U << nbits) - 1; 160 uint32_t result = val >> lsb; 161 result &= mask; 162 return result; 163 } 164 165 static inline int32_t sextract(uint32_t val, int msb, int lsb) { 166 uint32_t uval = extract(val, msb, lsb); 167 return extend(uval, msb - lsb); 168 } 169 170 static void patch(address a, int msb, int lsb, unsigned long val) { 171 int nbits = msb - lsb + 1; 172 guarantee(val < (1U << nbits), "Field too big for insn"); 173 assert_cond(msb >= lsb); 174 unsigned mask = (1U << nbits) - 1; 175 val <<= lsb; 176 mask <<= lsb; 177 unsigned target = *(unsigned *)a; 178 target &= ~mask; 179 target |= val; 180 *(unsigned *)a = target; 181 } 182 183 static void spatch(address a, int msb, int lsb, long val) { 184 int nbits = msb - lsb + 1; 185 long chk = val >> (nbits - 1); 186 guarantee (chk == -1 || chk == 0, "Field too big for insn"); 187 unsigned uval = val; 188 unsigned mask = (1U << nbits) - 1; 189 uval &= mask; 190 uval <<= lsb; 191 mask <<= lsb; 192 unsigned target = *(unsigned *)a; 193 target &= ~mask; 194 target |= uval; 195 *(unsigned *)a = target; 196 } 197 198 /* void f(unsigned val, int msb, int lsb) { 199 int nbits = msb - lsb + 1; 200 guarantee(val < (1U << nbits), "Field too big for insn"); 201 assert_cond(msb >= lsb); 202 unsigned mask = (1U << nbits) - 1; 203 val <<= lsb; 204 mask <<= lsb; 205 insn |= val; 206 assert_cond((bits & mask) == 0); 207 #ifdef ASSERT 208 bits |= mask; 209 #endif 210 }*/ 211 212 void f(unsigned val, int msb, int lsb) { 213 int nbits = msb - lsb + 1; 214 guarantee(val < (1U << nbits), "Field too big for insn"); 215 assert_cond(msb >= lsb); 216 unsigned mask = (1U << nbits) - 1; 217 val <<= lsb; 218 mask <<= lsb; 219 insn &= ~mask; 220 insn |= val; 221 #ifdef ASSERT 222 bits |= mask; 223 #endif 224 } 225 226 void f(unsigned val, int bit) { 227 f(val, bit, bit); 228 } 229 230 void sf(long val, int msb, int lsb) { 231 int nbits = msb - lsb + 1; 232 long chk = val >> (nbits - 1); 233 guarantee (chk == -1 || chk == 0, "Field too big for insn"); 234 unsigned uval = val; 235 unsigned mask = (1U << nbits) - 1; 236 uval &= mask; 237 f(uval, lsb + nbits - 1, lsb); 238 } 239 240 void rf(Register r, int lsb) { 241 f(r->encoding_nocheck(), lsb + 3, lsb); 242 } 243 244 void rf(FloatRegister r, int lsb) { 245 f(r->encoding_nocheck(), lsb + 4, lsb); 246 } 247 248 unsigned get(int msb = 31, int lsb = 0) { 249 int nbits = msb - lsb + 1; 250 unsigned mask = ((1U << nbits) - 1) << lsb; 251 assert_cond((bits & mask) == mask); 252 return (insn & mask) >> lsb; 253 } 254 255 void fixed(unsigned value, unsigned mask) { 256 assert_cond ((mask & bits) == 0); 257 #ifdef ASSERT 258 bits |= mask; 259 #endif 260 insn |= value; 261 } 262 }; 263 264 #define starti Instruction_aarch32 do_not_use(this); set_current(&do_not_use) 265 266 // abs methods which cannot overflow and so are well-defined across 267 // the entire domain of integer types. 268 static inline unsigned int uabs(unsigned int n) { 269 union { 270 unsigned int result; 271 int value; 272 }; 273 result = n; 274 if (value < 0) result = -result; 275 return result; 276 } 277 static inline unsigned long uabs(unsigned long n) { 278 union { 279 unsigned long result; 280 long value; 281 }; 282 result = n; 283 if (value < 0) result = -result; 284 return result; 285 } 286 static inline unsigned long uabs(long n) { return uabs((unsigned long)n); } 287 static inline unsigned long uabs(int n) { return uabs((unsigned int)n); } 288 289 #define S_DFLT ::lsl() 290 #define C_DFLT AL 291 292 293 // Shift for base reg + reg offset addressing 294 class shift_op { 295 public: 296 enum shift_kind { LSL, LSR, ASR, ROR }; 297 private: 298 enum shift_source { imm_s, reg_s }; 299 enum shift_source _source; 300 enum shift_kind _op; 301 int _shift; 302 Register _reg; 303 304 bool check_valid() { 305 if(imm_s == _source) { 306 switch(_op) { 307 case LSL: return _shift >= 0 && _shift <= 31; 308 case ROR: return _shift >= 1 && _shift <= 32; 309 default: return _shift >= 1 && _shift <= 32; 310 } 311 } 312 return true; //Don't check register shifts 313 } 314 public: 315 // Default shift is lsl(0) 316 shift_op() 317 : _source(imm_s), _op(LSL), _shift(0) { } 318 shift_op(enum shift_kind op, int shift) 319 : _source(imm_s), _op(op), _shift(shift) { 320 if(!shift) { 321 // All zero shift encodings map to LSL 0 322 _shift = 0; 323 _op = LSL; 324 } 325 int pshift = _shift; 326 if(-1 == _shift && ROR == _op) { 327 // This is an RRX, make shift valid for the check 328 _shift = 1; 329 pshift = 0; //set to zero 330 } 331 assert(check_valid(), "Invalid shift quantity"); 332 _shift = pshift; //restore shift 333 } 334 shift_op(enum shift_kind op, Register r) 335 : _source(reg_s), _op(op), _reg(r) {} 336 337 shift_kind kind() const { 338 return _op; 339 } 340 341 int shift() const { 342 assert(imm_s == _source, "Not an immediate shift"); 343 return _shift % 32; 344 } 345 Register reg() const { 346 assert(reg_s == _source, "Not a register shift"); 347 return _reg; 348 } 349 bool is_register() { 350 return reg_s == _source; 351 } 352 bool operator==(const shift_op& other) const { 353 if(imm_s == _source && imm_s == other._source) { 354 return _op == other._op && _shift == other._shift; 355 } else if (reg_s == _source && imm_s == _source) { 356 return _op == other._op && _reg == other._reg; 357 } 358 return false; 359 } 360 bool operator!=(const shift_op& other) const { 361 return !( *this == other); 362 } 363 }; 364 class lsl : public shift_op { 365 public: 366 lsl(int sft = 0): shift_op(LSL, sft) { } 367 lsl(Register r): shift_op(LSL, r) { } 368 }; 369 class lsr : public shift_op { 370 public: 371 lsr(int sft = 0): shift_op(LSR, sft) { } 372 lsr(Register r): shift_op(LSR, r) { } 373 }; 374 class asr : public shift_op { 375 public: 376 asr(int sft = 0): shift_op(ASR, sft) { } 377 asr(Register r): shift_op(ASR, r) { } 378 }; 379 class ror : public shift_op { 380 public: 381 ror(int sft = 0): shift_op(ROR, sft) {} 382 ror(Register r): shift_op(ROR, r) { } 383 }; 384 class rrx : public shift_op { 385 public: 386 rrx(): shift_op(ROR, -1) {} 387 }; 388 389 390 // Addressing modes 391 class Address { 392 public: 393 enum access_mode { no_mode, imm, reg, lit }; 394 //literal is class of imm? -> potentially have to split later if some instructions work 395 // with one but not other although can be determined from registers. 396 enum wb_mode { off, pre, post }; 397 398 enum reg_op { ADD, SUB }; 399 400 private: 401 Register _base; 402 Register _index; 403 int _offset; 404 enum access_mode _acc_mode; 405 enum wb_mode _wb_mode; 406 enum reg_op _as_op; 407 shift_op _shift; 408 409 RelocationHolder _rspec; 410 411 // Typically we use AddressLiterals we want to use their rval 412 // However in some situations we want the lval (effect address) of 413 // the item. We provide a special factory for making those lvals. 414 bool _is_lval; 415 416 // If the target is far we'll need to load the ea of this to a 417 // register to reach it. Otherwise if near we can do PC-relative 418 // addressing. 419 address _target; 420 421 public: 422 Address() 423 : _acc_mode(no_mode) { } 424 //immediate & literal 425 Address(Register r, enum wb_mode mode = off) 426 : _base(r), _index(noreg), _offset(0), _acc_mode(imm), _wb_mode(mode), 427 _shift(lsl()), _target(0) { 428 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 429 } 430 Address(Register r, int o, enum wb_mode mode = off) 431 : _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode), 432 _shift(lsl()), _target(0) { 433 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 434 } 435 Address(Register r, long o, enum wb_mode mode = off) 436 : _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode), 437 _shift(lsl()), _target(0) { 438 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 439 } 440 Address(Register r, unsigned long o, enum wb_mode mode = off) 441 : _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode), 442 _shift(lsl()), _target(0) { 443 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 444 } 445 Address(Register r, unsigned int o, enum wb_mode mode = off) 446 : _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode), 447 _shift(lsl()), _target(0) { 448 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 449 } 450 #ifdef ASSERT 451 Address(Register r, ByteSize disp) 452 : _base(r), _index(noreg), _offset(in_bytes(disp)), _acc_mode(imm), _wb_mode(off), 453 _shift(lsl()), _target(0) { 454 assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed."); 455 } 456 #endif 457 458 459 //Register-offset 460 Address(Register r, Register r1, shift_op shift = lsl(), enum reg_op op = ADD, 461 enum wb_mode wbm = off) 462 : _base(r), _index(r1), _offset(0), _acc_mode(reg), _wb_mode(wbm), _as_op(op), 463 _shift(shift), _target(0) { 464 assert(!shift.is_register(), "Can't shift a register-offset address by a register"); 465 } 466 467 Address(address target, RelocationHolder const& rspec) 468 : _acc_mode(lit), 469 _base(sp), 470 _wb_mode(off), 471 _rspec(rspec), 472 _is_lval(false), 473 _target(target) 474 { } 475 Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type); 476 477 #ifdef COMPILER2 478 static Address make_raw(int base, int index, int scale, unsigned long o, relocInfo::relocType disp_reloc); 479 #endif 480 481 private: 482 //Could be either 483 void AddressConstruct(Register base, RegisterOrConstant index, enum reg_op op, shift_op shift, 484 enum wb_mode mode); 485 public: 486 487 Address(Register base, RegisterOrConstant index, enum reg_op op, enum wb_mode mode) { 488 AddressConstruct(base, index, op, lsl(), mode); 489 } 490 Address(Register base, RegisterOrConstant index, shift_op shift = lsl(), enum reg_op op = ADD, 491 enum wb_mode mode = off) { 492 if(shift.kind() != lsl().kind()) { 493 assert(index.is_register(), "should be"); 494 } 495 AddressConstruct(base, index, op, shift, mode); 496 } 497 498 499 Register base() const { 500 //in aarch64 this didn't apply to preindex mode -> why? 501 guarantee(_acc_mode == imm || _acc_mode == reg, "wrong mode"); 502 return _base; 503 } 504 long offset() const { 505 return _offset; 506 } 507 Register index() const { 508 return _index; 509 } 510 shift_op shift() const { 511 return _shift; 512 } 513 reg_op op() const { 514 return _as_op; 515 } 516 access_mode get_mode() const { 517 return _acc_mode; 518 } 519 wb_mode get_wb_mode() const { 520 return _wb_mode; 521 } 522 bool uses(Register reg) const { return _base == reg || _index == reg; } 523 unsigned reg_bits() { return _base->bit(_acc_mode != no_mode) | _index->bit(_acc_mode == reg); } 524 address target() const { return _target; } 525 const RelocationHolder& rspec() const { return _rspec; } 526 527 void encode(Instruction_aarch32 *i, CodeSection *sec, address pc) const; 528 529 void fp_encode(Instruction_aarch32 *i, CodeSection *sec, address pc) const; 530 531 void lea(MacroAssembler *, Register) const; 532 533 typedef enum { 534 IDT_BOOLEAN = T_BOOLEAN, 535 IDT_CHAR = T_CHAR, 536 IDT_FLOAT = T_FLOAT, 537 IDT_DOUBLE = T_DOUBLE, 538 IDT_BYTE = T_BYTE, 539 IDT_SHORT = T_SHORT, 540 IDT_INT = T_INT, 541 IDT_LONG = T_LONG, 542 IDT_OBJECT = T_OBJECT, 543 IDT_ARRAY = T_ARRAY, 544 IDT_ADDRESS = T_ADDRESS, 545 IDT_METADATA = T_METADATA, 546 // not really a data type, denotes the use when address value is needed 547 // itself, and Address instance is not used to fetch actual data from memory 548 IDT_LEA = 100, 549 // ldrex*/strex* 550 IDT_ATOMIC = 101, 551 // multi-word memory access insn (ldmia/stmia etc) 552 IDT_MULTIWORD 553 } InsnDataType; 554 555 inline static InsnDataType toInsnDataType(BasicType type) { 556 return (InsnDataType)type; 557 } 558 559 Address safe_for(InsnDataType type, MacroAssembler *, Register temp); 560 bool is_safe_for(InsnDataType); 561 562 static bool offset_ok_for_immed(long offset, InsnDataType type); 563 static bool shift_ok_for_index(shift_op shift, InsnDataType type); 564 }; 565 566 // Convience classes 567 class RuntimeAddress: public Address { 568 public: 569 RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {} 570 }; 571 572 class OopAddress: public Address { 573 public: 574 OopAddress(address target) : Address(target, relocInfo::oop_type){} 575 }; 576 577 class ExternalAddress: public Address { 578 private: 579 static relocInfo::relocType reloc_for_target(address target) { 580 // Sometimes ExternalAddress is used for values which aren't 581 // exactly addresses, like the card table base. 582 // external_word_type can't be used for values in the first page 583 // so just skip the reloc in that case. 584 return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none; 585 } 586 587 public: 588 ExternalAddress(address target) : Address(target, reloc_for_target(target)) {} 589 }; 590 591 class InternalAddress: public Address { 592 public: 593 InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {} 594 }; 595 596 597 const int FPUStateSizeInWords = FloatRegisterImpl::number_of_registers; 598 599 class Assembler : public AbstractAssembler { 600 void emit_long(jint x) { 601 AbstractAssembler::emit_int32(x); 602 } 603 604 public: 605 //TODO REMOVE shift_kind from here once done 606 enum shift_kind { LSL, LSR, ASR, ROR }; 607 // NOTE RRX is a special case of ROR with shift = 0# 608 609 // Helper functions for shifts 610 // Here to allow compiler to find global shift_op without :: prefix as lsl is a 611 // standalone instruction 612 #define HELPER(NAME) \ 613 shift_op NAME(int sft = 0) { return ::NAME(sft); } \ 614 shift_op NAME(Register r) { return ::NAME(r); } 615 HELPER(lsl); 616 HELPER(lsr); 617 HELPER(asr); 618 HELPER(ror); 619 shift_op rrx() { return ::rrx(); } 620 #undef HELPER 621 622 typedef enum { 623 EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV 624 } Condition; 625 626 enum { instruction_size = 4 }; 627 628 static const uint32_t nop_insn = 0xe1a00000; 629 630 Address adjust(Register base, int offset, bool preIncrement) { 631 if (preIncrement) 632 return Address(base, offset, Address::pre); 633 else 634 return Address(base, offset, Address::post); 635 } 636 637 Address adjust(Register base, Register index, shift_op shift, 638 enum Address::reg_op op, bool preIncrement) { 639 return Address(base, index, shift, op, preIncrement ? Address::pre : Address::post); 640 } 641 642 Address pre(Register base, int offset) { 643 return adjust(base, offset, true); 644 } 645 646 Address pre(Register base, Register index, shift_op shift, enum Address::reg_op op) { 647 return adjust(base, index, shift, op, true); 648 } 649 650 Address post (Register base, int offset) { 651 return adjust(base, offset, false); 652 } 653 654 Instruction_aarch32* current; 655 656 void set_current(Instruction_aarch32* i) { current = i; } 657 658 void f(unsigned val, int msb, int lsb) { 659 current->f(val, msb, lsb); 660 } 661 void f(unsigned val, int msb) { 662 current->f(val, msb, msb); 663 } 664 void sf(long val, int msb, int lsb) { 665 current->sf(val, msb, lsb); 666 } 667 void rf(Register reg, int lsb) { 668 current->rf(reg, lsb); 669 } 670 void rf(FloatRegister reg, int lsb) { 671 current->rf(reg, lsb); 672 } 673 void fixed(unsigned value, unsigned mask) { 674 current->fixed(value, mask); 675 } 676 677 void emit() { 678 emit_long(current->get_insn()); 679 assert_cond(current->get_bits() == 0xffffffff); 680 current = NULL; 681 } 682 683 typedef void (Assembler::* uncond_branch_insn)(address dest); 684 typedef void (Assembler::* cond_branch_insn)(address dest, Condition cond); 685 typedef void (Assembler::* cond_ldst_insn)(Register Rt, address dest, Condition cond); 686 typedef void (Assembler::* cond_fp_ldst_insn)(FloatRegister Vd, address dest, Condition cond); 687 688 void wrap_label(Label &L, uncond_branch_insn insn); 689 void wrap_label(Label &L, Condition cond, cond_branch_insn insn); 690 void wrap_label(Register r, Label &L, Condition cond, cond_ldst_insn insn); 691 void wrap_label(FloatRegister r, Label &L, Condition cond, cond_fp_ldst_insn insn); 692 693 #undef INSN 694 695 // AARCH32 Instructions 696 // Defined roughly in the order they are found in 697 // ARM Archicture Reference Manual, section 5 698 699 #define ZERO_ADDR_REG r0 700 #define ONES_ADDR_REG r15 701 702 // Data processing (register & register-shifted-register) 703 void reg_instr(int decode, shift_op shift, Condition cond, bool s) { 704 f(cond, 31, 28), f(0b000, 27, 25), f(decode, 24, 21), f(s, 20); 705 f(shift.shift(), 11, 7), f(shift.kind(), 6, 5), f(0, 4); 706 } 707 void reg_shift_reg_instr(int decode, enum shift_op::shift_kind kind, 708 Condition cond, bool s) { 709 f(cond, 31, 28), f(0b000, 27, 25), f(decode, 24, 21), f(s, 20); 710 f(0, 7), f(kind, 6, 5), f(1, 4); 711 } 712 713 #define INSN(NAME, decode, s_flg) \ 714 void NAME(Register Rd, Register Rn, Register Rm, shift_op shift = S_DFLT, \ 715 Condition cond = C_DFLT) { \ 716 starti; \ 717 if(shift.is_register()) { \ 718 reg_shift_reg_instr(decode, shift.kind(), cond, s_flg); \ 719 rf(Rn, 16), rf(Rd, 12), rf(shift.reg(), 8), rf(Rm, 0); \ 720 } else { \ 721 reg_instr(decode, shift, cond, s_flg); \ 722 rf(Rn, 16), rf(Rd, 12), rf(Rm, 0); \ 723 } \ 724 } 725 INSN(andr, 0b0000, 0); 726 INSN(eor, 0b0001, 0); 727 INSN(sub, 0b0010, 0); 728 INSN(rsb, 0b0011, 0); 729 INSN(add, 0b0100, 0); 730 INSN(adc, 0b0101, 0); 731 INSN(sbc, 0b0110, 0); 732 INSN(rsc, 0b0111, 0); 733 INSN(orr, 0b1100, 0); 734 INSN(bic, 0b1110, 0); 735 736 INSN(ands, 0b0000, 1); 737 INSN(eors, 0b0001, 1); 738 INSN(subs, 0b0010, 1); 739 INSN(rsbs, 0b0011, 1); 740 INSN(adds, 0b0100, 1); 741 INSN(adcs, 0b0101, 1); 742 INSN(sbcs, 0b0110, 1); 743 INSN(rscs, 0b0111, 1); 744 INSN(orrs, 0b1100, 1); 745 INSN(bics, 0b1110, 1); 746 747 #undef INSN 748 749 #define INSN(NAME, decode) \ 750 void NAME(Register Rn, Register Rm, Condition cond) { \ 751 NAME(Rn, Rm, S_DFLT, cond); \ 752 } \ 753 void NAME(Register Rn, Register Rm, shift_op shift = S_DFLT, \ 754 Condition cond = C_DFLT) { \ 755 starti; \ 756 if(shift.is_register()) { \ 757 reg_shift_reg_instr(decode, shift.kind(), cond, true); \ 758 rf(Rn, 16), f(0b0000, 15, 12), rf(shift.reg(), 8), rf(Rm, 0); \ 759 } else { \ 760 reg_instr(decode, shift, cond, true); \ 761 rf(Rn, 16), f(0, 15, 12), rf(Rm, 0); \ 762 } \ 763 } 764 INSN(tst, 0b1000); 765 INSN(teq, 0b1001); 766 INSN(cmp, 0b1010); 767 INSN(cmn, 0b1011); 768 #undef INSN 769 770 // TODO appears that if Rd = 15 and s flag set then perhaps different method 771 void mov_internal(int decode, Register Rd, Register Rnm, shift_op shift, bool s, Condition cond) { 772 starti; 773 if(shift.is_register()) { 774 reg_shift_reg_instr(decode, shift.kind(), cond, s); 775 f(0b0000, 19, 16), rf(Rd, 12), rf(shift.reg(), 8), rf(Rnm, 0); 776 } else { 777 reg_instr(decode, shift, cond, s); 778 f(0, 19, 16), rf(Rd, 12), rf(Rnm, 0); 779 } 780 } 781 void mov(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) { 782 mov_internal(0b1101, Rd, Rm, shift, false, cond); 783 } 784 void movs(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) { 785 mov_internal(0b1101, Rd, Rm, shift, true, cond); 786 } 787 void mov(Register Rd, Register Rm, Condition cond = C_DFLT) { 788 mov_internal(0b1101, Rd, Rm, S_DFLT, false, cond); 789 } 790 void movs(Register Rd, Register Rm, Condition cond = C_DFLT) { 791 mov_internal(0b1101, Rd, Rm, S_DFLT, true, cond); 792 } 793 794 void mvn(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) { 795 mov_internal(0b1111, Rd, Rm, shift, false, cond); 796 } 797 void mvns(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) { 798 mov_internal(0b1111, Rd, Rm, shift, true, cond); 799 } 800 void mvn(Register Rd, Register Rm, Condition cond = C_DFLT) { 801 mov_internal(0b1111, Rd, Rm, S_DFLT, false, cond); 802 } 803 void mvns(Register Rd, Register Rm, Condition cond = C_DFLT) { 804 mov_internal(0b1111, Rd, Rm, S_DFLT, true, cond); 805 } 806 807 #define INSN(NAME, type, s_flg, ASSERTION) \ 808 void NAME(Register Rd, Register Rm, unsigned shift, Condition cond = C_DFLT) { \ 809 assert_cond(ASSERTION); \ 810 if(s_flg) movs(Rd, Rm, shift_op(type, shift), cond); \ 811 else mov(Rd, Rm, shift_op(type, shift), cond); \ 812 } 813 INSN(lsl, shift_op::LSL, 0, true); 814 INSN(lsr, shift_op::LSR, 0, true); 815 INSN(asr, shift_op::ASR, 0, true); 816 INSN(ror, shift_op::ROR, 0, shift != 0); //shift == 0 => RRX 817 818 INSN(lsls, shift_op::LSL, 1, true); 819 INSN(lsrs, shift_op::LSR, 1, true); 820 INSN(asrs, shift_op::ASR, 1, true); 821 INSN(rors, shift_op::ROR, 1, shift != 0); //shift == 0 => RRX 822 #undef INSN 823 824 #define INSN(NAME, type, s_flg) \ 825 void NAME(Register Rd, Register Rm, Condition cond = C_DFLT) { \ 826 if(s_flg) movs(Rd, Rm, shift_op(type, 0), cond); \ 827 else mov(Rd, Rm, shift_op(type, 0), cond); \ 828 } 829 INSN(rrx, shift_op::LSR, 0); 830 INSN(rrxs, shift_op::LSR, 1); 831 #undef INSN 832 833 //Data processing (register-shifted-register) 834 #define INSN(NAME, type, s_flg) \ 835 void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \ 836 if(s_flg) movs(Rd, Rn, shift_op(type, Rm), cond); \ 837 else mov(Rd, Rn, shift_op(type, Rm), cond); \ 838 } 839 INSN(lsl, shift_op::LSL, 0); 840 INSN(lsr, shift_op::LSR, 0); 841 INSN(asr, shift_op::ASR, 0); 842 INSN(ror, shift_op::ROR, 0); 843 844 INSN(lsls, shift_op::LSL, 1); 845 INSN(lsrs, shift_op::LSR, 1); 846 INSN(asrs, shift_op::ASR, 1); 847 INSN(rors, shift_op::ROR, 1); 848 #undef INSN 849 850 bool imm_instr(int decode, Register Rd, Register Rn, int imm, Condition cond, 851 bool s) { 852 if(!is_valid_for_imm12(imm)) 853 return false; 854 { 855 starti; 856 f(cond, 31, 28), f(0b001, 27, 25), f(decode, 24, 21), f(s, 20), rf(Rn, 16); 857 int imm12 = encode_imm12(imm); 858 rf(Rd, 12), f(imm12, 11, 0); 859 } 860 return true; 861 } 862 863 #define INSN(NAME, decode, s_flg) \ 864 inline void NAME(Register Rd, Register Rn, unsigned imm, Condition cond = C_DFLT) {\ 865 bool status = imm_instr(decode, Rd, Rn, imm, cond, s_flg); \ 866 assert(status, "invalid imm"); \ 867 } 868 INSN(andr, 0b0000, 0); 869 INSN(eor, 0b0001, 0); 870 INSN(orr, 0b1100, 0); 871 INSN(bic, 0b1110, 0); 872 873 INSN(ands, 0b0000, 1); 874 INSN(eors, 0b0001, 1); 875 INSN(orrs, 0b1100, 1); 876 INSN(bics, 0b1110, 1); 877 //NOTE: arithmetic immediate instructions are defined below to allow dispatch. 878 #undef INSN 879 protected: 880 // Mov data to destination register in the shortest number of instructions 881 // possible. 882 void mov_immediate(Register dst, uint32_t imm32, Condition cond, bool s); 883 // Mov data to destination register but always emit enough instructions that would 884 // permit any 32-bit constant to be loaded. (Allow for rewriting later). 885 void mov_immediate32(Register dst, uint32_t imm32, Condition cond, bool s); 886 887 void add_sub_imm(int decode, Register Rd, Register Rn, int imm, 888 Condition cond, bool s); 889 890 public: 891 #define INSN(NAME, decode, s_flg) \ 892 inline void NAME(Register Rd, Register Rn, int imm, Condition cond = C_DFLT) { \ 893 add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \ 894 } \ 895 inline void NAME(Register Rd, Register Rn, unsigned imm, \ 896 Condition cond = C_DFLT) { \ 897 add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \ 898 } \ 899 inline void NAME(Register Rd, Register Rn, long imm, Condition cond = C_DFLT) { \ 900 add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \ 901 } \ 902 inline void NAME(Register Rd, Register Rn, unsigned long imm, \ 903 Condition cond = C_DFLT) { \ 904 add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \ 905 } \ 906 /*Addition dispatch - place in macroassembler?*/ \ 907 void NAME(Register Rd, Register Rn, RegisterOrConstant operand, \ 908 Condition cond = C_DFLT) { \ 909 if(operand.is_register()) { \ 910 NAME(Rd, Rn, (Register)operand.as_register(), lsl(), cond); \ 911 } else { \ 912 NAME(Rd, Rn, (unsigned)operand.as_constant(), cond); \ 913 } \ 914 } \ 915 inline void NAME(Register Rd, Register Rn, unsigned imm, Register Rtmp, \ 916 Condition cond = C_DFLT) { \ 917 if (Assembler::operand_valid_for_add_sub_immediate(imm)) \ 918 NAME(Rd, Rn, imm, cond); \ 919 else { \ 920 mov_immediate(Rtmp, imm, cond, false); \ 921 NAME(Rd, Rn, Rtmp, cond); \ 922 } \ 923 } \ 924 //Note that the RegisterOrConstant version can't take a shift even though 925 // one of the instructions dispatched to can 926 INSN(sub, 0b0010, 0); 927 INSN(rsb, 0b0011, 0); 928 INSN(add, 0b0100, 0); 929 INSN(adc, 0b0101, 0); 930 INSN(sbc, 0b0110, 0); 931 INSN(rsc, 0b0111, 0); 932 933 INSN(subs, 0b0010, 1); 934 INSN(rsbs, 0b0011, 1); 935 INSN(adds, 0b0100, 1); 936 INSN(adcs, 0b0101, 1); 937 INSN(sbcs, 0b0110, 1); 938 INSN(rscs, 0b0111, 1); 939 #undef INSN 940 //No need to do reverse as register subtracted from immediate 941 942 // alias for mvn 943 void inv(Register Rd, Register Rn, Condition cond = C_DFLT) { 944 mvn(Rd, Rn, cond); 945 } 946 //alias for rsb 947 void neg(Register Rd, Register Rn, Condition cond = C_DFLT) { 948 rsb(Rd, Rn, 0, cond); 949 } 950 void negs(Register Rd, Register Rn, Condition cond = C_DFLT) { 951 rsbs(Rd, Rn, 0, cond); 952 } 953 954 // PC-rel. addressing 955 void adr_encode(Register Rd, int imm, Condition cond) { 956 if (is_valid_for_imm12(imm) || is_valid_for_imm12(-imm)) { 957 add_sub_imm(0b0100, Rd, r15_pc, imm, cond, false); //opcode for add 958 } else { 959 int adjust = 0; 960 if (VM_Version::features() & (FT_ARMV7 | FT_ARMV6T2)) { 961 adjust = 8; // mov_w/mov_t 962 } else { 963 adjust = 16; // mov and 3 orr 964 } 965 mov_immediate32(Rd, imm - adjust, cond, false); 966 add(Rd, r15_pc, Rd, cond); 967 } 968 } 969 970 void adr(Register Rd, address dest, Condition cond = C_DFLT); 971 972 void adr(Register Rd, const Address &dest, Condition cond = C_DFLT); 973 974 void adr(Register Rd, Label &L, Condition cond = C_DFLT) { 975 wrap_label(Rd, L, cond, &Assembler::Assembler::adr); 976 } 977 978 private: 979 friend void entry(CodeBuffer *cb); 980 #define INSN(NAME, decode, s_flg) \ 981 inline void NAME(Register Rd, unsigned imm, Condition cond = C_DFLT) { \ 982 bool status = imm_instr(decode, Rd, ZERO_ADDR_REG, imm, cond, s_flg); \ 983 assert(status, "invalid imm"); \ 984 } \ 985 inline void NAME(Register Rd, int imm, Condition cond = C_DFLT) { \ 986 bool status = imm_instr(decode, Rd, ZERO_ADDR_REG, imm, cond, s_flg); \ 987 assert(status, "invalid imm"); \ 988 } 989 public: 990 991 INSN(mov_i, 0b1101, 0); 992 INSN(mvn_i, 0b1111, 0); 993 994 INSN(movs_i, 0b1101, 1); 995 INSN(mvns_i, 0b1111, 1); 996 #undef INSN 997 998 void movw_i(Register Rd, unsigned imm, Condition cond = C_DFLT) { 999 starti; 1000 assert(imm < (1 << 16), "Immediate too big for movw"); 1001 f(cond, 31, 28), f(0b00110000, 27, 20), f(imm >> 12, 19, 16); 1002 rf(Rd, 12), f(imm & 0xfff, 11, 0); 1003 } 1004 1005 void movt_i(Register Rd, unsigned imm, Condition cond = C_DFLT) { 1006 starti; 1007 assert(imm < (1 << 16), "Immediate too big for movt"); 1008 f(cond, 31, 28), f(0b00110100, 27, 20), f(imm >> 12, 19, 16); 1009 rf(Rd, 12), f(imm & 0xfff, 11, 0); 1010 } 1011 1012 #define INSN(NAME, decode) \ 1013 inline void NAME(Register Rn, int imm, Condition cond = C_DFLT) { \ 1014 bool status = imm_instr(decode, ZERO_ADDR_REG, Rn, imm, cond, true); \ 1015 assert(status, "invalid imm"); \ 1016 } \ 1017 inline void NAME(Register Rn, unsigned imm, Condition cond = C_DFLT) { \ 1018 bool status = imm_instr(decode, ZERO_ADDR_REG, Rn, imm, cond, true); \ 1019 assert(status, "invalid imm"); \ 1020 } \ 1021 inline void NAME(Register Rn, int imm, Register Rtmp, Condition cond = C_DFLT) { \ 1022 if (Assembler::operand_valid_for_add_sub_immediate(imm)) \ 1023 NAME(Rn, imm, cond); \ 1024 else { \ 1025 mov_immediate(Rtmp, imm, cond, false); \ 1026 NAME(Rn, Rtmp, cond); \ 1027 } \ 1028 } \ 1029 inline void NAME(Register Rn, unsigned imm, Register Rtmp, Condition cond = C_DFLT) { \ 1030 if (Assembler::operand_valid_for_add_sub_immediate(imm)) \ 1031 NAME(Rn, imm, cond); \ 1032 else { \ 1033 mov_immediate(Rtmp, imm, cond, false); \ 1034 NAME(Rn, Rtmp, cond); \ 1035 } \ 1036 } 1037 INSN(tst, 0b1000); 1038 INSN(teq, 0b1001); 1039 INSN(cmp, 0b1010); 1040 INSN(cmn, 0b1011); 1041 #undef INSN 1042 1043 1044 // Multiply and multiply accumulate 1045 void mult_instr(int decode, Register a, Register b, Register c, 1046 Register d, Condition cond, bool s) { 1047 starti; 1048 f(cond, 31, 28), f(0b0000, 27, 24), f(decode, 23, 21), f(s, 20); 1049 rf(a, 16), rf(b, 12), rf(c, 8), rf(d, 0), f(0b1001, 7, 4); 1050 } 1051 1052 void mul(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { 1053 mult_instr(0b000, Rd, ZERO_ADDR_REG, Rm, Rn, cond, false); 1054 } 1055 void muls(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { 1056 mult_instr(0b000, Rd, ZERO_ADDR_REG, Rm, Rn, cond, true); 1057 } 1058 1059 void mla(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) { 1060 mult_instr(0b001, Rd, Ra, Rm, Rn, cond, false); 1061 } 1062 void mlas(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) { 1063 mult_instr(0b001, Rd, Ra, Rm, Rn, cond, true); 1064 } 1065 1066 void mls(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) { 1067 mult_instr(0b011, Rd, Ra, Rm, Rn, cond, false); 1068 } 1069 1070 void umaal(Register RdLo, Register RdHi, Register Rn, Register Rm, Condition cond = C_DFLT) { 1071 mult_instr(0b010, RdHi, RdLo, Rm, Rn, cond, false); 1072 } 1073 1074 #define INSN(NAME, decode, s_flg) \ 1075 void NAME(Register RdLo, Register RdHi, Register Rn, Register Rm, \ 1076 Condition cond = C_DFLT) { \ 1077 mult_instr(decode, RdHi, RdLo, Rm, Rn, cond, s_flg); \ 1078 } 1079 INSN(umull, 0b100, 0); 1080 INSN(umlal, 0b101, 0); 1081 INSN(smull, 0b110, 0); 1082 INSN(smlal, 0b111, 0); 1083 1084 INSN(umulls, 0b100, 1); 1085 INSN(umlals, 0b101, 1); 1086 INSN(smulls, 0b110, 1); 1087 INSN(smlals, 0b111, 1); 1088 1089 #undef INSN 1090 1091 //Saturating addition and subtraction 1092 #define INSN(NAME, decode) \ 1093 void NAME(Register Rd, Register Rm, Register Rn, Condition cond = C_DFLT) { \ 1094 starti; \ 1095 f(cond, 31, 28), f( 0b00010, 27, 23), f(decode, 22, 21), f(0, 20); \ 1096 rf(Rn, 16), rf(Rd, 12), f( 0b00000101, 11, 4), rf(Rm, 0); \ 1097 } 1098 INSN(qadd, 0b00); 1099 INSN(qsub, 0b01); 1100 INSN(qdadd, 0b10); 1101 INSN(qdsub, 0b11); 1102 #undef INSN 1103 1104 // Halfword multiply and multiply accumulate 1105 void mul_instr(int decode, Register Ra, Register Rb, Register Rc, Register Rd, 1106 bool N, bool M, Condition cond) { 1107 starti; 1108 f(cond, 31, 28), f(0b00010, 27, 23), f(decode, 22, 21), f(0, 20); 1109 rf(Ra, 16), rf(Rb, 12), rf(Rc, 8), f(1, 7), f(M, 6), f(N, 5), f(0, 4); 1110 rf(Rd, 0); 1111 } 1112 1113 #define INSN(NAME, decode, N, M) \ 1114 void NAME(Register Rd, Register Rn, Register Rm, Register Ra, \ 1115 Condition cond = C_DFLT) { \ 1116 mul_instr(decode, Rd, Ra, Rm, Rn, N, M, cond); \ 1117 } 1118 INSN(smlabb, 0b00, 0, 0); 1119 INSN(smlabt, 0b00, 0, 1) 1120 INSN(smlatb, 0b00, 1, 0) 1121 INSN(smlatt, 0b00, 1, 1) 1122 1123 INSN(smlawb, 0b01, 0, 0); 1124 INSN(smlawt, 0b01, 0, 1); 1125 #undef INSN 1126 1127 #define INSN(NAME, decode, N, M) \ 1128 void NAME(Register RdLo, Register RdHi, Register Rn, Register Rm, \ 1129 Condition cond = C_DFLT) { \ 1130 mul_instr(decode, RdHi, RdLo, Rm, Rn, N, M, cond); \ 1131 } 1132 INSN(smlalbb, 0b10, 0, 0); 1133 INSN(smlalbt, 0b10, 0, 1); 1134 INSN(smlaltb, 0b10, 1, 0); 1135 INSN(smlaltt, 0b10, 1, 1); 1136 #undef INSN 1137 1138 #define INSN(NAME, decode, N, M) \ 1139 void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \ 1140 mul_instr(decode, Rd, ZERO_ADDR_REG, Rm, Rn, N, M, cond); \ 1141 } 1142 INSN(smulwb, 0b01, 1, 0); 1143 INSN(smulwt, 0b01, 1, 1); 1144 1145 INSN(smulbb, 0b11, 0, 0); 1146 INSN(smulbt, 0b11, 0, 1); 1147 INSN(smultb, 0b11, 1, 0); 1148 INSN(smultt, 0b11, 1, 1); 1149 #undef INSN 1150 1151 // For Extra load/store instructions, see load/store section 1152 // For Synchronization primitives, see load/store section 1153 1154 // MSR(immediate), and hints 1155 #define INSN(NAME, decode) \ 1156 void NAME(Condition cond = C_DFLT) { \ 1157 starti; \ 1158 f(cond, 31, 28), f(0b001100100000, 27, 16), f(0b11110000, 15, 8); \ 1159 f(decode, 7, 0); \ 1160 } 1161 INSN(nop, 0b000); 1162 INSN(yield, 0b001); 1163 INSN(wfe, 0b010); 1164 INSN(wfi, 0b011); 1165 INSN(sev, 0b100); 1166 void dbg(int dbg_hint, Condition cond = C_DFLT) { 1167 f(cond, 31, 28), f(0b001100100000, 27, 16), f(0b11110000, 15, 8); 1168 f(0b1111, 7, 4); f(dbg_hint, 3, 0); 1169 } 1170 #undef INSN 1171 1172 //TODO Misc instructions 1173 void bkpt(unsigned imm) { 1174 starti; 1175 f(AL, 31, 28), f(0b00010010, 27, 20); 1176 f(imm >> 4, 19, 8), f(0b0111, 7, 4), f(imm & 0xf, 3, 0); 1177 } 1178 void hlt(unsigned imm) { 1179 bkpt(imm); 1180 // FIXME This seemed like the best option! 1181 } 1182 1183 // Load/store register (all modes) 1184 void load_store_instr(Register Rt, const Address &adr, int op, int op2, int a, int b, 1185 Condition cond) { 1186 starti; 1187 f(cond, 31, 28), f(op, 27, 25), f(a, 22), f(b, 20); 1188 if(op2 >= 0) 1189 f(op2, 7, 4); 1190 //Destination 1191 rf(Rt, 12); 1192 adr.encode(current, code_section(), pc()); 1193 } 1194 1195 bool encodeable(int decode, address dest) { 1196 long offset = dest - pc(); 1197 switch(decode) { 1198 case 0b010: 1199 // LDR, LDRB, STR, STRB 1200 return uabs(offset) < (1 << 12); 1201 case 0b000: 1202 //LDRD, LDRH, LDRSB, LDRSH, STRH, STRD 1203 return uabs(offset) < (1 << 8); 1204 default: 1205 ShouldNotReachHere(); 1206 } 1207 return false; 1208 } 1209 1210 1211 #define INSN_INT(NAME, op, op2, a, b, isload) \ 1212 void NAME(Register Rt, address dest, Condition cond = C_DFLT) { \ 1213 if(encodeable(op, dest)) { /* Plan A */ \ 1214 long offset = dest - pc(); \ 1215 NAME(Rt, Address(r15_pc, offset), cond); \ 1216 } else if(isload){ /* Plan B */ \ 1217 /* TODO check we don't have to relocate this*/ \ 1218 mov_immediate(Rt, (uint32_t)dest, cond, false); \ 1219 NAME(Rt, Address(Rt, 0), cond); \ 1220 } else { /* There is no plan C */ \ 1221 ShouldNotReachHere(); \ 1222 } \ 1223 } \ 1224 void NAME(Register Rt, address dest, relocInfo::relocType rtype, \ 1225 Condition cond = C_DFLT) { \ 1226 guarantee(rtype == relocInfo::internal_word_type, \ 1227 "only internal_word_type relocs make sense here"); \ 1228 NAME(Rt, InternalAddress(dest), cond); \ 1229 } \ 1230 void NAME(Register Rt, Label &L, Condition cond = C_DFLT) { \ 1231 wrap_label(Rt, L, cond, &Assembler::NAME); \ 1232 } 1233 1234 #define INSN(NAME, op, op2, a, b, isload) \ 1235 void NAME(Register Rt, const Address &adr, Condition cond = C_DFLT) { \ 1236 load_store_instr(Rt, adr, op, op2, a, b, cond); \ 1237 } \ 1238 INSN_INT(NAME, op, op2, a, b, isload); 1239 INSN(ldr, 0b010, -1, 0, 1, 1); 1240 INSN(ldrb, 0b010, -1, 1, 1, 1); 1241 1242 INSN(ldrsb, 0b000, 0b1101, 0, 1, 1); 1243 INSN(ldrh, 0b000, 0b1011, 0, 1, 1); 1244 INSN(ldrsh, 0b000, 0b1111, 0, 1, 1); 1245 1246 INSN(str, 0b010, -1, 0, 0, 0); 1247 INSN(strb, 0b010, -1, 1, 0, 0); 1248 INSN(strh, 0b000, 0b1011, 0, 0, 0); 1249 //Note LDRD & STRD are defined with the load/store multiple instructions 1250 1251 //TODO Need to introduce ldrsb ldrsh - then check that the encoding works properly! 1252 #undef INSN 1253 1254 1255 //Synchronization primitives 1256 void sync_instr(int decode, Register Ra, Register Rb, Register Rc, Register Rd, 1257 Condition cond) { 1258 starti; 1259 f(cond, 31, 28), f(0b0001, 27, 24), f(decode, 23, 20), rf(Ra, 16), rf(Rb, 12); 1260 rf(Rc, 8), f(0b1001, 7, 4), rf(Rd, 0); 1261 } 1262 1263 #define INSN(NAME, decode) \ 1264 void NAME(Register Rd, Register Rt, Register Rn, Condition cond = C_DFLT) { \ 1265 assert(r15_pc != Rn, "Unpredictable"); \ 1266 sync_instr(decode, Rn, Rd, ONES_ADDR_REG, Rt, cond); \ 1267 } \ 1268 void NAME(Register Rd, Register Rt, Address a, Condition cond = C_DFLT) { \ 1269 assert(a.get_mode() == Address::imm, "must be"); \ 1270 assert(a.offset() == 0, "unsupported"); \ 1271 NAME(Rd, Rt, a.base(), cond); \ 1272 } 1273 INSN( strex, 0b1000); 1274 INSN(strexd, 0b1010); 1275 INSN(strexb, 0b1100); 1276 INSN(strexh, 0b1110); 1277 #undef INSN 1278 1279 #define INSN(NAME, decode) \ 1280 void NAME(Register Rt, Register Rn, Condition cond = C_DFLT) { \ 1281 assert(r15_pc != Rn, "Unpredictable"); \ 1282 sync_instr(decode, Rn, Rt, ONES_ADDR_REG, ONES_ADDR_REG, cond); \ 1283 } \ 1284 void NAME(Register Rt, Address a, Condition cond = C_DFLT) { \ 1285 assert(a.get_mode() == Address::imm, "must be"); \ 1286 assert(a.offset() == 0, "unsupported"); \ 1287 NAME(Rt, a.base(), cond); \ 1288 } 1289 INSN(ldrex, 0b1001); 1290 INSN(ldrexd, 0b1011); 1291 INSN(ldrexb, 0b1101); 1292 INSN(ldrexh, 0b1111); 1293 #undef INSN 1294 1295 // Media instructions 1296 void media_instr(int decode, int decode2, Condition cond) { 1297 f(cond, 31, 28), f(0b011, 27, 25), f(decode, 24, 20); 1298 f(decode2, 7, 5), f(1, 4); 1299 } 1300 1301 #define INSN(NAME, decode, decode2) \ 1302 void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \ 1303 starti; \ 1304 media_instr(0b00000 | decode, decode2, cond); \ 1305 rf(Rn, 16), rf(Rd, 12), f(0b1111, 11, 8), rf(Rm, 0); \ 1306 } 1307 INSN(sadd16, 0b01, 0b000); 1308 INSN(sasx, 0b01, 0b001); 1309 INSN(ssax, 0b01, 0b010); 1310 INSN(ssub16, 0b01, 0b011); 1311 INSN(sadd8, 0b01, 0b100); 1312 INSN(ssub8, 0b01, 0b111); 1313 //Saturating 1314 INSN(qadd16, 0b10, 0b000); 1315 INSN(qasx, 0b10, 0b001); 1316 INSN(qsax, 0b10, 0b010); 1317 INSN(qsub16, 0b10, 0b011); 1318 INSN(qadd8, 0b10, 0b100); 1319 INSN(qsub8, 0b10, 0b111); 1320 //Halving 1321 INSN(shadd16, 0b11, 0b000); 1322 INSN(shasx, 0b11, 0b001); 1323 INSN(shsax, 0b11, 0b010); 1324 INSN(shsub16, 0b11, 0b011); 1325 INSN(shadd8, 0b11, 0b100); 1326 INSN(shsub8, 0b11, 0b111); 1327 1328 //Now unsigned 1329 INSN(uadd16, 0b101, 0b000); 1330 INSN(uasx, 0b101, 0b001); 1331 INSN(usax, 0b101, 0b010); 1332 INSN(usub16, 0b101, 0b011); 1333 INSN(uadd8, 0b101, 0b100); 1334 INSN(usub8, 0b101, 0b111); 1335 //Saturating 1336 INSN(uqadd16, 0b110, 0b000); 1337 INSN(uqasx, 0b110, 0b001); 1338 INSN(uqsax, 0b110, 0b010); 1339 INSN(uqsub16, 0b110, 0b011); 1340 INSN(uqadd8, 0b110, 0b100); 1341 INSN(uqsub8, 0b110, 0b111); 1342 //Halving 1343 INSN(uhadd16, 0b111, 0b000); 1344 INSN(uhasx, 0b111, 0b001); 1345 INSN(uhsax, 0b111, 0b010); 1346 INSN(uhsub16, 0b111, 0b011); 1347 INSN(uhadd8, 0b111, 0b100); 1348 INSN(uhsub8, 0b111, 0b111); 1349 #undef INSN 1350 1351 //Packing, unpacking, saturation and reversal 1352 // Note rotation can only be one of ROR #0 ROR #8 ROR #16 ROR #24 1353 void extend_instr(int decode, int decode2, int decode3, Register Rd, Register Rn, 1354 Register Rm, shift_op shift, Condition cond) { 1355 starti; 1356 assert(0 == shift.shift() || 1357 shift_op::ROR == shift.kind(), "Only ROR may be used for op"); 1358 // All zero shifts are mapped to LSL #0 1359 int shift_enc = 0; 1360 switch(shift.shift()) { 1361 case 0: break; 1362 case 8: shift_enc = 1; break; 1363 case 16: shift_enc = 2; break; 1364 case 24: shift_enc = 3; break; 1365 default: assert(false, "Invalid shift quantity"); 1366 } 1367 media_instr(0b01000 | decode, decode2, cond); 1368 rf(Rn, 16), rf(Rd, 12), f(shift_enc, 11, 10), f(decode3, 9, 8), rf(Rm, 0); 1369 } 1370 void extend_instr(int decode, int decode2, int decode3, Register Rd, Register Rn, 1371 unsigned imm, Condition cond) { 1372 starti; 1373 media_instr(0b01000 | decode, decode2, cond); 1374 rf(Rn, 0), rf(Rd, 12), f(decode3, 11, 8), f(imm, 19, 16); 1375 } 1376 1377 #define INSN(NAME, decode, decode2) \ 1378 void NAME(Register Rd, Register Rn, Register Rm, shift_op shift = ::ror(), \ 1379 Condition cond = C_DFLT) { \ 1380 assert(0xf != Rn->encoding_nocheck(), "Rn = pc makes different instruction"); \ 1381 extend_instr(decode, decode2, 0b00, Rd, Rn, Rm, shift, cond); \ 1382 } 1383 INSN(sxtab16, 0b000, 0b011); 1384 INSN(sxtab, 0b010, 0b011); 1385 INSN(sxtah, 0b011, 0b011); 1386 INSN(uxtab16, 0b100, 0b011); 1387 INSN(uxtab, 0b110, 0b011); 1388 INSN(uxtah, 0b111, 0b011); 1389 #undef INSN 1390 1391 #define INSN(NAME, decode, decode2) \ 1392 void NAME(Register Rd, Register Rm, shift_op shift = ::ror(), \ 1393 Condition cond = C_DFLT) { \ 1394 extend_instr(decode, decode2, 0b00, Rd, ONES_ADDR_REG, Rm, shift, cond); \ 1395 } 1396 INSN(sxtb16, 0b000, 0b011); 1397 INSN(sxtb, 0b010, 0b011); 1398 INSN(sxth, 0b011, 0b011); 1399 INSN(uxtb16, 0b100, 0b011); 1400 INSN(uxtb, 0b110, 0b011); 1401 INSN(uxth, 0b111, 0b011); 1402 #undef INSN 1403 1404 #define INSN(NAME, decode, decode2) \ 1405 void NAME(Register Rd, unsigned imm, Register Rn, Condition cond = C_DFLT) { \ 1406 extend_instr(decode, decode2, 0b1111, Rd, Rn, imm, cond); \ 1407 } 1408 INSN(usat16, 0b110, 0b001); 1409 #undef INSN 1410 1411 //Reverse instructions 1412 #define INSN(NAME, decode, decode2) \ 1413 void NAME(Register Rd, Register Rm, Condition cond = C_DFLT) { \ 1414 extend_instr(decode, decode2, 0b11, Rd, ONES_ADDR_REG, Rm, ::ror(24), cond); \ 1415 } 1416 INSN(rev, 0b011, 0b001); 1417 INSN(rev16, 0b011, 0b101); 1418 INSN(rbit, 0b111, 0b001); 1419 INSN(revsh, 0b111, 0b101); 1420 #undef INSN 1421 1422 // Signed multiply, signed and unsigned divide 1423 #define INSN(NAME, decode, decode2) \ 1424 void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \ 1425 starti; \ 1426 media_instr(0b10000 | decode, decode2, cond); \ 1427 rf(Rd, 16), f(0b1111, 15, 12), rf(Rm, 8), rf(Rn, 0); \ 1428 } 1429 INSN(sdiv, 0b001, 0b000); 1430 INSN(udiv, 0b011, 0b000); 1431 INSN(smuad, 0b000, 0b000); 1432 INSN(smuadx, 0b000, 0b001); 1433 INSN(smusd, 0b000, 0b010); 1434 INSN(smusdx, 0b000, 0b011); 1435 INSN(smmul, 0b101, 0b000); 1436 INSN(smmulr, 0b101, 0b001); 1437 //TODO ALL THE REST! 1438 #undef INSN 1439 1440 // Remainder of things 1441 #define INSN(NAME, decode, decode2) \ 1442 void NAME(Register Rd, Register Rn, int lsb, int width, \ 1443 Condition cond = C_DFLT) { \ 1444 starti; \ 1445 assert(lsb >= 0 && lsb < 32, "lsb out of range"); \ 1446 assert(width > 0 && width <= 32 - lsb, "width out of range"); \ 1447 media_instr(decode, decode2, cond); \ 1448 f(width - 1, 20, 16), rf(Rd, 12), f(lsb, 11, 7), rf(Rn, 0); \ 1449 } 1450 INSN(sbfx, 0b11010, 0b010); 1451 INSN(ubfx, 0b11110, 0b010); 1452 #undef INSN 1453 1454 void bfi(Register Rd, Register Rn, int lsb, int width, Condition cond = C_DFLT) { 1455 assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu"); 1456 int msb = lsb + width - 1; 1457 assert(lsb >= 0 && lsb < 32, "lsb out of range"); 1458 assert(msb < 32 && msb >= lsb, "width out of range"); 1459 starti; 1460 media_instr(0b11100, 0b000, cond); 1461 f(msb, 20, 16), rf(Rd, 12), f(lsb, 11, 7), rf(Rn, 0); 1462 } 1463 1464 void bfc(Register Rd, int lsb, int width, Condition cond = C_DFLT) { 1465 assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu"); 1466 int msb = lsb + width - 1; 1467 assert(lsb >= 0 && lsb < 32, "lsb out of range"); 1468 assert(msb < 32 && msb >= lsb, "width out of range"); 1469 starti; 1470 media_instr(0b11100, 0b000, cond); 1471 f(msb, 20, 16), rf(Rd, 12), f(lsb, 11, 7), f(0b1111, 3, 0); 1472 } 1473 1474 void clz(Register Rd, Register Rm, Condition cond = C_DFLT) { 1475 assert(Rd != r15_pc && Rm != r15_pc, "must be"); 1476 starti; 1477 f(cond, 31, 28), f(0b000101101111, 27, 16), rf(Rd, 12); 1478 f(0b11110001, 11, 4), rf(Rm, 0); 1479 } 1480 1481 //Branch, branch with link, and block data transfer 1482 1483 void block_imm_instr(int decode, int w, Register Rn, unsigned regset, 1484 Condition cond) { 1485 starti; 1486 f(cond, 31, 28), f(0b10, 27, 26), f(decode | (w << 1), 25, 20); 1487 rf(Rn, 16), f(regset, 15, 0); 1488 } 1489 #define INSN(NAME, decode) \ 1490 void NAME(Register Rn, unsigned regset, bool wb = true, Condition cond = C_DFLT) { \ 1491 block_imm_instr(decode, wb, Rn, regset, cond); \ 1492 } 1493 INSN(stmda, 0b000000); 1494 INSN(stmed, 0b000000); 1495 1496 INSN(ldmda, 0b000001); 1497 INSN(ldmfa, 0b000001); 1498 1499 //INSN(stm, 0b001000); 1500 INSN(stmia, 0b001000); 1501 INSN(stmea, 0b001000); 1502 1503 //INSN(ldm, 0b001001); 1504 INSN(ldmia, 0b001001); 1505 INSN(ldmfd, 0b001001); 1506 1507 INSN(stmdb, 0b010000); 1508 INSN(stmfd, 0b010000); 1509 1510 INSN(ldmdb, 0b010001); 1511 INSN(ldmea, 0b010001); 1512 1513 INSN(stmib, 0b011000); 1514 INSN(stmfa, 0b011000); 1515 1516 INSN(ldmib, 0b011001); 1517 INSN(ldmed, 0b011001); 1518 #undef INSN 1519 1520 unsigned count_bits(unsigned val); 1521 bool can_ldst_multiple( unsigned regset, const Address& adr); 1522 1523 //NOTE!! Have repurposed stm and ldm for auto dispatch instructions 1524 #define INSN(NAME, PREFIX) \ 1525 void NAME(unsigned regset, const Address& adr, Condition cond = C_DFLT) { \ 1526 assert(can_ldst_multiple(regset, adr), "Can't do anything with this!"); \ 1527 int offset = adr.offset(); \ 1528 switch(adr.get_wb_mode()) { \ 1529 case Address::pre: \ 1530 if(offset > 0) PREFIX##mib(adr.base(), regset, true, cond); \ 1531 else PREFIX##mdb(adr.base(), regset, true, cond); \ 1532 break; \ 1533 case Address::post: \ 1534 if(offset > 0) PREFIX##mia(adr.base(), regset, true, cond); \ 1535 else PREFIX##mda(adr.base(), regset, offset != 0, cond); \ 1536 break; \ 1537 case Address::off: \ 1538 if(offset > 0) PREFIX##mib(adr.base(), regset, false, cond); \ 1539 else if(!offset) PREFIX##mia(adr.base(), regset, false, cond); \ 1540 else PREFIX##mdb(adr.base(), regset, false, cond); \ 1541 break; \ 1542 default: \ 1543 ShouldNotReachHere(); \ 1544 } \ 1545 } 1546 INSN(ldm, ld); 1547 INSN(stm, st); 1548 #undef INSN 1549 1550 //Made push and pop operate on full descending stacks 1551 #define INSN(NAME, CNAME) \ 1552 inline void NAME(unsigned regset, Condition cond = C_DFLT) { \ 1553 CNAME(r13, regset, true, cond); \ 1554 } 1555 INSN(pop, ldmia); 1556 INSN(push, stmdb); 1557 #undef INSN 1558 1559 public: 1560 1561 #define INSN(NAME, PREFIX, op, op2, a, b, isload) \ 1562 void NAME(Register Rt, const Address& adr, Condition cond = C_DFLT) { \ 1563 load_store_instr(Rt, adr, op, op2, a, b, cond); \ 1564 } \ 1565 INSN_INT(NAME, op, op2, a, b, isload); 1566 1567 INSN(ldrd, ld, 0b000, 0b1101, 0, 0, 1); 1568 INSN(strd, st, 0b000, 0b1111, 0, 0, 0); 1569 #undef INSN 1570 #undef INSN_INT 1571 1572 // Branches 1573 1574 // For immediate branches: 1575 // The maximum range of a branch is fixed for the aarch32 1576 // architecture. In debug mode we shrink it in order to test 1577 // trampolines, but not so small that branches in the interpreter 1578 // are out of range. Compiler2 is ported in the assumption that code cache is 1579 // always reachable with immediate branch, so cannot restrict the size 1580 static const unsigned long branch_range = 1581 COMPILER2_PRESENT(32 * M) NOT_COMPILER2(NOT_DEBUG(32 * M) DEBUG_ONLY(2 * M)); 1582 static bool reachable_from_branch_at(address branch, address target) { 1583 return uabs(target - branch) < branch_range; 1584 } 1585 1586 void branch_imm_instr(int decode, address dest, Condition cond) { 1587 starti; 1588 // Correct PC for as it will be when executing this instruction 1589 int offset = (dest - (pc() + 8)) >> 2; 1590 assert(reachable_from_branch_at(pc(), dest), "branch target unreachable"); 1591 f(cond, 31, 28), f(decode, 27, 24), sf(offset, 23, 0); 1592 } 1593 1594 void branch_reg_instr(int decode, Register Rm, Condition cond) { 1595 starti; 1596 f(cond, 31, 28), f(0b00010010, 27, 20); 1597 f(0b111111111111, 19, 8), f(decode, 7, 4), rf(Rm, 0); 1598 } 1599 1600 #define INSN(NAME, decode_imm, decode_reg) \ 1601 void NAME(Register Rm, Condition cond = C_DFLT) { \ 1602 branch_reg_instr(decode_reg, Rm, cond); \ 1603 } \ 1604 void NAME(address dest, Condition cond = C_DFLT) { \ 1605 branch_imm_instr(decode_imm, dest, cond); \ 1606 } \ 1607 void NAME(Label &L, Condition cond = C_DFLT) { \ 1608 wrap_label(L, cond, &Assembler::NAME); \ 1609 } \ 1610 void NAME(const Address &dest, Condition cond = C_DFLT) { \ 1611 code_section()->relocate(pc(), dest.rspec()); \ 1612 NAME(dest.target(), cond); \ 1613 } 1614 //TODO assert type of address 1615 INSN(b, 0b1010, 0b0001); // B & BX 1616 INSN(bl, 0b1011, 0b0011); // BL & BLX 1617 #undef INSN 1618 1619 1620 //TODO Coprocessor instructions, and Supervisor Call 1621 1622 1623 // Unconditional Instructions 1624 enum barrier {OSHST = 0b0010, OSH, 1625 NSHST = 0b0110, NSH, 1626 ISHST = 0b1010, ISH, 1627 ST = 0b1110, SY}; 1628 1629 void sync_instr(int decode, enum barrier option) { 1630 starti; 1631 f(0b11110, 31, 27), f(0b1010111, 26, 20), f(0b111111110000, 19, 8); 1632 f(decode, 7, 4), f(option, 3, 0); 1633 } 1634 void clrex() { 1635 sync_instr(0b0001, SY); 1636 } 1637 void dsb(enum barrier option) { 1638 sync_instr(0b0100, option); 1639 } 1640 void dmb(enum barrier option) { 1641 sync_instr(0b0101, option); 1642 } 1643 void bkpt(); 1644 void isb() { 1645 sync_instr(0b0110, SY); 1646 } 1647 1648 void udf(int imm_16) { 1649 assert((imm_16 >> 16) == 0, "encoding constraint"); 1650 emit_int32(0xe7f000f0 | (imm_16 & 0xfff0) << 8 | (imm_16 & 0xf)); 1651 } 1652 1653 // And the relevant instructions for ARMv6. 1654 1655 // MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>} 1656 void mcr(int cpc_dex, int opc1, Register Rt, int cpc_reg_dex1, 1657 int cpc_reg_dex2, int opc2, Condition cond = C_DFLT) { 1658 starti; 1659 f(cond, 31, 28), f(0b1110, 27, 24), f(opc1, 23, 21), f(0, 20); 1660 f(cpc_reg_dex1, 19, 16), rf(Rt, 12), f(cpc_dex, 11, 8); 1661 f(opc2, 7, 5), f(1, 4), f(cpc_reg_dex2, 3, 0); 1662 } 1663 1664 // These instructions do not read the value of the register passed, 1665 // can be any. Chosen r0. 1666 void cp15dmb(Condition cond = C_DFLT) { 1667 mcr(15, 0, r0, 7, 10, 5, cond); 1668 } 1669 1670 void cp15dsb(Condition cond = C_DFLT) { 1671 mcr(15, 0, r0, 7, 10, 4, cond); 1672 } 1673 1674 void cp15isb(Condition cond = C_DFLT) { 1675 mcr(15, 0, r0, 7, 5, 4, cond); 1676 } 1677 1678 enum Membar_mask_bits { 1679 // We can use ISH for a barrier because the ARM ARM says "This 1680 // architecture assumes that all Processing Elements that use the 1681 // same operating system or hypervisor are in the same Inner 1682 // Shareable shareability domain." 1683 StoreStore = ISHST, 1684 LoadStore = ISH, //ISHLD, Changed to 1685 LoadLoad = ISH, //ISHLD, 1686 StoreLoad = ISH, 1687 AnyAny = ISH 1688 }; 1689 1690 void mrs(Register Rd, Condition cond = C_DFLT) { 1691 starti; 1692 f(cond, 31, 28), f(0b00010, 27, 23), f(0, 22), f(0b00, 21, 20), f(0b1111, 19, 16); 1693 rf(Rd, 12), f(0b000000000000, 11, 0); 1694 } 1695 1696 void msr(Register Rn, bool nzcvq = true, bool g = true, Condition cond = C_DFLT) { 1697 starti; 1698 f(cond, 31, 28), f(0b00010, 27, 23), f(0, 22), f(0b10, 21, 20); 1699 f(nzcvq ? 1 : 0, 19), f(g ? 1 : 0, 18), f(0b00, 17, 16); 1700 f(0b111100000000, 15, 4), rf(Rn, 0); 1701 } 1702 1703 // Floating point operations 1704 1705 enum fpscr_cond { FP_EQ = 0b0110 << 28, 1706 FP_LT = 0b1000 << 28, 1707 FP_GT = 0b0010 << 28, 1708 FP_UN = 0b0011 << 28, 1709 FP_MASK = 0b1111 << 28 }; 1710 1711 void fp_instr_base(bool is64bit, Condition cond) { 1712 f(cond, 31, 28), f(0b1110, 27, 24), f(0b101, 11, 9), f(is64bit, 8), f(0, 4); 1713 } 1714 1715 void fp_rencode(FloatRegister reg, bool is64bit, int base, int bit) { 1716 int reg_val = reg->encoding_nocheck(); 1717 if(!is64bit) { 1718 f( reg_val >> 1, base + 3, base); 1719 f( reg_val & 1, bit); 1720 } else { 1721 f( reg_val & 0xf, base + 3, base); 1722 f( reg_val >> 4, bit); 1723 } 1724 } 1725 1726 void fp_instr(int decode, int op, bool is64bit, FloatRegister Rd, FloatRegister Rn, 1727 FloatRegister Rm, Condition cond) { 1728 fp_instr_base(is64bit, cond); 1729 f(decode, 23, 20), f(op, 6); 1730 // Register encoding is a bit involved 1731 // double register passed (see 'd0'-'dN' encoding), not reencode it's number 1732 fp_rencode(Rn, false, 16, 7); 1733 fp_rencode(Rd, false, 12, 22); 1734 fp_rencode(Rm, false, 0, 5); 1735 } 1736 1737 #define INSN(NAME, decode, op, is64bit) \ 1738 void NAME(FloatRegister Rd, FloatRegister Rn, FloatRegister Rm, \ 1739 Condition cond = C_DFLT) { \ 1740 starti; \ 1741 fp_instr(decode, op, is64bit, Rd, Rn, Rm, cond); \ 1742 } 1743 INSN(vmla_f32, 0b0000, 0, 0); 1744 INSN(vmla_f64, 0b0000, 0, 1); 1745 INSN(vmls_f32, 0b0000, 1, 0); 1746 INSN(vmls_f64, 0b0000, 1, 1); 1747 1748 INSN(vnmla_f32, 0b0001, 1, 0); 1749 INSN(vnmla_f64, 0b0001, 1, 1); 1750 INSN(vnmls_f32, 0b0001, 0, 0); 1751 INSN(vnmls_f64, 0b0001, 0, 1); 1752 INSN(vnmul_f32, 0b0010, 1, 0); 1753 INSN(vnmul_f64, 0b0010, 1, 1); 1754 INSN(vmul_f32, 0b0010, 0, 0); 1755 INSN(vmul_f64, 0b0010, 0, 1); 1756 1757 INSN(vadd_f32, 0b0011, 0, 0); 1758 INSN(vadd_f64, 0b0011, 0, 1); 1759 INSN(vsub_f32, 0b0011, 1, 0); 1760 INSN(vsub_f64, 0b0011, 1, 1); 1761 1762 INSN(vdiv_f32, 0b1000, 0, 0); 1763 INSN(vdiv_f64, 0b1000, 0, 1); 1764 1765 INSN(vfnma_f32, 0b1001, 1, 0); 1766 INSN(vfnma_f64, 0b1001, 1, 1); 1767 INSN(vfnms_f32, 0b1001, 0, 0); 1768 INSN(vfnms_f64, 0b1001, 0, 1); 1769 1770 INSN(vfma_f32, 0b1010, 0, 0); 1771 INSN(vfma_f64, 0b1010, 0, 1); 1772 INSN(vfms_f32, 0b1010, 1, 0); 1773 INSN(vfms_f64, 0b1010, 1, 1); 1774 #undef INSN 1775 1776 1777 void vmov_imm(FloatRegister Rd, unsigned imm, bool is64bit, Condition cond); 1778 void vmov_imm(FloatRegister Rd, unsigned imm); 1779 void vmov_imm_zero(FloatRegister Rd, bool is64bit, Condition cond); 1780 1781 unsigned encode_float_fp_imm(float imm_f); 1782 1783 void vmov_f32(FloatRegister Rd, float imm, Condition cond = C_DFLT) { 1784 vmov_imm(Rd, encode_float_fp_imm(imm), false, cond); 1785 } 1786 1787 unsigned encode_double_fp_imm(double imm_f); 1788 1789 void vmov_f64(FloatRegister Rd, double imm, Condition cond = C_DFLT) { 1790 bool positive_zero = (imm == 0.0) && !signbit(imm); 1791 if(positive_zero) vmov_imm_zero(Rd, true, cond); 1792 else vmov_imm(Rd, encode_double_fp_imm(imm), true, cond); 1793 } 1794 1795 #define INSN(NAME, decode, op, is64bit) \ 1796 void NAME(FloatRegister Rd, FloatRegister Rm, Condition cond = C_DFLT) { \ 1797 starti; \ 1798 fp_instr_base(is64bit, cond); \ 1799 f(0b1011, 23, 20), f(decode, 19, 16), f(op, 7, 6), f(0b00, 5, 4); \ 1800 /* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \ 1801 fp_rencode(Rd, false, 12, 22); \ 1802 fp_rencode(Rm, false, 0, 5); \ 1803 } 1804 INSN(vmov_f32, 0b0000, 0b01, 0); 1805 INSN(vmov_f64, 0b0000, 0b01, 1); 1806 INSN(vabs_f32, 0b0000, 0b11, 0); 1807 INSN(vabs_f64, 0b0000, 0b11, 1); 1808 INSN(vneg_f32, 0b0001, 0b01, 0); 1809 INSN(vneg_f64, 0b0001, 0b01, 1); 1810 INSN(vsqrt_f32, 0b0001, 0b11, 0); 1811 INSN(vsqrt_f64, 0b0001, 0b11, 1); 1812 #undef INSN 1813 1814 //ARM -> FP, FP -> ARM 1815 // NOTE - Have only implemented the double precision variant as only operating on 1816 // double registers - can still be used to copy single precision 1817 void vmov64_instr_base(FloatRegister Rm, Register Rt, Register Rt2, int op, 1818 Condition cond) { 1819 starti; 1820 f(cond, 31, 28), f(0b1100010, 27, 21), f(op, 20); 1821 rf(Rt2, 16), rf(Rt, 12), f(0b101100, 11, 6), f(1, 4); 1822 // double register passed (see 'd0'-'dN' encoding), not reencode it's number 1823 fp_rencode(Rm, false, 0, 5); 1824 } 1825 1826 void vmov_f64(FloatRegister Rm, Register Rt, Register Rt2, Condition cond = C_DFLT) { 1827 vmov64_instr_base(Rm, Rt, Rt2, 0, cond); 1828 } 1829 void vmov_f64(Register Rt, Register Rt2, FloatRegister Rm, Condition cond = C_DFLT) { 1830 vmov64_instr_base(Rm, Rt, Rt2, 1, cond); 1831 } 1832 1833 void vmov_f32(FloatRegister Rn, Register Rt, Condition cond = C_DFLT) { 1834 starti; 1835 fp_instr_base(false, cond); 1836 f(0b000, 23, 21), f(0, 20); 1837 rf(Rt, 12), f(0b101000010000, 11, 0); 1838 // double register passed (see 'd0'-'dN' encoding), not reencode it's number 1839 fp_rencode(Rn, false, 16, 7); 1840 } 1841 void vmov_f32(Register Rt, FloatRegister Rn, Condition cond = C_DFLT) { 1842 starti; 1843 fp_instr_base(false, cond); 1844 f(0b000, 23, 21), f(1, 20); 1845 rf(Rt, 12), f(0b101000010000, 11, 0); 1846 // double register passed (see 'd0'-'dN' encoding), not reencode it's number 1847 fp_rencode(Rn, false, 16, 7); 1848 } 1849 1850 // Floating-point comparison 1851 #define INSN(NAME, E, is64bit) \ 1852 void NAME(FloatRegister Rd, int imm, Condition cond = C_DFLT) { \ 1853 assert(0 == imm, "vector compare can only be with another vector or zero"); \ 1854 starti; \ 1855 fp_instr_base(is64bit, cond); \ 1856 f(0b10110101, 23, 16), f(E, 7), f(0b1000000, 6, 0); \ 1857 /* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \ 1858 fp_rencode(Rd, false, 12, 22); \ 1859 } \ 1860 void NAME(FloatRegister Vd, FloatRegister Vm, Condition cond = C_DFLT) { \ 1861 starti; \ 1862 fp_instr_base(is64bit, cond); \ 1863 f(0b10110100, 23, 16), f(E, 7), f(1, 6), f(0, 4); \ 1864 /* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \ 1865 fp_rencode(Vd, false, 12, 22), fp_rencode(Vm, false, 0, 5); \ 1866 } 1867 INSN(vcmpe_f64, 1, 1); 1868 INSN(vcmpe_f32, 1, 0); 1869 INSN( vcmp_f64, 0, 1); 1870 INSN( vcmp_f32, 0, 0); 1871 #undef INSN 1872 1873 //Move FPSCR to ARM register 1874 void vmrs(Register Rt, Condition cond = C_DFLT) { 1875 starti; 1876 f(cond, 31, 28), f(0b111011110001, 27, 16), rf(Rt, 12), f(0b101000010000, 11, 0); 1877 } 1878 1879 //Move ARM register to FPSCR 1880 void vmsr(Register Rt, Condition cond = C_DFLT) { 1881 starti; 1882 f(cond, 31, 28), f(0b111011100001, 27, 16), rf(Rt, 12), f(0b101000010000, 11, 0); 1883 } 1884 1885 // TODO These instructions use round towards zero mode. It is possible 1886 // for the mode to be taken from the FPSCR however it doesn't do it currently 1887 #define INSN(NAME, decode2, b19, op, is64bitRd, is64bitRm, sz) \ 1888 void NAME(FloatRegister Rd, FloatRegister Rm, Condition cond = C_DFLT) { \ 1889 starti; \ 1890 fp_instr_base(sz, cond); \ 1891 f(0b1011, 23, 20), f(b19, 19), f(decode2, 18, 16), f(op, 7), f(0b100, 6, 4); \ 1892 /* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \ 1893 fp_rencode(Rd, false, 12, 22); \ 1894 fp_rencode(Rm, false, 0, 5); \ 1895 } 1896 INSN(vcvt_s32_f32, 0b101, 1, 1, 0, 0, 0); 1897 INSN(vcvt_s32_f64, 0b101, 1, 1, 0, 1, 1); 1898 INSN(vcvt_u32_f32, 0b100, 1, 1, 0, 0, 0); 1899 INSN(vcvt_u32_f64, 0b100, 1, 1, 0, 1, 1); 1900 1901 INSN(vcvt_f64_s32, 0b000, 1, 1, 1, 0, 1); 1902 INSN(vcvt_f64_u32, 0b000, 1, 0, 1, 0, 1); 1903 INSN(vcvt_f32_s32, 0b000, 1, 1, 0, 0, 0); 1904 INSN(vcvt_f32_u32, 0b000, 1, 0, 0, 0, 0); 1905 1906 INSN(vcvt_f32_f64, 0b111, 0, 1, 0, 1, 1); 1907 INSN(vcvt_f64_f32, 0b111, 0, 1, 1, 0, 0); 1908 #undef INSN 1909 1910 //Vector load/store 1911 private: 1912 void fp_ldst_instr(int decode, bool is64bit, const Address& adr, Condition cond); 1913 public: 1914 1915 #define INSN(NAME, decode, is64bit) \ 1916 void NAME(FloatRegister Vd, const Address &adr, Condition cond = C_DFLT) { \ 1917 starti; \ 1918 fp_ldst_instr(decode, is64bit, adr, cond); \ 1919 /* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \ 1920 fp_rencode(Vd, false, 12, 22); \ 1921 } \ 1922 void NAME(FloatRegister Vd, address dest, Condition cond = C_DFLT) { \ 1923 long offset = dest - pc(); \ 1924 NAME(Vd, Address(r15_pc, offset), cond); \ 1925 } \ 1926 void NAME(FloatRegister Vd, address dest, relocInfo::relocType rtype, \ 1927 Condition cond = C_DFLT) { \ 1928 guarantee(rtype == relocInfo::internal_word_type, \ 1929 "only internal_word_type relocs make sense here"); \ 1930 NAME(Vd, InternalAddress(dest), cond); \ 1931 } \ 1932 void NAME(FloatRegister Vd, Label &L, Condition cond = C_DFLT) { \ 1933 wrap_label(Vd, L, cond, &Assembler::NAME); \ 1934 } 1935 INSN(vstr_f64, 0b10000, 1); 1936 INSN(vstr_f32, 0b10000, 0); 1937 INSN(vldr_f64, 0b10001, 1); 1938 INSN(vldr_f32, 0b10001, 0); 1939 #undef INSN 1940 1941 private: 1942 enum fp_mode { ia_wb, ia, db_wb }; 1943 void fp_ldst_mul(Register Rn, uint32_t regset, bool load, bool is64bit, enum fp_mode mode, Condition cond); 1944 public: 1945 #define INSN(NAME, EXT, is64bit, load) \ 1946 inline void NAME##ia##EXT(Register Rn, unsigned regset, bool wb = true, \ 1947 Condition cond = C_DFLT) { \ 1948 fp_ldst_mul(Rn, regset, load, is64bit, \ 1949 (enum fp_mode)( ia_wb + ( wb?0:1 )), cond); \ 1950 } \ 1951 inline void NAME##db##EXT(Register Rn, unsigned regset, Condition cond = C_DFLT) { \ 1952 fp_ldst_mul(Rn, regset, load, is64bit, db_wb, cond); \ 1953 } 1954 INSN(vldm, _f32, 0, 1); 1955 INSN(vldm, _f64, 1, 1); 1956 INSN(vstm, _f32, 0, 0); 1957 INSN(vstm, _f64, 1, 0); 1958 #undef INSN 1959 1960 #undef ZERO_ADDR_REG 1961 #undef ONES_ADDR_REG 1962 1963 /* SIMD extensions 1964 * 1965 * We just use FloatRegister in the following. They are exactly the same 1966 * as SIMD registers. 1967 */ 1968 public: 1969 enum SIMD_Align { 1970 ALIGN_STD = 0b00, ALIGN_64 = 0b01, ALIGN_128 = 0b10, ALIGN_256 = 0b11 1971 }; 1972 // multiple single elements 1973 private: 1974 void simd_ldst(FloatRegister, unsigned type, unsigned size, unsigned xfer_size, 1975 const Address &addr, enum SIMD_Align align, unsigned encode); 1976 public: 1977 #define INSN(NAME, size, encode) \ 1978 inline void NAME(FloatRegister Dd, const Address &addr, enum SIMD_Align align) { \ 1979 simd_ldst(Dd, 0b0111, size, 1, addr, align, encode); \ 1980 } \ 1981 inline void NAME(FloatRegister Dd, FloatRegister Dd1, const Address &addr, \ 1982 enum SIMD_Align align) { \ 1983 assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \ 1984 simd_ldst(Dd, 0b1010, size, 2, addr, align, encode); \ 1985 } \ 1986 inline void NAME(FloatRegister Dd, FloatRegister Dd1, FloatRegister Dd2, \ 1987 const Address &addr, enum SIMD_Align align) { \ 1988 assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \ 1989 assert(Dd1->successor(FloatRegisterImpl::DOUBLE) == Dd2, "Must be consecutive"); \ 1990 simd_ldst(Dd, 0b0110, size, 3, addr, align, encode); \ 1991 } \ 1992 inline void NAME(FloatRegister Dd, FloatRegister Dd1, FloatRegister Dd2, \ 1993 FloatRegister Dd3, const Address &addr, enum SIMD_Align align) { \ 1994 assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \ 1995 assert(Dd1->successor(FloatRegisterImpl::DOUBLE) == Dd2, "Must be consecutive"); \ 1996 assert(Dd2->successor(FloatRegisterImpl::DOUBLE) == Dd3, "Must be consecutive"); \ 1997 simd_ldst(Dd, 0b0010, size, 4, addr, align, encode); \ 1998 } 1999 INSN(vld1_8, 0b00, 0b10); 2000 INSN(vld1_16, 0b01, 0b10); 2001 INSN(vld1_32, 0b10, 0b10); 2002 INSN(vld1_64, 0b11, 0b10); 2003 INSN(vst1_8, 0b00, 0b00); 2004 INSN(vst1_16, 0b01, 0b00); 2005 INSN(vst1_32, 0b10, 0b00); 2006 INSN(vst1_64, 0b11, 0b00); 2007 #undef INSN 2008 2009 // single element to one lane 2010 private: 2011 void simd_ldst_single(FloatRegister Rd, unsigned size, unsigned index, 2012 const Address &addr, bool align, unsigned encode); 2013 public: 2014 #define INSN(NAME, size, encode) \ 2015 inline void NAME(FloatRegister Dd, unsigned index, const Address &addr, bool align) { \ 2016 simd_ldst_single(Dd, size, index, addr, align, encode); \ 2017 } 2018 INSN(vld1_8, 0b00, 0b10); 2019 INSN(vld1_16, 0b01, 0b10); 2020 INSN(vld1_32, 0b10, 0b10); 2021 INSN(vst1_8, 0b00, 0b00); 2022 INSN(vst1_16, 0b01, 0b00); 2023 INSN(vst1_32, 0b10, 0b00); 2024 #undef INSN 2025 2026 private: 2027 void simd_vmov(FloatRegister Dd, unsigned index, Register Rt, bool advsimd, 2028 unsigned index_bits, unsigned bit20, unsigned opc, Condition cond); 2029 public: 2030 #define INSN(NAME, advsimd, opc, index_bits) \ 2031 inline void NAME(FloatRegister Rd, unsigned index, Register Rt, \ 2032 Condition cond = Assembler::AL) { \ 2033 simd_vmov(Rd, index, Rt, advsimd, index_bits, 0, opc, cond); \ 2034 } 2035 INSN(vmov_8, true, 0b1000, 2); 2036 INSN(vmov_16, true, 0b0001, 1); 2037 INSN(vmov_32, false, 0b0000, 0); 2038 #undef INSN 2039 #define INSN(NAME, advsimd, opc, index_bits) \ 2040 inline void NAME(Register Rt, FloatRegister Rd, unsigned index, \ 2041 Condition cond = Assembler::AL) { \ 2042 simd_vmov(Rd, index, Rt, advsimd, index_bits, 1, opc, cond); \ 2043 } 2044 INSN(vmov_8s, true, 0b01000, 3); 2045 INSN(vmov_16s, true, 0b00001, 2); 2046 INSN(vmov_8u, true, 0b11000, 3); 2047 INSN(vmov_16u, true, 0b10001, 2); 2048 INSN(vmov_32, false, 0b00000, 1); 2049 #undef INSN 2050 2051 private: 2052 void simd_vmov(FloatRegister Dd, unsigned imm, unsigned q, unsigned op_cmode); 2053 public: 2054 #define INSN(NAME, q, op_cmode) \ 2055 inline void NAME(FloatRegister Dd, unsigned imm) { \ 2056 simd_vmov(Dd, imm, q, op_cmode); \ 2057 } 2058 INSN(vmov_64_8, 0, 0b01110); 2059 INSN(vmov_64_16, 0, 0b01000); 2060 INSN(vmov_64_32, 0, 0b00000); 2061 INSN(vmov_128_8, 1, 0b01110); 2062 INSN(vmov_128_16, 1, 0b01000); 2063 INSN(vmov_128_32, 1, 0b00000); 2064 #undef INSN 2065 2066 private: 2067 void simd_logicalop(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, unsigned q, 2068 unsigned a, unsigned b, unsigned u, unsigned c); 2069 public: 2070 #define INSN(NAME, q, a, b, u, c) \ 2071 inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \ 2072 simd_logicalop(Dd, Dn, Dm, q, a, b, u, c); \ 2073 } 2074 INSN(veor_64, 0, 0b0001, 1, 1, 0b00); 2075 INSN(veor_128, 1, 0b0001, 1, 1, 0b00); 2076 INSN(vand_64, 0, 0b0001, 1, 0, 0b00); 2077 INSN(vand_128, 1, 0b0001, 1, 0, 0b00); 2078 INSN(vorr_64, 0, 0b0001, 1, 0, 0b10); 2079 INSN(vorr_128, 1, 0b0001, 1, 0, 0b10); 2080 #undef INSN 2081 2082 // vmov is actually a vorr 2083 #define vmov_64(Dd, Dm) vorr_64(Dd, Dm, Dm) 2084 #define vmov_128(Qd, Qm) vorr_128(Qd, Qm, Qm) 2085 2086 private: 2087 void simd_vmul(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, 2088 unsigned bit24, unsigned bits109, unsigned size, unsigned mul, unsigned bit6); 2089 public: 2090 #define INSN(NAME, bit24, bit9, size, mul, bit6, bit10) \ 2091 inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \ 2092 simd_vmul(Dd, Dn, Dm, bit24, (bit10<<1)|bit9, size, mul, bit6); \ 2093 } 2094 INSN(vmul_64_8, 0, 0, 0b00, 1, 0, 0); 2095 INSN(vmul_64_16, 0, 0, 0b01, 1, 0, 0); 2096 INSN(vmul_64_32, 0, 0, 0b10, 1, 0, 0); 2097 INSN(vmulp_64_8, 1, 0, 0b00, 1, 0, 0); 2098 INSN(vmul_128_8, 0, 0, 0b00, 1, 1, 0); 2099 INSN(vmul_128_16, 0, 0, 0b01, 1, 1, 0); 2100 INSN(vmul_128_32, 0, 0, 0b10, 1, 1, 0); 2101 INSN(vmulp_128_8, 1, 0, 0b00, 1, 1, 0); 2102 INSN(vmull_8s, 0, 0, 0b00, 0, 0, 1); 2103 INSN(vmull_16s, 0, 0, 0b01, 0, 0, 1); 2104 INSN(vmull_32s, 0, 0, 0b10, 0, 0, 1); 2105 INSN(vmull_8u, 1, 0, 0b00, 0, 0, 1); 2106 INSN(vmull_16u, 1, 0, 0b01, 0, 0, 1); 2107 INSN(vmull_32u, 1, 0, 0b10, 0, 0, 1); 2108 INSN(vmullp_8, 0, 1, 0b00, 0, 0, 1); 2109 INSN(vmul_64_f32, 1, 0, 0b00, 1, 0, 1); 2110 INSN(vmul_128_f32,1, 0, 0b00, 1, 1, 1); 2111 #undef INSN 2112 2113 private: 2114 void simd_vuzp(FloatRegister Dd, FloatRegister Dm, unsigned size, unsigned q); 2115 public: 2116 #define INSN(NAME, size, q) \ 2117 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2118 simd_vuzp(Dd, Dm, size, q); \ 2119 } 2120 INSN(vuzp_64_8, 0b00, 0); 2121 INSN(vuzp_64_16, 0b01, 0); 2122 INSN(vuzp_64_32, 0b10, 0); 2123 INSN(vuzp_128_8, 0b00, 1); 2124 INSN(vuzp_128_16, 0b01, 1); 2125 INSN(vuzp_128_32, 0b10, 1); 2126 #undef INSN 2127 2128 private: 2129 void simd_vshl(FloatRegister Dd, FloatRegister Dm, unsigned imm, 2130 unsigned q, unsigned u, unsigned encode); 2131 public: 2132 #define INSN(NAME, size, q, u, encode, checkDd) \ 2133 inline void NAME(FloatRegister Dd, FloatRegister Dm, unsigned imm) { \ 2134 assert(!checkDd || (Dd->encoding() & 2) == 0, "Odd register"); \ 2135 unsigned encode_eff = encode; \ 2136 unsigned u_eff = u; \ 2137 imm &= size == 6 ? 0x3f : 0x1f; /* per jvms */ \ 2138 if (imm >= (1u << size)) { /* vshl cannot encode shift by size or more... */ \ 2139 encode_eff = 0b0000; /* .. change to equivalent vshr (actually set to 0) */ \ 2140 u_eff = 1; \ 2141 imm = (1u << size); \ 2142 } \ 2143 simd_vshl(Dd, Dm, imm|(1u<<size), q, u_eff, encode_eff); \ 2144 } 2145 INSN(vshl_64_8, 3, 0, 0, 0b0101, false); 2146 INSN(vshl_64_16, 4, 0, 0, 0b0101, false); 2147 INSN(vshl_64_32, 5, 0, 0, 0b0101, false); 2148 INSN(vshl_64_64, 6, 0, 0, 0b0101, false); 2149 INSN(vshl_128_8, 3, 1, 0, 0b0101, false); 2150 INSN(vshl_128_16, 4, 1, 0, 0b0101, false); 2151 INSN(vshl_128_32, 5, 1, 0, 0b0101, false); 2152 INSN(vshl_128_64, 6, 1, 0, 0b0101, false); 2153 INSN(vshll_8s, 3, 0, 0, 0b1010, true); 2154 INSN(vshll_8u, 3, 0, 1, 0b1010, true); 2155 INSN(vshll_16s, 4, 0, 0, 0b1010, true); 2156 INSN(vshll_16u, 4, 0, 1, 0b1010, true); 2157 INSN(vshll_32s, 5, 0, 0, 0b1010, true); 2158 INSN(vshll_32u, 5, 0, 1, 0b1010, true); 2159 #undef INSN 2160 #define INSN(NAME, size, q, u) \ 2161 inline void NAME(FloatRegister Dd, FloatRegister Dm, unsigned imm) { \ 2162 unsigned encode_eff = 0b0000; \ 2163 imm &= size == 6 ? 0x3f : 0x1f; /* per jvms */ \ 2164 if (imm == 0) { /* vshr cannot encode shift by 0... */ \ 2165 encode_eff = 0b0101; /* ... change equivalent vshl */ \ 2166 imm = 1u << size; \ 2167 } else if (imm > (1u << size)) { \ 2168 imm = 1u << size; /* saturate shift */ \ 2169 } else { /* encode the imm per ARM spec */ \ 2170 imm = (1u << size+1) - imm; \ 2171 } \ 2172 simd_vshl(Dd, Dm, imm, q, u, encode_eff); \ 2173 } 2174 INSN(vshr_64_u8, 3, 0, 1); 2175 INSN(vshr_64_u16, 4, 0, 1); 2176 INSN(vshr_64_u32, 5, 0, 1); 2177 INSN(vshr_64_u64, 6, 0, 1); 2178 INSN(vshr_128_u8, 3, 1, 1); 2179 INSN(vshr_128_u16, 4, 1, 1); 2180 INSN(vshr_128_u32, 5, 1, 1); 2181 INSN(vshr_128_u64, 6, 1, 1); 2182 INSN(vshr_64_s8, 3, 0, 0); 2183 INSN(vshr_64_s16, 4, 0, 0); 2184 INSN(vshr_64_s32, 5, 0, 0); 2185 INSN(vshr_64_s64, 6, 0, 0); 2186 INSN(vshr_128_s8, 3, 1, 0); 2187 INSN(vshr_128_s16, 4, 1, 0); 2188 INSN(vshr_128_s32, 5, 1, 0); 2189 INSN(vshr_128_s64, 6, 1, 0); 2190 #undef INSN 2191 #define INSN(NAME, encode, size, q) \ 2192 inline void NAME(FloatRegister Dd, FloatRegister Dm, unsigned imm) { \ 2193 simd_vshl(Dd, Dm, imm|(1u<<size), q, 1, encode); \ 2194 } 2195 #define INSN_GR(NAME, U, encode, u) \ 2196 INSN(NAME##_64##U##8, encode, 3, 0); \ 2197 INSN(NAME##_64##U##16, encode, 4, 0); \ 2198 INSN(NAME##_64##U##32, encode, 5, 0); \ 2199 INSN(NAME##_64##U##64, encode, 6, 0); \ 2200 INSN(NAME##_128##U##8, encode, 3, 1); \ 2201 INSN(NAME##_128##U##16, encode, 4, 2); \ 2202 INSN(NAME##_128##U##32, encode, 5, 3); \ 2203 INSN(NAME##_128##U##64, encode, 6, 4); 2204 2205 INSN_GR(vsli, _, 0b0101, 1); 2206 INSN_GR(vsri, _, 0b0100, 1); 2207 INSN_GR(vsra, _u, 0b0001, 1); 2208 INSN_GR(vsra, _s, 0b0001, 0); 2209 #undef INSN_GR 2210 #undef INSN 2211 2212 #define vmovl_8s(Qd, Dm) vshll_8s(Qd, Dm, 0); 2213 #define vmovl_16s(Qd, Dm) vshll_16s(Qd, Dm, 0); 2214 #define vmovl_32s(Qd, Dm) vshll_32s(Qd, Dm, 0); 2215 #define vmovl_8u(Qd, Dm) vshll_8u(Qd, Dm, 0); 2216 #define vmovl_16u(Qd, Dm) vshll_16u(Qd, Dm, 0); 2217 #define vmovl_32u(Qd, Dm) vshll_32u(Qd, Dm, 0); 2218 2219 private: 2220 void simd_vshl(FloatRegister Dd, FloatRegister Dm, FloatRegister Dn, unsigned size, 2221 unsigned q, unsigned u); 2222 public: 2223 #define INSN(NAME, size, q, u) \ 2224 inline void NAME(FloatRegister Dd, FloatRegister Dm, FloatRegister Dn) { \ 2225 simd_vshl(Dd, Dm, Dn, size, q, u); \ 2226 } 2227 INSN(vshl_64_u8, 0, 0, 1); 2228 INSN(vshl_64_u16, 1, 0, 1); 2229 INSN(vshl_64_u32, 2, 0, 1); 2230 INSN(vshl_64_u64, 3, 0, 1); 2231 INSN(vshl_128_u8, 0, 1, 1); 2232 INSN(vshl_128_u16, 1, 1, 1); 2233 INSN(vshl_128_u32, 2, 1, 1); 2234 INSN(vshl_128_u64, 3, 1, 1); 2235 INSN(vshl_64_s8, 0, 0, 0); 2236 INSN(vshl_64_s16, 1, 0, 0); 2237 INSN(vshl_64_s32, 2, 0, 0); 2238 INSN(vshl_64_s64, 3, 0, 0); 2239 INSN(vshl_128_s8, 0, 1, 0); 2240 INSN(vshl_128_s16, 1, 1, 0); 2241 INSN(vshl_128_s32, 2, 1, 0); 2242 INSN(vshl_128_s64, 3, 1, 0); 2243 #undef INSN 2244 2245 // Two registers, miscellaneous 2246 private: 2247 void simd_insn(FloatRegister Dd, FloatRegister Dm, unsigned q, unsigned a, 2248 unsigned b, unsigned size); 2249 public: 2250 #define INSN(NAME, q, size, op, a) \ 2251 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2252 simd_insn(Dd, Dm, q, a, q|(op<<1), size); \ 2253 } 2254 INSN(vrev16_64_8, 0, 0, 2, 0b00); 2255 INSN(vrev16_128_8, 1, 0, 2, 0b00); 2256 INSN(vrev32_64_8, 0, 0, 1, 0b00); 2257 INSN(vrev32_128_8, 1, 0, 1, 0b00); 2258 INSN(vrev32_64_16, 0, 1, 1, 0b00); 2259 INSN(vrev32_128_16, 1, 1, 1, 0b00); 2260 INSN(vrev64_64_8, 0, 0, 0, 0b00); 2261 INSN(vrev64_128_8, 1, 0, 0, 0b00); 2262 INSN(vrev64_64_16, 0, 1, 0, 0b00); 2263 INSN(vrev64_128_16, 1, 1, 0, 0b00); 2264 INSN(vrev64_64_32, 0, 2, 0, 0b00); 2265 INSN(vrev64_128_32, 1, 2, 0, 0b00); 2266 #undef INSN 2267 #define INSN(NAME, q, a, b, size) \ 2268 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2269 simd_insn(Dd, Dm, q, a, (b<<1)|q, size); \ 2270 } 2271 #define INSN_GR(NAME, a, b) \ 2272 INSN(NAME##_64_8, 0, a, b, 0b00); \ 2273 INSN(NAME##_64_16, 0, a, b, 0b01); \ 2274 INSN(NAME##_64_32, 0, a, b, 0b10); \ 2275 INSN(NAME##_128_8, 1, a, b, 0b00); \ 2276 INSN(NAME##_128_16, 1, a, b, 0b01); \ 2277 INSN(NAME##_128_32, 1, a, b, 0b10); 2278 2279 INSN_GR(vtrn, 0b10, 0b0001); 2280 INSN(vswp_64, 0, 0b10, 0b0000, 0b00); 2281 INSN(vswp_128, 1, 0b10, 0b0000, 0b00); 2282 #undef INSN_GR 2283 #undef INSN 2284 2285 private: 2286 void simd_cnt(FloatRegister Dd, FloatRegister Dm, unsigned q); 2287 public: 2288 #define INSN(NAME, q) \ 2289 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2290 simd_cnt(Dd, Dm, q); \ 2291 } 2292 INSN(vcnt_64, 0); 2293 INSN(vcnt_128, 1); 2294 #undef INSN 2295 2296 private: 2297 void simd_padl(FloatRegister Dd, FloatRegister Dm, unsigned q, unsigned size, 2298 unsigned op, unsigned encode); 2299 public: 2300 #define INSN(NAME, q, size, op, encode) \ 2301 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2302 simd_padl(Dd, Dm, q, size, op, encode); \ 2303 } 2304 INSN(vpadal_64_s8, 0, 0, 0, 0b110); 2305 INSN(vpadal_64_s16, 0, 1, 0, 0b110); 2306 INSN(vpadal_64_s32, 0, 2, 0, 0b110); 2307 INSN(vpadal_64_u8, 0, 0, 1, 0b110); 2308 INSN(vpadal_64_u16, 0, 1, 1, 0b110); 2309 INSN(vpadal_64_u32, 0, 2, 1, 0b110); 2310 INSN(vpadal_128_s8, 1, 0, 0, 0b110); 2311 INSN(vpadal_128_s16, 1, 1, 0, 0b110); 2312 INSN(vpadal_128_s32, 1, 2, 0, 0b110); 2313 INSN(vpadal_128_u8, 1, 0, 1, 0b110); 2314 INSN(vpadal_128_u16, 1, 1, 1, 0b110); 2315 INSN(vpadal_128_u32, 1, 2, 1, 0b110); 2316 INSN(vpaddl_64_s8, 0, 0, 0, 0b010); 2317 INSN(vpaddl_64_s16, 0, 1, 0, 0b010); 2318 INSN(vpaddl_64_s32, 0, 2, 0, 0b010); 2319 INSN(vpaddl_64_u8, 0, 0, 1, 0b010); 2320 INSN(vpaddl_64_u16, 0, 1, 1, 0b010); 2321 INSN(vpaddl_64_u32, 0, 2, 1, 0b010); 2322 INSN(vpaddl_128_s8, 1, 0, 0, 0b010); 2323 INSN(vpaddl_128_s16, 1, 1, 0, 0b010); 2324 INSN(vpaddl_128_s32, 1, 2, 0, 0b010); 2325 INSN(vpaddl_128_u8, 1, 0, 1, 0b010); 2326 INSN(vpaddl_128_u16, 1, 1, 1, 0b010); 2327 INSN(vpaddl_128_u32, 1, 2, 1, 0b010); 2328 #undef INSN 2329 2330 private: 2331 void simd_dup(FloatRegister Dd, Register Rt, unsigned q, unsigned size); 2332 void simd_dup(FloatRegister Dd, FloatRegister Dm, unsigned index, unsigned q, unsigned size); 2333 public: 2334 #define INSN(NAME, q, size) \ 2335 inline void NAME(FloatRegister Dd, Register Rt) { \ 2336 simd_dup(Dd, Rt, q, size); \ 2337 } 2338 INSN(vdup_64_8, 0, 0b10); 2339 INSN(vdup_64_16, 0, 0b01); 2340 INSN(vdup_64_32, 0, 0b00); 2341 INSN(vdup_128_8, 1, 0b10); 2342 INSN(vdup_128_16, 1, 0b01); 2343 INSN(vdup_128_32, 1, 0b00); 2344 #undef INSN 2345 public: 2346 #define INSN(NAME, q, size) \ 2347 inline void NAME(FloatRegister Dd, FloatRegister Dm, unsigned index) { \ 2348 simd_dup(Dd, Dm, index, q, size); \ 2349 } 2350 INSN(vdup_64_8, 0, 0b10); 2351 INSN(vdup_64_16, 0, 0b01); 2352 INSN(vdup_64_32, 0, 0b00); 2353 INSN(vdup_128_8, 1, 0b10); 2354 INSN(vdup_128_16, 1, 0b01); 2355 INSN(vdup_128_32, 1, 0b00); 2356 #undef INSN 2357 #define INSN(NAME, q) \ 2358 inline void NAME(FloatRegister Dd, FloatRegister Sm) { \ 2359 const int m_num = Sm->encoding_nocheck(); \ 2360 simd_dup(Dd, as_FloatRegister(m_num & ~1), m_num & 1, q, 0b00); \ 2361 } 2362 INSN(vdups_64, 0); 2363 INSN(vdups_128, 1); 2364 #undef INSN 2365 2366 private: 2367 void simd_neg(FloatRegister Dd, FloatRegister Dm, unsigned q, unsigned size); 2368 public: 2369 #define INSN(NAME, q, size) \ 2370 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2371 simd_neg(Dd, Dm, q, size); \ 2372 } 2373 INSN(vneg_64_s8, 0, 0b00); 2374 INSN(vneg_64_s16, 0, 0b01); 2375 INSN(vneg_64_s32, 0, 0b10); 2376 INSN(vneg_128_s8, 1, 0b00); 2377 INSN(vneg_128_s16, 1, 0b01); 2378 INSN(vneg_128_s32, 1, 0b10); 2379 #undef INSN 2380 2381 private: 2382 void simd_mvn(FloatRegister Dd, FloatRegister Dm, unsigned q); 2383 public: 2384 #define INSN(NAME, q) \ 2385 inline void NAME(FloatRegister Dd, FloatRegister Dm) { \ 2386 simd_mvn(Dd, Dm, q); \ 2387 } 2388 INSN(vmvn_64, 0); 2389 INSN(vmvn_128, 1); 2390 #undef INSN 2391 2392 // three registers of the same length 2393 private: 2394 void simd_insn(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, 2395 unsigned q, unsigned a, unsigned b, unsigned u, unsigned c); 2396 public: 2397 #define INSN(NAME, q, a, b, u, c) \ 2398 inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \ 2399 simd_insn(Dd, Dn, Dm, q, a, b, u, c); \ 2400 } 2401 #define INSN_GR(NAME, a, b, u) \ 2402 INSN(NAME##_64_8, 0, a, b, u, 0b00) \ 2403 INSN(NAME##_64_16, 0, a, b, u, 0b01) \ 2404 INSN(NAME##_64_32, 0, a, b, u, 0b10) \ 2405 INSN(NAME##_64_64, 0, a, b, u, 0b11) \ 2406 INSN(NAME##_128_8, 1, a, b, u, 0b00) \ 2407 INSN(NAME##_128_16, 1, a, b, u, 0b01) \ 2408 INSN(NAME##_128_32, 1, a, b, u, 0b10) \ 2409 INSN(NAME##_128_64, 1, a, b, u, 0b11) 2410 2411 INSN_GR(vadd, 0b1000, 0b0, 0b0); 2412 INSN(vadd_64_f32, 0, 0b1101, 0b0, 0b0, 0b00); 2413 INSN(vadd_128_f32, 1, 0b1101, 0b0, 0b0, 0b00); 2414 INSN_GR(vsub, 0b1000, 0b0, 0b1); 2415 INSN(vsub_64_f32, 0, 0b1101, 0b0, 0b0, 0b10); 2416 INSN(vsub_128_f32, 1, 0b1101, 0b0, 0b0, 0b10); 2417 2418 #undef INSN_GR 2419 #undef INSN 2420 2421 // three registers of different length 2422 private: 2423 void simd_insn(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, 2424 unsigned qn, unsigned a, unsigned b, unsigned u); 2425 public: 2426 #define INSN(NAME, qn, a, b, u) \ 2427 inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \ 2428 simd_insn(Dd, Dn, Dm, qn, a, b, u); \ 2429 } 2430 #define INSN_GR(NAME, qn, a) \ 2431 INSN(NAME##_8u, qn, a, 0b00, 1) \ 2432 INSN(NAME##_16u, qn, a, 0b01, 1) \ 2433 INSN(NAME##_32u, qn, a, 0b10, 1) \ 2434 INSN(NAME##_8s, qn, a, 0b00, 0) \ 2435 INSN(NAME##_16s, qn, a, 0b01, 0) \ 2436 INSN(NAME##_32s, qn, a, 0b10, 0) 2437 2438 INSN_GR(vaddw, 1, 0b0001); 2439 INSN_GR(vaddl, 0, 0b0000); 2440 #undef INSN_GR 2441 #undef INSN 2442 2443 // VEXT, the instruction out of any class 2444 private: 2445 void simd_vext(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, unsigned q, unsigned imm); 2446 public: 2447 #define INSN(NAME, q) \ 2448 inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, unsigned imm) { \ 2449 simd_vext(Dd, Dn, Dm, q, imm); \ 2450 } 2451 INSN(vext_64, 0u); 2452 INSN(vext_128, 1u); 2453 #undef INSN 2454 2455 public: 2456 2457 #define INSN(NAME, r) \ 2458 inline void NAME(Address a) { \ 2459 starti; \ 2460 f(0b1111, 31, 28); \ 2461 f(0b0101, 27, 24), f(0b01, 21, 20); \ 2462 f(0b1111, 15, 12); \ 2463 f(r, 22); \ 2464 rf(a.base(), 16); \ 2465 if (a.get_mode() == Address::imm) { \ 2466 f(a.offset() >= 0 ? 1 : 0, 23); \ 2467 f(a.offset() >= 0 ? a.offset() : -a.offset(), 11, 0); \ 2468 } else if (a.get_mode() == Address::reg) { \ 2469 assert(a.get_wb_mode() == Address::off, "must be"); \ 2470 assert(!a.shift().is_register(), "must be"); \ 2471 f(a.op() == Address::ADD ? 1 : 0, 23); \ 2472 rf(a.index(), 0); \ 2473 f(0, 4); \ 2474 f(a.shift().shift(), 11, 7); \ 2475 f(a.shift().kind(), 6, 5); \ 2476 } else { \ 2477 ShouldNotReachHere(); \ 2478 } \ 2479 } 2480 INSN(pld, 1); 2481 INSN(pldw, 0); 2482 #undef INSN 2483 2484 #define INSN(NAME, size, c) \ 2485 inline void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \ 2486 starti; \ 2487 assert(VM_Version::features() & FT_CRC32, "Instruction is not supported by CPU"); \ 2488 f(cond, 31, 28), f(0b00010, 27, 23), f(size, 22, 21), f(0, 20), rf(Rn, 16), rf(Rd, 12); \ 2489 f(0b00, 11, 10), c ? f(0b1, 9) : f(0b0, 9), f(0b00100, 8, 4), rf(Rm, 0); \ 2490 } 2491 INSN(crc32b, 0, 0); 2492 INSN(crc32h, 1, 0); 2493 INSN(crc32w, 2, 0); 2494 INSN(crc32cb, 0, 1); 2495 INSN(crc32ch, 1, 1); 2496 INSN(crc32cw, 2, 1); 2497 #undef INSN 2498 2499 #define INSN(NAME, opc) \ 2500 inline void NAME(FloatRegister Vd, FloatRegister Vm) { \ 2501 starti; \ 2502 f(0b111100111, 31, 23), f(0b110000, 21, 16), f(0, 4); \ 2503 f(opc, 11, 6), fp_rencode(Vd, false, 12, 22), fp_rencode(Vm, false, 0, 5); \ 2504 } 2505 2506 INSN(aese, 0b001100); 2507 INSN(aesd, 0b001101); 2508 INSN(aesmc, 0b001110); 2509 INSN(aesimc, 0b001111); 2510 2511 #undef INSN 2512 2513 Assembler(CodeBuffer* code) : AbstractAssembler(code) {} 2514 2515 virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, 2516 Register tmp, 2517 int offset) { 2518 ShouldNotCallThis(); 2519 return RegisterOrConstant(); 2520 } 2521 2522 // Stack overflow checking 2523 virtual void bang_stack_with_offset(int offset); 2524 2525 // Immediate values checks and transformations 2526 2527 static uint32_t encode_imm12(int imm); 2528 static int decode_imm12(uint32_t imm12); 2529 static bool is_valid_for_imm12(int imm); 2530 2531 static bool is_valid_for_offset_imm(int imm, int nbits) { 2532 return uabs(imm) < (1u << nbits); 2533 } 2534 2535 static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm); 2536 static bool operand_valid_for_add_sub_immediate(int imm); 2537 static bool operand_valid_for_add_sub_immediate(unsigned imm); 2538 static bool operand_valid_for_add_sub_immediate(unsigned long imm); 2539 static bool operand_valid_for_add_sub_immediate(jlong imm); 2540 static bool operand_valid_for_float_immediate(float imm); 2541 static bool operand_valid_for_double_immediate(double imm); 2542 2543 void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); 2544 void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); 2545 2546 // useful to revert back the effect of post/pre addressing modifications 2547 // applied to the base register 2548 void compensate_addr_offset(const Address &adr, Condition cond) { 2549 compensate_addr_offset(adr.base(), adr.index(), adr.shift(), adr.op() == Address::ADD, cond); 2550 } 2551 void compensate_addr_offset(Register Rd, Register Roff, shift_op shift, bool isAdd, Condition cond) { 2552 shift_op shift_back; 2553 2554 if (shift.is_register()) { 2555 switch (shift.kind()) { 2556 case shift_op::LSL: 2557 case shift_op::LSR: 2558 shift_back = asr(shift.reg()); 2559 break; 2560 case shift_op::ASR: 2561 shift_back = lsl(shift.reg()); 2562 break; 2563 case shift_op::ROR: 2564 Unimplemented(); // need a temp register here 2565 break; 2566 default: 2567 ShouldNotReachHere(); 2568 } 2569 } else { 2570 switch (shift.kind()) { 2571 case shift_op::LSL: 2572 case shift_op::LSR: 2573 shift_back = asr(shift.shift()); 2574 break; 2575 case shift_op::ASR: 2576 shift_back = lsl(shift.shift()); 2577 break; 2578 case shift_op::ROR: 2579 shift_back = ror(32-shift.shift()); 2580 break; 2581 default: 2582 ShouldNotReachHere(); 2583 } 2584 } 2585 if (isAdd) 2586 sub(Rd, Rd, Roff, shift_back, cond); 2587 else 2588 add(Rd, Rd, Roff, shift_back, cond); 2589 } 2590 }; 2591 2592 inline Assembler::Membar_mask_bits operator|(Assembler::Membar_mask_bits a, 2593 Assembler::Membar_mask_bits b) { 2594 return Assembler::Membar_mask_bits(unsigned(a)|unsigned(b)); 2595 } 2596 2597 Instruction_aarch32::~Instruction_aarch32() { 2598 assem->emit(); 2599 } 2600 2601 #undef starti 2602 2603 // Invert a condition 2604 inline const Assembler::Condition operator~(const Assembler::Condition cond) { 2605 return Assembler::Condition(int(cond) ^ 1); 2606 } 2607 2608 class BiasedLockingCounters; 2609 2610 extern "C" void das(uint64_t start, int len); 2611 2612 #endif // CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP