11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef CPU_AARCH64_ASSEMBLER_AARCH64_HPP
27 #define CPU_AARCH64_ASSEMBLER_AARCH64_HPP
28
29 #include "asm/register.hpp"
30
31 // definitions of various symbolic names for machine registers
32
33 // First intercalls between C and Java which use 8 general registers
34 // and 8 floating registers
35
36 // we also have to copy between x86 and ARM registers but that's a
37 // secondary complication -- not all code employing C call convention
38 // executes as x86 code though -- we generate some of it
39
40 class Argument {
41 public:
42 enum {
43 n_int_register_parameters_c = 8, // r0, r1, ... r7 (c_rarg0, c_rarg1, ...)
44 n_float_register_parameters_c = 8, // v0, v1, ... v7 (c_farg0, c_farg1, ... )
45
46 n_int_register_parameters_j = 8, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ...
47 n_float_register_parameters_j = 8 // v0, v1, ... v7 (j_farg0, j_farg1, ...
48 };
49 };
50
596
597 InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
598 };
599
600 const int FPUStateSizeInWords = FloatRegisterImpl::number_of_registers *
601 FloatRegisterImpl::save_slots_per_register;
602
603 typedef enum {
604 PLDL1KEEP = 0b00000, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
605 PSTL1KEEP = 0b10000, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM,
606 PLIL1KEEP = 0b01000, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM
607 } prfop;
608
609 class Assembler : public AbstractAssembler {
610
611 #ifndef PRODUCT
612 static const uintptr_t asm_bp;
613
614 void emit_long(jint x) {
615 if ((uintptr_t)pc() == asm_bp)
616 asm volatile ("nop");
617 AbstractAssembler::emit_int32(x);
618 }
619 #else
620 void emit_long(jint x) {
621 AbstractAssembler::emit_int32(x);
622 }
623 #endif
624
625 public:
626
627 enum { instruction_size = 4 };
628
629 //---< calculate length of instruction >---
630 // We just use the values set above.
631 // instruction must start at passed address
632 static unsigned int instr_len(unsigned char *instr) { return instruction_size; }
633
634 //---< longest instructions >---
635 static unsigned int instr_maxlen() { return instruction_size; }
636
637 Address adjust(Register base, int offset, bool preIncrement) {
638 if (preIncrement)
639 return Address(Pre(base, offset));
640 else
641 return Address(Post(base, offset));
642 }
643
644 Address pre(Register base, int offset) {
645 return adjust(base, offset, true);
646 }
647
648 Address post(Register base, int offset) {
649 return adjust(base, offset, false);
650 }
651
652 Address post(Register base, Register idx) {
653 return Address(Post(base, idx));
654 }
655
656 Instruction_aarch64* current;
657
658 void set_current(Instruction_aarch64* i) { current = i; }
659
660 void f(unsigned val, int msb, int lsb) {
661 current->f(val, msb, lsb);
662 }
663 void f(unsigned val, int msb) {
664 current->f(val, msb, msb);
665 }
666 void sf(int64_t val, int msb, int lsb) {
667 current->sf(val, msb, lsb);
668 }
669 void rf(Register reg, int lsb) {
670 current->rf(reg, lsb);
671 }
672 void srf(Register reg, int lsb) {
673 current->srf(reg, lsb);
674 }
675 void zrf(Register reg, int lsb) {
1504 } \
1505 \
1506 /* These instructions have no immediate form. Provide an overload so \
1507 that if anyone does try to use an immediate operand -- this has \
1508 happened! -- we'll get a compile-time error. */ \
1509 void NAME(Register Rd, Register Rn, unsigned imm, \
1510 enum shift_kind kind = LSL, unsigned shift = 0) { \
1511 assert(false, " can't be used with immediate operand"); \
1512 }
1513
1514 INSN(bic, 1, 0b00, 1);
1515 INSN(orn, 1, 0b01, 1);
1516 INSN(eon, 1, 0b10, 1);
1517 INSN(bics, 1, 0b11, 1);
1518 INSN(bicw, 0, 0b00, 1);
1519 INSN(ornw, 0, 0b01, 1);
1520 INSN(eonw, 0, 0b10, 1);
1521 INSN(bicsw, 0, 0b11, 1);
1522
1523 #undef INSN
1524
1525 // Aliases for short forms of orn
1526 void mvn(Register Rd, Register Rm,
1527 enum shift_kind kind = LSL, unsigned shift = 0) {
1528 orn(Rd, zr, Rm, kind, shift);
1529 }
1530
1531 void mvnw(Register Rd, Register Rm,
1532 enum shift_kind kind = LSL, unsigned shift = 0) {
1533 ornw(Rd, zr, Rm, kind, shift);
1534 }
1535
1536 // Add/subtract (shifted register)
1537 #define INSN(NAME, size, op) \
1538 void NAME(Register Rd, Register Rn, Register Rm, \
1539 enum shift_kind kind, unsigned shift = 0) { \
1540 starti; \
1541 f(0, 21); \
1542 assert_cond(kind != ROR); \
1543 guarantee(size == 1 || shift < 32, "incorrect shift");\
|
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef CPU_AARCH64_ASSEMBLER_AARCH64_HPP
27 #define CPU_AARCH64_ASSEMBLER_AARCH64_HPP
28
29 #include "asm/register.hpp"
30
31 #ifdef __GNUC__
32
33 // __nop needs volatile so that compiler doesn't optimize it away
34 #define NOP() asm volatile ("nop");
35
36 #elif defined(_MSC_VER)
37
38 // Use MSVC instrinsic: https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=vs-2019#I
39 #define NOP() __nop();
40
41 #endif
42
43
44
45 // definitions of various symbolic names for machine registers
46
47 // First intercalls between C and Java which use 8 general registers
48 // and 8 floating registers
49
50 // we also have to copy between x86 and ARM registers but that's a
51 // secondary complication -- not all code employing C call convention
52 // executes as x86 code though -- we generate some of it
53
54 class Argument {
55 public:
56 enum {
57 n_int_register_parameters_c = 8, // r0, r1, ... r7 (c_rarg0, c_rarg1, ...)
58 n_float_register_parameters_c = 8, // v0, v1, ... v7 (c_farg0, c_farg1, ... )
59
60 n_int_register_parameters_j = 8, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ...
61 n_float_register_parameters_j = 8 // v0, v1, ... v7 (j_farg0, j_farg1, ...
62 };
63 };
64
610
611 InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
612 };
613
614 const int FPUStateSizeInWords = FloatRegisterImpl::number_of_registers *
615 FloatRegisterImpl::save_slots_per_register;
616
617 typedef enum {
618 PLDL1KEEP = 0b00000, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
619 PSTL1KEEP = 0b10000, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM,
620 PLIL1KEEP = 0b01000, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM
621 } prfop;
622
623 class Assembler : public AbstractAssembler {
624
625 #ifndef PRODUCT
626 static const uintptr_t asm_bp;
627
628 void emit_long(jint x) {
629 if ((uintptr_t)pc() == asm_bp)
630 NOP();
631 AbstractAssembler::emit_int32(x);
632 }
633 #else
634 void emit_long(jint x) {
635 AbstractAssembler::emit_int32(x);
636 }
637 #endif
638
639 public:
640
641 enum { instruction_size = 4 };
642
643 //---< calculate length of instruction >---
644 // We just use the values set above.
645 // instruction must start at passed address
646 static unsigned int instr_len(unsigned char *instr) { return instruction_size; }
647
648 //---< longest instructions >---
649 static unsigned int instr_maxlen() { return instruction_size; }
650
651 Address adjust(Register base, int offset, bool preIncrement) {
652 if (preIncrement)
653 return Address(Pre(base, offset));
654 else
655 return Address(Post(base, offset));
656 }
657
658 Address pre(Register base, int offset) {
659 return adjust(base, offset, true);
660 }
661
662 Address post(Register base, int offset) {
663 return adjust(base, offset, false);
664 }
665
666 Address post(Register base, Register idx) {
667 return Address(Post(base, idx));
668 }
669
670 static address locate_next_instruction(address inst);
671
672 Instruction_aarch64* current;
673
674 void set_current(Instruction_aarch64* i) { current = i; }
675
676 void f(unsigned val, int msb, int lsb) {
677 current->f(val, msb, lsb);
678 }
679 void f(unsigned val, int msb) {
680 current->f(val, msb, msb);
681 }
682 void sf(int64_t val, int msb, int lsb) {
683 current->sf(val, msb, lsb);
684 }
685 void rf(Register reg, int lsb) {
686 current->rf(reg, lsb);
687 }
688 void srf(Register reg, int lsb) {
689 current->srf(reg, lsb);
690 }
691 void zrf(Register reg, int lsb) {
1520 } \
1521 \
1522 /* These instructions have no immediate form. Provide an overload so \
1523 that if anyone does try to use an immediate operand -- this has \
1524 happened! -- we'll get a compile-time error. */ \
1525 void NAME(Register Rd, Register Rn, unsigned imm, \
1526 enum shift_kind kind = LSL, unsigned shift = 0) { \
1527 assert(false, " can't be used with immediate operand"); \
1528 }
1529
1530 INSN(bic, 1, 0b00, 1);
1531 INSN(orn, 1, 0b01, 1);
1532 INSN(eon, 1, 0b10, 1);
1533 INSN(bics, 1, 0b11, 1);
1534 INSN(bicw, 0, 0b00, 1);
1535 INSN(ornw, 0, 0b01, 1);
1536 INSN(eonw, 0, 0b10, 1);
1537 INSN(bicsw, 0, 0b11, 1);
1538
1539 #undef INSN
1540
1541 #ifdef _WIN64
1542 // In MSVC, `mvn` is defined as a macro and it affects compilation
1543 #undef mvn
1544 #endif
1545
1546 // Aliases for short forms of orn
1547 void mvn(Register Rd, Register Rm,
1548 enum shift_kind kind = LSL, unsigned shift = 0) {
1549 orn(Rd, zr, Rm, kind, shift);
1550 }
1551
1552 void mvnw(Register Rd, Register Rm,
1553 enum shift_kind kind = LSL, unsigned shift = 0) {
1554 ornw(Rd, zr, Rm, kind, shift);
1555 }
1556
1557 // Add/subtract (shifted register)
1558 #define INSN(NAME, size, op) \
1559 void NAME(Register Rd, Register Rn, Register Rm, \
1560 enum shift_kind kind, unsigned shift = 0) { \
1561 starti; \
1562 f(0, 21); \
1563 assert_cond(kind != ROR); \
1564 guarantee(size == 1 || shift < 32, "incorrect shift");\
|