diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp index 68a72f87cfa..37320d96808 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -83,7 +83,7 @@ void Assembler::zext_w(Register Rd, Register Rs) { add_uw(Rd, Rs, zr); } -void Assembler::li(Register Rd, int64_t imm) { +void Assembler::_li(Register Rd, int64_t imm) { // int64_t is in range 0x8000 0000 0000 0000 ~ 0x7fff ffff ffff ffff int shift = 12; int64_t upper = imm, lower = imm; diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 100be449879..4bb9f0a8338 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -301,7 +301,7 @@ class Assembler : public AbstractAssembler { } } - void li(Register Rd, int64_t imm); // optimized load immediate + void _li(Register Rd, int64_t imm); // optimized load immediate void li32(Register Rd, int32_t imm); void li64(Register Rd, int64_t imm); void movptr(Register Rd, address addr); @@ -378,11 +378,11 @@ class Assembler : public AbstractAssembler { emit_int32((jint)insn); } - void halt() { + void _halt() { emit_int32(0); } -// Rigster Instruction +// Register Instruction #define INSN(NAME, op, funct3, funct7) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ unsigned insn = 0; \ @@ -395,18 +395,18 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(add, 0b0110011, 0b000, 0b0000000); - INSN(sub, 0b0110011, 0b000, 0b0100000); - INSN(andr, 0b0110011, 0b111, 0b0000000); - INSN(orr, 0b0110011, 0b110, 0b0000000); - INSN(xorr, 0b0110011, 0b100, 0b0000000); + INSN(_add, 0b0110011, 0b000, 0b0000000); + INSN(_sub, 0b0110011, 0b000, 0b0100000); + INSN(_andr, 0b0110011, 0b111, 0b0000000); + INSN(_orr, 0b0110011, 0b110, 0b0000000); + INSN(_xorr, 0b0110011, 0b100, 0b0000000); INSN(sll, 0b0110011, 0b001, 0b0000000); INSN(sra, 0b0110011, 0b101, 0b0100000); INSN(srl, 0b0110011, 0b101, 0b0000000); INSN(slt, 0b0110011, 0b010, 0b0000000); INSN(sltu, 0b0110011, 0b011, 0b0000000); - INSN(addw, 0b0111011, 0b000, 0b0000000); - INSN(subw, 0b0111011, 0b000, 0b0100000); + INSN(_addw, 0b0111011, 0b000, 0b0000000); + INSN(_subw, 0b0111011, 0b000, 0b0100000); INSN(sllw, 0b0111011, 0b001, 0b0000000); INSN(sraw, 0b0111011, 0b101, 0b0100000); INSN(srlw, 0b0111011, 0b101, 0b0000000); @@ -436,8 +436,8 @@ class Assembler : public AbstractAssembler { // Load/store register (all modes) #define INSN(NAME, op, funct3) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ int32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -445,7 +445,19 @@ class Assembler : public AbstractAssembler { patch_reg((address)&insn, 7, Rd); \ patch((address)&insn, 31, 20, val); \ emit(insn); \ - } \ + } + + INSN(lb, 0b0000011, 0b000); + INSN(lbu, 0b0000011, 0b100); + INSN(lh, 0b0000011, 0b001); + INSN(lhu, 0b0000011, 0b101); + INSN(_lw, 0b0000011, 0b010); + INSN(lwu, 0b0000011, 0b110); + INSN(_ld, 0b0000011, 0b011); + +#undef INSN + +#define INSN(NAME) \ void NAME(Register Rd, address dest) { \ assert_cond(dest != NULL); \ int64_t distance = (dest - pc()); \ @@ -491,20 +503,20 @@ class Assembler : public AbstractAssembler { wrap_label(Rd, L, &Assembler::NAME); \ } - INSN(lb, 0b0000011, 0b000); - INSN(lbu, 0b0000011, 0b100); - INSN(ld, 0b0000011, 0b011); - INSN(lh, 0b0000011, 0b001); - INSN(lhu, 0b0000011, 0b101); - INSN(lw, 0b0000011, 0b010); - INSN(lwu, 0b0000011, 0b110); + INSN(lb); + INSN(lbu); + INSN(lh); + INSN(lhu); + INSN(lw); + INSN(lwu); + INSN(ld); #undef INSN #define INSN(NAME, op, funct3) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -512,7 +524,14 @@ class Assembler : public AbstractAssembler { patch_reg((address)&insn, 7, Rd); \ patch((address)&insn, 31, 20, val); \ emit(insn); \ - } \ + } + + INSN(flw, 0b0000111, 0b010); + INSN(_fld, 0b0000111, 0b011); + +#undef INSN + +#define INSN(NAME) \ void NAME(FloatRegister Rd, address dest, Register temp = t0) { \ assert_cond(dest != NULL); \ int64_t distance = (dest - pc()); \ @@ -550,14 +569,14 @@ class Assembler : public AbstractAssembler { } \ } - INSN(flw, 0b0000111, 0b010); - INSN(fld, 0b0000111, 0b011); + INSN(flw); + INSN(fld); #undef INSN #define INSN(NAME, op, funct3) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - unsigned insn = 0; \ guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid."); \ + unsigned insn = 0; \ uint32_t val = offset & 0x1fff; \ uint32_t val11 = (val >> 11) & 0x1; \ uint32_t val12 = (val >> 12) & 0x1; \ @@ -572,7 +591,18 @@ class Assembler : public AbstractAssembler { patch((address)&insn, 30, 25, high); \ patch((address)&insn, 31, val12); \ emit(insn); \ - } \ + } + + INSN(_beq, 0b1100011, 0b000); + INSN(_bne, 0b1100011, 0b001); + INSN(bge, 0b1100011, 0b101); + INSN(bgeu, 0b1100011, 0b111); + INSN(blt, 0b1100011, 0b100); + INSN(bltu, 0b1100011, 0b110); + +#undef INSN + +#define INSN(NAME) \ void NAME(Register Rs1, Register Rs2, const address dest) { \ assert_cond(dest != NULL); \ int64_t offset = (dest - pc()); \ @@ -583,12 +613,12 @@ class Assembler : public AbstractAssembler { NAME(Rs1, Rs2, dest); \ } - INSN(beq, 0b1100011, 0b000); - INSN(bge, 0b1100011, 0b101); - INSN(bgeu, 0b1100011, 0b111); - INSN(blt, 0b1100011, 0b100); - INSN(bltu, 0b1100011, 0b110); - INSN(bne, 0b1100011, 0b001); + INSN(beq); + INSN(bne); + INSN(bge); + INSN(bgeu); + INSN(blt); + INSN(bltu); #undef INSN @@ -608,8 +638,8 @@ class Assembler : public AbstractAssembler { #define INSN(NAME, REGISTER, op, funct3) \ void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ uint32_t low = val & 0x1f; \ uint32_t high = (val >> 5) & 0x7f; \ @@ -621,16 +651,27 @@ class Assembler : public AbstractAssembler { patch((address)&insn, 31, 25, high); \ emit(insn); \ } \ + + INSN(sb, Register, 0b0100011, 0b000); + INSN(sh, Register, 0b0100011, 0b001); + INSN(_sw, Register, 0b0100011, 0b010); + INSN(_sd, Register, 0b0100011, 0b011); + INSN(fsw, FloatRegister, 0b0100111, 0b010); + INSN(_fsd, FloatRegister, 0b0100111, 0b011); + +#undef INSN + +#define INSN(NAME, REGISTER) \ INSN_ENTRY_RELOC(void, NAME(REGISTER Rs, address dest, relocInfo::relocType rtype, Register temp = t0)) \ NAME(Rs, dest, temp); \ } - INSN(sb, Register, 0b0100011, 0b000); - INSN(sh, Register, 0b0100011, 0b001); - INSN(sw, Register, 0b0100011, 0b010); - INSN(sd, Register, 0b0100011, 0b011); - INSN(fsw, FloatRegister, 0b0100111, 0b010); - INSN(fsd, FloatRegister, 0b0100111, 0b011); + INSN(sb, Register); + INSN(sh, Register); + INSN(sw, Register); + INSN(sd, Register); + INSN(fsw, FloatRegister); + INSN(fsd, FloatRegister); #undef INSN @@ -759,8 +800,8 @@ class Assembler : public AbstractAssembler { #define INSN(NAME, op) \ void NAME(Register Rd, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_imm_in_range(offset, 20, 1), "offset is invalid."); \ + unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch_reg((address)&insn, 7, Rd); \ patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff)); \ @@ -768,7 +809,13 @@ class Assembler : public AbstractAssembler { patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff)); \ patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1)); \ emit(insn); \ - } \ + } + + INSN(_jal, 0b1101111); + +#undef INSN + +#define INSN(NAME) \ void NAME(Register Rd, const address dest, Register temp = t0) { \ assert_cond(dest != NULL); \ int64_t offset = dest - pc(); \ @@ -786,7 +833,7 @@ class Assembler : public AbstractAssembler { wrap_label(Rd, L, temp, &Assembler::NAME); \ } - INSN(jal, 0b1101111); + INSN(jal); #undef INSN @@ -794,8 +841,8 @@ class Assembler : public AbstractAssembler { #define INSN(NAME, op, funct) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch_reg((address)&insn, 7, Rd); \ patch((address)&insn, 14, 12, funct); \ @@ -805,7 +852,7 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(jalr, 0b1100111, 0b000); + INSN(_jalr, 0b1100111, 0b000); #undef INSN @@ -841,7 +888,8 @@ class Assembler : public AbstractAssembler { INSN(fence_i, 0b0001111, 0b001, 0b000000000000); INSN(ecall, 0b1110011, 0b000, 0b000000000000); - INSN(ebreak, 0b1110011, 0b000, 0b000000000001); + INSN(_ebreak, 0b1110011, 0b000, 0b000000000001); + #undef INSN enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; @@ -949,12 +997,12 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(addi, 0b0010011, 0b000); - INSN(slti, 0b0010011, 0b010); - INSN(addiw, 0b0011011, 0b000); - INSN(and_imm12, 0b0010011, 0b111); - INSN(ori, 0b0010011, 0b110); - INSN(xori, 0b0010011, 0b100); + INSN(_addi, 0b0010011, 0b000); + INSN(slti, 0b0010011, 0b010); + INSN(_addiw, 0b0011011, 0b000); + INSN(_and_imm12, 0b0010011, 0b111); + INSN(ori, 0b0010011, 0b110); + INSN(xori, 0b0010011, 0b100); #undef INSN @@ -988,9 +1036,9 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(slli, 0b0010011, 0b001, 0b000000); - INSN(srai, 0b0010011, 0b101, 0b010000); - INSN(srli, 0b0010011, 0b101, 0b000000); + INSN(_slli, 0b0010011, 0b001, 0b000000); + INSN(_srai, 0b0010011, 0b101, 0b010000); + INSN(_srli, 0b0010011, 0b101, 0b000000); #undef INSN @@ -1026,7 +1074,7 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(lui, 0b0110111); + INSN(_lui, 0b0110111); INSN(auipc, 0b0010111); #undef INSN @@ -1971,6 +2019,963 @@ enum Nf { #undef INSN +// ======================================== +// RISC-V Compressed Instructions Extension +// ======================================== +// Note: +// 1. When UseRVC is enabled, 32-bit instructions under 'CompressibleRegion's will be +// transformed to 16-bit instructions if compressible. +// 2. RVC instructions in Assembler always begin with 'c_' prefix, as 'c_li', +// but most of time we have no need to explicitly use these instructions. +// 3. 'CompressibleRegion' is introduced to hint instructions in this Region's RTTI range +// are qualified to be compressed with their 2-byte versions. +// An example: +// +// CompressibleRegion cr(_masm); +// __ andr(...); // this instruction could change to c.and if able to +// +// 4. Using -XX:PrintAssemblyOptions=no-aliases could distinguish RVC instructions from +// normal ones. +// + +private: + bool _in_compressible_region; +public: + bool in_compressible_region() const { return _in_compressible_region; } + void set_in_compressible_region(bool b) { _in_compressible_region = b; } +public: + + // a compressible region + class CompressibleRegion : public StackObj { + protected: + Assembler *_masm; + bool _saved_in_compressible_region; + public: + CompressibleRegion(Assembler *_masm) + : _masm(_masm) + , _saved_in_compressible_region(_masm->in_compressible_region()) { + _masm->set_in_compressible_region(true); + } + ~CompressibleRegion() { + _masm->set_in_compressible_region(_saved_in_compressible_region); + } + }; + + // patch a 16-bit instruction. + static void c_patch(address a, unsigned msb, unsigned lsb, uint16_t val) { + assert_cond(a != NULL); + assert_cond(msb >= lsb && msb <= 15); + unsigned nbits = msb - lsb + 1; + guarantee(val < (1U << nbits), "Field too big for insn"); + uint16_t mask = (1U << nbits) - 1; + val <<= lsb; + mask <<= lsb; + uint16_t target = *(uint16_t *)a; + target &= ~mask; + target |= val; + *(uint16_t *)a = target; + } + + static void c_patch(address a, unsigned bit, uint16_t val) { + c_patch(a, bit, bit, val); + } + + // patch a 16-bit instruction with a general purpose register ranging [0, 31] (5 bits) + static void c_patch_reg(address a, unsigned lsb, Register reg) { + c_patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + // patch a 16-bit instruction with a general purpose register ranging [8, 15] (3 bits) + static void c_patch_compressed_reg(address a, unsigned lsb, Register reg) { + c_patch(a, lsb + 2, lsb, reg->compressed_encoding_nocheck()); + } + + // patch a 16-bit instruction with a float register ranging [0, 31] (5 bits) + static void c_patch_reg(address a, unsigned lsb, FloatRegister reg) { + c_patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + // patch a 16-bit instruction with a float register ranging [8, 15] (3 bits) + static void c_patch_compressed_reg(address a, unsigned lsb, FloatRegister reg) { + c_patch(a, lsb + 2, lsb, reg->compressed_encoding_nocheck()); + } + +// -------------- RVC Instruction Definitions -------------- + + void c_nop() { + c_addi(x0, 0); + } + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi, 0b000, 0b01); + INSN(c_addiw, 0b001, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 10, 0)); \ + assert_cond((imm & 0b1111) == 0); \ + assert_cond(imm != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 4, 3, (imm & right_n_bits(9)) >> 7); \ + c_patch((address)&insn, 5, 5, (imm & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 6, 6, (imm & nth_bit(4)) >> 4); \ + c_patch_reg((address)&insn, 7, sp); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(9)) >> 9); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi16sp, 0b011, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 10, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + assert_cond(uimm != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd); \ + c_patch((address)&insn, 5, 5, (uimm & nth_bit(3)) >> 3); \ + c_patch((address)&insn, 6, 6, (uimm & nth_bit(2)) >> 2); \ + c_patch((address)&insn, 10, 7, (uimm & right_n_bits(10)) >> 6); \ + c_patch((address)&insn, 12, 11, (uimm & right_n_bits(6)) >> 4); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi4spn, 0b000, 0b00); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs1, uint32_t shamt) { \ + assert_cond(is_unsigned_imm_in_range(shamt, 6, 0)); \ + assert_cond(shamt != 0); \ + assert_cond(Rd_Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (shamt & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 12, 12, (shamt & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_slli, 0b000, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, funct2, op) \ + void NAME(Register Rd_Rs1, uint32_t shamt) { \ + assert_cond(is_unsigned_imm_in_range(shamt, 6, 0)); \ + assert_cond(shamt != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (shamt & right_n_bits(5))); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 11, 10, funct2); \ + c_patch((address)&insn, 12, 12, (shamt & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_srli, 0b100, 0b00, 0b01); + INSN(c_srai, 0b100, 0b01, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, funct2, op) \ + void NAME(Register Rd_Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 11, 10, funct2); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_andi, 0b100, 0b10, 0b01); + +#undef INSN + +#define INSN(NAME, funct6, funct2, op) \ + void NAME(Register Rd_Rs1, Register Rs2) { \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 6, 5, funct2); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 15, 10, funct6); \ + emit_int16(insn); \ + } + + INSN(c_sub, 0b100011, 0b00, 0b01); + INSN(c_xor, 0b100011, 0b01, 0b01); + INSN(c_or, 0b100011, 0b10, 0b01); + INSN(c_and, 0b100011, 0b11, 0b01); + INSN(c_subw, 0b100111, 0b00, 0b01); + INSN(c_addw, 0b100111, 0b01, 0b01); + +#undef INSN + +#define INSN(NAME, funct4, op) \ + void NAME(Register Rd_Rs1, Register Rs2) { \ + assert_cond(Rd_Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 15, 12, funct4); \ + emit_int16(insn); \ + } + + INSN(c_mv, 0b1000, 0b10); + INSN(c_add, 0b1001, 0b10); + +#undef INSN + +#define INSN(NAME, funct4, op) \ + void NAME(Register Rs1) { \ + assert_cond(Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, x0); \ + c_patch_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 15, 12, funct4); \ + emit_int16(insn); \ + } + + INSN(c_jr, 0b1000, 0b10); + INSN(c_jalr, 0b1001, 0b10); + +#undef INSN + + typedef void (Assembler::* j_c_insn)(address dest); + typedef void (Assembler::* compare_and_branch_c_insn)(Register Rs1, address dest); + + void wrap_label(Label &L, j_c_insn insn) { + if (L.is_bound()) { + (this->*insn)(target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(pc()); + } + } + + void wrap_label(Label &L, Register r, compare_and_branch_c_insn insn) { + if (L.is_bound()) { + (this->*insn)(r, target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(r, pc()); + } + } + +#define INSN(NAME, funct3, op) \ + void NAME(int32_t offset) { \ + assert_cond(is_imm_in_range(offset, 11, 1)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (offset & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 5, 3, (offset & right_n_bits(4)) >> 1); \ + c_patch((address)&insn, 6, 6, (offset & nth_bit(7)) >> 7); \ + c_patch((address)&insn, 7, 7, (offset & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 8, 8, (offset & nth_bit(10)) >> 10); \ + c_patch((address)&insn, 10, 9, (offset & right_n_bits(10)) >> 8); \ + c_patch((address)&insn, 11, 11, (offset & nth_bit(4)) >> 4); \ + c_patch((address)&insn, 12, 12, (offset & nth_bit(11)) >> 11); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } \ + void NAME(address dest) { \ + assert_cond(dest != NULL); \ + int64_t distance = dest - pc(); \ + assert_cond(is_imm_in_range(distance, 11, 1)); \ + c_j(distance); \ + } \ + void NAME(Label &L) { \ + wrap_label(L, &Assembler::NAME); \ + } + + INSN(c_j, 0b101, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 8, 1)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 4, 3, (imm & right_n_bits(3)) >> 1); \ + c_patch((address)&insn, 6, 5, (imm & right_n_bits(8)) >> 6); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 11, 10, (imm & right_n_bits(5)) >> 3); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(8)) >> 8); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } \ + void NAME(Register Rs1, address dest) { \ + assert_cond(dest != NULL); \ + int64_t distance = dest - pc(); \ + assert_cond(is_imm_in_range(distance, 8, 1)); \ + NAME(Rs1, distance); \ + } \ + void NAME(Register Rs1, Label &L) { \ + wrap_label(L, Rs1, &Assembler::NAME); \ + } + + INSN(c_beqz, 0b110, 0b01); + INSN(c_bnez, 0b111, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 18, 0)); \ + assert_cond((imm & 0xfff) == 0); \ + assert_cond(imm != 0); \ + assert_cond(Rd != x0 && Rd != x2); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(17)) >> 12); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(17)) >> 17); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lui, 0b011, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (imm & right_n_bits(6)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_li, 0b010, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 4, 2, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(5)) >> 3); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ldsp, 0b011, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(FloatRegister Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 4, 2, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(5)) >> 3); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_fldsp, 0b001, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op, REGISTER_TYPE) \ + void NAME(REGISTER_TYPE Rd_Rs2, Register Rs1, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd_Rs2); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(8)) >> 6); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ld, 0b011, 0b00, Register); + INSN(c_sd, 0b111, 0b00, Register); + INSN(c_fld, 0b001, 0b00, FloatRegister); + INSN(c_fsd, 0b101, 0b00, FloatRegister); + +#undef INSN + +#define INSN(NAME, funct3, op, REGISTER_TYPE) \ + void NAME(REGISTER_TYPE Rs2, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 9, 7, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_sdsp, 0b111, 0b10, Register); + INSN(c_fsdsp, 0b101, 0b10, FloatRegister); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rs2, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 8, 7, (uimm & right_n_bits(8)) >> 6); \ + c_patch((address)&insn, 12, 9, (uimm & right_n_bits(6)) >> 2); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_swsp, 0b110, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 3, 2, (uimm & right_n_bits(8)) >> 6); \ + c_patch((address)&insn, 6, 4, (uimm & right_n_bits(5)) >> 2); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lwsp, 0b010, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs2, Register Rs1, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 7, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd_Rs2); \ + c_patch((address)&insn, 5, 5, (uimm & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 6, 6, (uimm & nth_bit(2)) >> 2); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lw, 0b010, 0b00); + INSN(c_sw, 0b110, 0b00); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME() { \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 11, 2, 0x0); \ + c_patch((address)&insn, 12, 12, 0b1); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ebreak, 0b100, 0b10); + +#undef INSN + +// -------------- RVC Transformation Functions -------------- + +// -------------------------- +// Register instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* add -> c.add */ \ + if (do_compress()) { \ + Register src = noreg; \ + if (Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ + c_add(Rd, src); \ + return; \ + } \ + } \ + _add(Rd, Rs1, Rs2); \ + } + + INSN(add); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* sub/subw -> c.sub/c.subw */ \ + if (do_compress() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid())) { \ + C_NAME(Rd, Rs2); \ + return; \ + } \ + NORMAL_NAME(Rd, Rs1, Rs2); \ + } + + INSN(sub, c_sub, _sub); + INSN(subw, c_subw, _subw); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* and/or/xor/addw -> c.and/c.or/c.xor/c.addw */ \ + if (do_compress()) { \ + Register src = noreg; \ + if (Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ + C_NAME(Rd, src); \ + return; \ + } \ + } \ + NORMAL_NAME(Rd, Rs1, Rs2); \ + } + + INSN(andr, c_and, _andr); + INSN(orr, c_or, _orr); + INSN(xorr, c_xor, _xorr); + INSN(addw, c_addw, _addw); + +#undef INSN + +private: +// some helper functions + bool do_compress() const { + return UseRVC && in_compressible_region(); + } + +#define FUNC(NAME, funct3, bits) \ + bool NAME(Register rs1, Register rd_rs2, int32_t imm12, bool ld) { \ + return rs1 == sp && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0 && \ + (!ld || rd_rs2 != x0); \ + } \ + + FUNC(is_c_ldsdsp, 0b111, 9); + FUNC(is_c_lwswsp, 0b011, 8); + +#undef FUNC + +#define FUNC(NAME, funct3, bits) \ + bool NAME(Register rs1, int32_t imm12) { \ + return rs1 == sp && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0; \ + } \ + + FUNC(is_c_fldsdsp, 0b111, 9); + +#undef FUNC + +#define FUNC(NAME, REG_TYPE, funct3, bits) \ + bool NAME(Register rs1, REG_TYPE rd_rs2, int32_t imm12) { \ + return rs1->is_compressed_valid() && \ + rd_rs2->is_compressed_valid() && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0; \ + } \ + + FUNC(is_c_ldsd, Register, 0b111, 8); + FUNC(is_c_lwsw, Register, 0b011, 7); + FUNC(is_c_fldsd, FloatRegister, 0b111, 8); + +#undef FUNC + +public: +// -------------------------- +// Load/store register +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* lw -> c.lwsp/c.lw */ \ + if (do_compress()) { \ + if (is_c_lwswsp(Rs, Rd, offset, true)) { \ + c_lwsp(Rd, offset); \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ + c_lw(Rd, Rs, offset); \ + return; \ + } \ + } \ + _lw(Rd, Rs, offset); \ + } + + INSN(lw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* ld -> c.ldsp/c.ld */ \ + if (do_compress()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, true)) { \ + c_ldsp(Rd, offset); \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ + c_ld(Rd, Rs, offset); \ + return; \ + } \ + } \ + _ld(Rd, Rs, offset); \ + } + + INSN(ld); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + /* fld -> c.fldsp/c.fld */ \ + if (do_compress()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ + c_fldsp(Rd, offset); \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ + c_fld(Rd, Rs, offset); \ + return; \ + } \ + } \ + _fld(Rd, Rs, offset); \ + } + + INSN(fld); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* sd -> c.sdsp/c.sd */ \ + if (do_compress()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, false)) { \ + c_sdsp(Rd, offset); \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ + c_sd(Rd, Rs, offset); \ + return; \ + } \ + } \ + _sd(Rd, Rs, offset); \ + } + + INSN(sd); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* sw -> c.swsp/c.sw */ \ + if (do_compress()) { \ + if (is_c_lwswsp(Rs, Rd, offset, false)) { \ + c_swsp(Rd, offset); \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ + c_sw(Rd, Rs, offset); \ + return; \ + } \ + } \ + _sw(Rd, Rs, offset); \ + } + + INSN(sw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + /* fsd -> c.fsdsp/c.fsd */ \ + if (do_compress()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ + c_fsdsp(Rd, offset); \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ + c_fsd(Rd, Rs, offset); \ + return; \ + } \ + } \ + _fsd(Rd, Rs, offset); \ + } + + INSN(fsd); + +#undef INSN + +// -------------------------- +// Conditional branch instructions +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + /* beq/bne -> c.beqz/c.bnez */ \ + if (do_compress() && \ + (offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1))) { \ + C_NAME(Rs1, offset); \ + return; \ + } \ + NORMAL_NAME(Rs1, Rs2, offset); \ + } + + INSN(beq, c_beqz, _beq); + INSN(bne, c_beqz, _bne); + +#undef INSN + +// -------------------------- +// Unconditional branch instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, const int32_t offset) { \ + /* jal -> c.j */ \ + if (do_compress() && offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) { \ + c_j(offset); \ + return; \ + } \ + _jal(Rd, offset); \ + } + + INSN(jal); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* jalr -> c.jr/c.jalr */ \ + if (do_compress() && (offset == 0 && Rs != x0)) { \ + if (Rd == x1) { \ + c_jalr(Rs); \ + return; \ + } else if (Rd == x0) { \ + c_jr(Rs); \ + return; \ + } \ + } \ + _jalr(Rd, Rs, offset); \ + } + + INSN(jalr); + +#undef INSN + +// -------------------------- +// Miscellaneous Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME() { \ + /* ebreak -> c.ebreak */ \ + if (do_compress()) { \ + c_ebreak(); \ + return; \ + } \ + _ebreak(); \ + } + + INSN(ebreak); + +#undef INSN + +#define INSN(NAME) \ + void NAME() { \ + /* The illegal instruction in RVC is presented by a 16-bit 0. */ \ + if (do_compress()) { \ + emit_int16(0); \ + return; \ + } \ + _halt(); \ + } + + INSN(halt); + +#undef INSN + +// -------------------------- +// Immediate Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, int64_t imm) { \ + /* li -> c.li */ \ + if (do_compress() && (is_imm_in_range(imm, 6, 0) && Rd != x0)) { \ + c_li(Rd, imm); \ + return; \ + } \ + _li(Rd, imm); \ + } + + INSN(li); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn */ \ + if (do_compress()) { \ + if (Rd == Rs1 && is_imm_in_range(imm, 6, 0)) { \ + c_addi(Rd, imm); \ + return; \ + } else if (imm == 0 && Rd != x0 && Rs1 != x0) { \ + c_mv(Rd, Rs1); \ + return; \ + } else if (Rs1 == sp && imm != 0) { \ + if (Rd == Rs1 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0)) { \ + c_addi16sp(imm); \ + return; \ + } else if (Rd->is_compressed_valid() && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0)) { \ + c_addi4spn(Rd, imm); \ + return; \ + } \ + } \ + } \ + _addi(Rd, Rs1, imm); \ + } + + INSN(addi); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* addiw -> c.addiw */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0))) { \ + c_addiw(Rd, imm); \ + return; \ + } \ + _addiw(Rd, Rs1, imm); \ + } + + INSN(addiw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* and_imm12 -> c.andi */ \ + if (do_compress() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0))) { \ + c_andi(Rd, imm); \ + return; \ + } \ + _and_imm12(Rd, Rs1, imm); \ + } + + INSN(and_imm12); + +#undef INSN + +// -------------------------- +// Shift Immediate Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + /* slli -> c.slli */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && shamt != 0)) { \ + c_slli(Rd, shamt); \ + return; \ + } \ + _slli(Rd, Rs1, shamt); \ + } + + INSN(slli); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + /* srai/srli -> c.srai/c.srli */ \ + if (do_compress() && (Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0)) { \ + C_NAME(Rd, shamt); \ + return; \ + } \ + NORMAL_NAME(Rd, Rs1, shamt); \ + } + + INSN(srai, c_srai, _srai); + INSN(srli, c_srli, _srli); + +#undef INSN + +// -------------------------- +// Upper Immediate Instruction +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, int32_t imm) { \ + /* lui -> c.lui */ \ + if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0))) { \ + c_lui(Rd, imm); \ + return; \ + } \ + _lui(Rd, imm); \ + } + + INSN(lui); + +#undef INSN + +// --------------------------------------------------------------------------------------- + void bgt(Register Rs, Register Rt, const address &dest); void ble(Register Rs, Register Rt, const address &dest); void bgtu(Register Rs, Register Rt, const address &dest); @@ -2000,7 +3005,7 @@ enum Nf { // zero extend word void zext_w(Register Rd, Register Rs); - Assembler(CodeBuffer* code) : AbstractAssembler(code) { + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(false) { } // Stack overflow checking @@ -2022,6 +3027,4 @@ enum Nf { }; -class BiasedLockingCounters; - #endif // CPU_RISCV_ASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index b0406c9fb28..e45deb49191 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1322,7 +1322,11 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } } -void LIR_Assembler::align_call(LIR_Code code) { } +void LIR_Assembler::align_call(LIR_Code code) { + // With RVC a call instruction (which will be patched later) may get 2-byte aligned and could + // span multiple cache lines. See CallStaticJavaDirectNode::compute_padding() for more info. + __ align(4); +} void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { address call = __ trampoline_call(Address(op->addr(), rtype)); @@ -1344,6 +1348,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { void LIR_Assembler::emit_static_call_stub() { address call_pc = __ pc(); + assert((__ offset() % 4) == 0, "call sites must be properly aligned"); address stub = __ start_a_stub(call_stub_size()); if (stub == NULL) { bailout("static call stub overflow"); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index f23ff34e3f4..bd39bfc29a2 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -238,6 +238,9 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { return; } + // RISCV's amoswap instructions require that the memory address must be naturally aligned. + __ align(4); + Label skip, guard; Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset())); @@ -256,6 +259,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { __ bind(guard); + assert(__ offset() % 4 == 0, "bad alignment"); __ emit_int32(0); // nmethod guard value. Skipped over in common case. __ bind(skip); diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index e5292719ff5..004b12f15a9 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -91,6 +91,7 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, AvoidUnalignedAccesses, true, \ "Avoid generating unaligned memory accesses") \ product(bool, UseRVV, false, EXPERIMENTAL, "Use RVV instructions") \ - product(bool, UseRVB, false, EXPERIMENTAL, "Use RVB instructions") + product(bool, UseRVB, false, EXPERIMENTAL, "Use RVB instructions") \ + product(bool, UseRVC, false, EXPERIMENTAL, "Use RVC instructions") #endif // CPU_RISCV_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index dcdeac65061..5255abe0762 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -88,8 +88,9 @@ static void pass_arg3(MacroAssembler* masm, Register arg) { } } -void MacroAssembler::align(int modulus) { - while (offset() % modulus != 0) { nop(); } +void MacroAssembler::align(int modulus, int extra_offset) { + CompressibleRegion cr(this); + while ((offset() + extra_offset) % modulus != 0) { nop(); } } void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { @@ -801,6 +802,7 @@ void MacroAssembler::la(Register Rd, Label &label) { INSN(beq, feq, bnez); INSN(bne, feq, beqz); + #undef INSN @@ -960,6 +962,7 @@ int MacroAssembler::bitset_to_regs(unsigned int bitset, unsigned char* regs) { // Return the number of words pushed int MacroAssembler::push_reg(unsigned int bitset, Register stack) { DEBUG_ONLY(int words_pushed = 0;) + CompressibleRegion cr(this); unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -981,6 +984,7 @@ int MacroAssembler::push_reg(unsigned int bitset, Register stack) { int MacroAssembler::pop_reg(unsigned int bitset, Register stack) { DEBUG_ONLY(int words_popped = 0;) + CompressibleRegion cr(this); unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -1003,6 +1007,7 @@ int MacroAssembler::pop_reg(unsigned int bitset, Register stack) { // Push float registers in the bitset, except sp. // Return the number of heapwords pushed. int MacroAssembler::push_fp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); int words_pushed = 0; unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -1022,6 +1027,7 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack) { } int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); int words_popped = 0; unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -1042,6 +1048,7 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { #ifdef COMPILER2 int MacroAssembler::push_vp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); // Scan bitset to accumulate register pairs @@ -1063,6 +1070,7 @@ int MacroAssembler::push_vp(unsigned int bitset, Register stack) { } int MacroAssembler::pop_vp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); // Scan bitset to accumulate register pairs @@ -1085,6 +1093,7 @@ int MacroAssembler::pop_vp(unsigned int bitset, Register stack) { #endif // COMPILER2 void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude) { + CompressibleRegion cr(this); // Push integer registers x7, x10-x17, x28-x31. push_reg(RegSet::of(x7) + RegSet::range(x10, x17) + RegSet::range(x28, x31) - exclude, sp); @@ -1099,6 +1108,7 @@ void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude) { } void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { + CompressibleRegion cr(this); int offset = 0; for (int i = 0; i < 32; i++) { if (i <= f7->encoding() || i >= f28->encoding() || (i >= f10->encoding() && i <= f17->encoding())) { @@ -1112,15 +1122,18 @@ void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { // Push all the integer registers, except zr(x0) & sp(x2) & gp(x3) & tp(x4). void MacroAssembler::pusha() { + CompressibleRegion cr(this); push_reg(0xffffffe2, sp); } // Pop all the integer registers, except zr(x0) & sp(x2) & gp(x3) & tp(x4). void MacroAssembler::popa() { + CompressibleRegion cr(this); pop_reg(0xffffffe2, sp); } void MacroAssembler::push_CPU_state(bool save_vectors, int vector_size_in_bytes) { + CompressibleRegion cr(this); // integer registers, except zr(x0) & ra(x1) & sp(x2) & gp(x3) & tp(x4) push_reg(0xffffffe0, sp); @@ -1142,6 +1155,7 @@ void MacroAssembler::push_CPU_state(bool save_vectors, int vector_size_in_bytes) } void MacroAssembler::pop_CPU_state(bool restore_vectors, int vector_size_in_bytes) { + CompressibleRegion cr(this); // vector registers if (restore_vectors) { vsetvli(t0, x0, Assembler::e64, Assembler::m8); @@ -1308,7 +1322,10 @@ int MacroAssembler::pd_patch_instruction_size(address branch, address target) { int64_t imm = (intptr_t)target; return patch_imm_in_li32(branch, (int32_t)imm); } else { - tty->print_cr("pd_patch_instruction_size: instruction 0x%x could not be patched!\n", *(unsigned*)branch); +#ifdef ASSERT + tty->print_cr("pd_patch_instruction_size: instruction 0x%x at " INTPTR_FORMAT " could not be patched!\n", *(unsigned*)branch, p2i(branch)); + Disassembler::decode(branch - 10, branch + 10); +#endif ShouldNotReachHere(); } return -1; @@ -2917,7 +2934,8 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, // make sure 4 byte aligned here, so that the destination address would be // 8 byte aligned after 3 intructions - while (offset() % wordSize == 0) { nop(); } + // when we reach here we may get a 2-byte alignment so need to align it + align(wordSize, NativeCallTrampolineStub::data_offset); relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset)); @@ -2932,6 +2950,7 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, bind(target); assert(offset() - stub_start_offset == NativeCallTrampolineStub::data_offset, "should be"); + assert(offset() % wordSize == 0, "address loaded by ld must be 8-byte aligned under riscv64"); emit_int64((intptr_t)dest); const address stub_start_addr = addr_at(stub_start_offset); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 5f05b95a75d..4e6203252a6 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -49,7 +49,7 @@ class MacroAssembler: public Assembler { void safepoint_ifence(); // Alignment - void align(int modulus); + void align(int modulus, int extra_offset = 0); // Stack frame creation/removal void enter() { @@ -445,11 +445,11 @@ class MacroAssembler: public Assembler { void fsflagsi(unsigned imm); void beqz(Register Rs, const address &dest); + void bnez(Register Rs, const address &dest); void blez(Register Rs, const address &dest); void bgez(Register Rs, const address &dest); void bltz(Register Rs, const address &dest); void bgtz(Register Rs, const address &dest); - void bnez(Register Rs, const address &dest); void la(Register Rd, Label &label); void la(Register Rd, const address &dest); void la(Register Rd, const Address &adr); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 117d58e8e28..dffe6f152ae 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -53,7 +53,8 @@ class NativeInstruction { friend bool is_NativeCallTrampolineStub_at(address); public: enum { - instruction_size = 4 + instruction_size = 4, + compressed_instruction_size = 2, }; juint encoding() const { @@ -422,10 +423,10 @@ inline NativeMovRegMem* nativeMovRegMem_at (address addr) { class NativeJump: public NativeInstruction { public: enum RISCV64_specific_constants { - instruction_size = 4, + instruction_size = NativeInstruction::instruction_size, instruction_offset = 0, data_offset = 0, - next_instruction_offset = 4 + next_instruction_offset = NativeInstruction::instruction_size }; address instruction_address() const { return addr_at(instruction_offset); } diff --git a/src/hotspot/cpu/riscv/register_riscv.hpp b/src/hotspot/cpu/riscv/register_riscv.hpp index e3203a5f032..771d78f9429 100644 --- a/src/hotspot/cpu/riscv/register_riscv.hpp +++ b/src/hotspot/cpu/riscv/register_riscv.hpp @@ -58,7 +58,11 @@ class RegisterImpl: public AbstractRegisterImpl { enum { number_of_registers = 32, number_of_byte_registers = 32, - max_slots_per_register = 2 + max_slots_per_register = 2, + + // integer registers in the range of [x8~x15] correspond to RVC. Please see Table 16.2 in spec. + compressed_register_base = 8, + compressed_register_top = 15, }; // derived registers, offsets, and addresses @@ -71,10 +75,13 @@ class RegisterImpl: public AbstractRegisterImpl { // accessors int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } + int compressed_encoding() const { assert(is_compressed_valid(), "invalid compressed register"); return ((intptr_t)this - compressed_register_base); } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } + bool is_compressed_valid() const { return compressed_register_base <= (intptr_t)this && (intptr_t)this <= compressed_register_top; } bool has_byte_register() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_byte_registers; } const char* name() const; int encoding_nocheck() const { return (intptr_t)this; } + int compressed_encoding_nocheck() const { return ((intptr_t)this - compressed_register_base); } // Return the bit which represents this register. This is intended // to be ORed into a bitmask: for usage see class RegSet below. @@ -131,7 +138,11 @@ class FloatRegisterImpl: public AbstractRegisterImpl { public: enum { number_of_registers = 32, - max_slots_per_register = 2 + max_slots_per_register = 2, + + // float registers in the range of [f8~f15] correspond to RVC. Please see Table 16.2 in spec. + compressed_register_base = 8, + compressed_register_top = 15, }; // construction @@ -144,8 +155,11 @@ class FloatRegisterImpl: public AbstractRegisterImpl { // accessors int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } + int compressed_encoding() const { assert(is_compressed_valid(), "invalid compressed register"); return ((intptr_t)this - compressed_register_base); } int encoding_nocheck() const { return (intptr_t)this; } + int compressed_encoding_nocheck() const { return ((intptr_t)this - compressed_register_base); } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } + bool is_compressed_valid() const { return compressed_register_base <= (intptr_t)this && (intptr_t)this <= compressed_register_top; } const char* name() const; }; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 6f943f55c1e..0f5e4742e33 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1156,14 +1156,13 @@ bool needs_acquiring_load_reserved(const Node *n) int MachCallStaticJavaNode::ret_addr_offset() { - // call should be a simple jal - int off = 4; - return off; + // jal + return 1 * NativeInstruction::instruction_size; } int MachCallDynamicJavaNode::ret_addr_offset() { - return 28; // movptr, jal + return 7 * NativeInstruction::instruction_size; // movptr, jal } int MachCallRuntimeNode::ret_addr_offset() { @@ -1171,13 +1170,13 @@ int MachCallRuntimeNode::ret_addr_offset() { // jal(addr) // or with far branches // jal(trampoline_stub) - // for real runtime callouts it will be five instructions + // for real runtime callouts it will be 11 instructions // see riscv64_enc_java_to_runtime - // la(t1, retaddr) - // la(t0, RuntimeAddress(addr)) - // addi(sp, sp, -2 * wordSize) - // sd(t1, Address(sp, wordSize)) - // jalr(t0) + // la(t1, retaddr) -> auipc + addi + // la(t0, RuntimeAddress(addr)) -> lui + addi + slli + addi + slli + addi + // addi(sp, sp, -2 * wordSize) -> addi + // sd(t1, Address(sp, wordSize)) -> sd + // jalr(t0) -> jalr CodeBlob *cb = CodeCache::find_blob(_entry_point); if (cb != NULL) { return 1 * NativeInstruction::instruction_size; @@ -1191,6 +1190,29 @@ int MachCallNativeNode::ret_addr_offset() { return -1; } +// With RVC a call site may get 2-byte aligned. +// The offset encoding in jal instruction bits [12, 31] could span multiple cache lines. +// Patching this jal instruction will not be atomic when its address is not naturally aligned. +// Other threads may be running the same piece of code at the same time, thus causing concurrency issues. +int CallStaticJavaDirectNode::compute_padding(int current_offset) const +{ + // to make sure the address of jal 4-byte aligned. + return align_up(current_offset, alignment_required()) - current_offset; +} + +// Please see CallStaticJavaDirectNode::compute_padding() for more info. +int CallDynamicJavaDirectNode::compute_padding(int current_offset) const +{ + // skip the movptr in MacroAssembler::ic_call(): + // lui + addi + slli + addi + slli + addi + // Though movptr() has already 4-byte aligned with or without RVC, + // We need to prevent from further changes by explicitly calculating the size. + const int movptr_size = 6 * NativeInstruction::instruction_size; + current_offset += movptr_size; + // to make sure the address of jal 4-byte aligned. + return align_up(current_offset, alignment_required()) - current_offset; +} + //============================================================================= #ifndef PRODUCT @@ -1202,6 +1224,7 @@ void MachBreakpointNode::format(PhaseRegAlloc *ra_, outputStream *st) const { void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); __ ebreak(); } @@ -1219,13 +1242,14 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); // nops shall be 2-byte under RVC for alignment purposes. for (int i = 0; i < _count; i++) { __ nop(); } } uint MachNopNode::size(PhaseRegAlloc*) const { - return _count * NativeInstruction::instruction_size; + return _count * (UseRVC ? NativeInstruction::compressed_instruction_size : NativeInstruction::instruction_size); } //============================================================================= @@ -1487,6 +1511,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo uint ireg = ideal_reg(); if (ireg == Op_VecA && cbuf) { C2_MacroAssembler _masm(cbuf); + Assembler::CompressibleRegion cr(&_masm); int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { // stack to stack @@ -1507,6 +1532,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo } } else if (cbuf != NULL) { C2_MacroAssembler _masm(cbuf); + Assembler::CompressibleRegion cr(&_masm); switch (src_lo_rc) { case rc_int: if (dst_lo_rc == rc_int) { // gpr --> gpr copy @@ -2044,6 +2070,7 @@ encode %{ enc_class riscv64_enc_li_imm(iRegIorL dst, immIorL src) %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); int64_t con = (int64_t)$src$$constant; Register dst_reg = as_Register($dst$$reg); __ li(dst_reg, con); @@ -2070,6 +2097,7 @@ encode %{ enc_class riscv64_enc_mov_p1(iRegP dst) %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); Register dst_reg = as_Register($dst$$reg); __ li(dst_reg, 1); %} @@ -2482,12 +2510,14 @@ encode %{ enc_class riscv64_enc_tail_call(iRegP jump_target) %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); Register target_reg = as_Register($jump_target$$reg); __ jr(target_reg); %} enc_class riscv64_enc_tail_jmp(iRegP jump_target) %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); Register target_reg = as_Register($jump_target$$reg); // exception oop should be in x10 // ret addr has been popped into ra @@ -2503,6 +2533,7 @@ encode %{ enc_class riscv64_enc_ret() %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); __ ret(); %} @@ -4487,6 +4518,7 @@ instruct loadI(iRegINoSp dst, memory mem) format %{ "lw $dst, $mem\t# int, #@loadI" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ lw(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4502,6 +4534,7 @@ instruct loadI2L(iRegLNoSp dst, memory mem) format %{ "lw $dst, $mem\t# int, #@loadI2L" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ lw(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4532,6 +4565,7 @@ instruct loadL(iRegLNoSp dst, memory mem) format %{ "ld $dst, $mem\t# int, #@loadL" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4563,6 +4597,7 @@ instruct loadP(iRegPNoSp dst, memory mem) format %{ "ld $dst, $mem\t# ptr, #@loadP" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4593,6 +4628,7 @@ instruct loadKlass(iRegPNoSp dst, memory mem) format %{ "ld $dst, $mem\t# class, #@loadKlass" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4638,6 +4674,7 @@ instruct loadD(fRegD dst, memory mem) format %{ "fld $dst, $mem\t# double, #@loadD" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ fld(as_FloatRegister($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4922,6 +4959,7 @@ instruct storeI(iRegIorL2I src, memory mem) format %{ "sw $src, $mem\t# int, #@storeI" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4951,6 +4989,7 @@ instruct storeL(iRegL src, memory mem) format %{ "sd $src, $mem\t# long, #@storeL" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sd(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -4981,6 +5020,7 @@ instruct storeP(iRegP src, memory mem) format %{ "sd $src, $mem\t# ptr, #@storeP" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sd(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -5011,6 +5051,7 @@ instruct storeN(iRegN src, memory mem) format %{ "sw $src, $mem\t# compressed ptr, #@storeN" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -5055,6 +5096,7 @@ instruct storeD(fRegD src, memory mem) format %{ "fsd $src, $mem\t# double, #@storeD" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ fsd(as_FloatRegister($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -5070,6 +5112,7 @@ instruct storeNKlass(iRegN src, memory mem) format %{ "sw $src, $mem\t# compressed klass ptr, #@storeNKlass" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); %} @@ -6365,6 +6408,7 @@ instruct addI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ format %{ "addw $dst, $src1, $src2\t#@addI_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -6380,6 +6424,7 @@ instruct addI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAdd src2) %{ format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); int32_t con = (int32_t)$src2$$constant; __ addiw(as_Register($dst$$reg), as_Register($src1$$reg), @@ -6396,6 +6441,7 @@ instruct addI_reg_imm_l2i(iRegINoSp dst, iRegL src1, immIAdd src2) %{ format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm_l2i" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ addiw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant); @@ -6412,6 +6458,7 @@ instruct addP_reg_reg(iRegPNoSp dst, iRegP src1, iRegL src2) %{ format %{ "add $dst, $src1, $src2\t# ptr, #@addP_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -6427,6 +6474,7 @@ instruct lShiftL_regI_immGE32(iRegLNoSp dst, iRegI src, uimmI6_ge32 scale) %{ format %{ "slli $dst, $src, $scale & 63\t#@lShiftL_regI_immGE32" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ slli(as_Register($dst$$reg), as_Register($src$$reg), $scale$$constant & 63); %} @@ -6442,6 +6490,7 @@ instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAdd src2) %{ format %{ "addi $dst, $src1, $src2\t# ptr, #@addP_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // src2 is imm, so actually call the addi __ add(as_Register($dst$$reg), as_Register($src1$$reg), @@ -6458,6 +6507,7 @@ instruct addL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ format %{ "add $dst, $src1, $src2\t#@addL_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -6473,6 +6523,7 @@ instruct addL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ format %{ "addi $dst, $src1, $src2\t#@addL_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // src2 is imm, so actually call the addi __ add(as_Register($dst$$reg), as_Register($src1$$reg), @@ -6490,6 +6541,7 @@ instruct subI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ format %{ "subw $dst, $src1, $src2\t#@subI_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -6506,6 +6558,7 @@ instruct subI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immISub src2) %{ format %{ "addiw $dst, $src1, -$src2\t#@subI_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // src2 is imm, so actually call the addiw __ subw(as_Register($dst$$reg), as_Register($src1$$reg), @@ -6522,6 +6575,7 @@ instruct subL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ format %{ "sub $dst, $src1, $src2\t#@subL_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -6537,6 +6591,7 @@ instruct subL_reg_imm(iRegLNoSp dst, iRegL src1, immLSub src2) %{ format %{ "addi $dst, $src1, -$src2\t#@subL_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // src2 is imm, so actually call the addi __ sub(as_Register($dst$$reg), as_Register($src1$$reg), @@ -6666,6 +6721,7 @@ instruct signExtractL(iRegLNoSp dst, iRegL src1, immI_63 div1, immI_63 div2) %{ format %{ "srli $dst, $src1, $div1\t# long signExtract, #@signExtractL" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ srli(as_Register($dst$$reg), as_Register($src1$$reg), 63); %} ins_pipe(ialu_reg_shift); @@ -6821,6 +6877,7 @@ instruct lShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ format %{ "slli $dst, $src1, ($src2 & 0x3f)\t#@lShiftL_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // the shift amount is encoded in the lower // 6 bits of the I-immediate field for RV64I __ slli(as_Register($dst$$reg), @@ -6856,6 +6913,7 @@ instruct urShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ format %{ "srli $dst, $src1, ($src2 & 0x3f)\t#@urShiftL_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // the shift amount is encoded in the lower // 6 bits of the I-immediate field for RV64I __ srli(as_Register($dst$$reg), @@ -6874,6 +6932,7 @@ instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ format %{ "srli $dst, p2x($src1), ($src2 & 0x3f)\t#@urShiftP_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // the shift amount is encoded in the lower // 6 bits of the I-immediate field for RV64I __ srli(as_Register($dst$$reg), @@ -6909,6 +6968,7 @@ instruct rShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ format %{ "srai $dst, $src1, ($src2 & 0x3f)\t#@rShiftL_reg_imm" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); // the shift amount is encoded in the lower // 6 bits of the I-immediate field for RV64I __ srai(as_Register($dst$$reg), @@ -7372,6 +7432,7 @@ instruct andI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7388,6 +7449,7 @@ instruct andI_reg_imm(iRegINoSp dst, iRegI src1, immIAdd src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ andi(as_Register($dst$$reg), as_Register($src1$$reg), (int32_t)($src2$$constant)); @@ -7404,6 +7466,7 @@ instruct orI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7436,6 +7499,7 @@ instruct xorI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ xorr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7468,6 +7532,7 @@ instruct andL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7484,6 +7549,7 @@ instruct andL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ andi(as_Register($dst$$reg), as_Register($src1$$reg), (int32_t)($src2$$constant)); @@ -7500,6 +7566,7 @@ instruct orL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7532,6 +7599,7 @@ instruct xorL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ ins_cost(ALU_COST); ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ xorr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); @@ -7733,6 +7801,7 @@ instruct castX2P(iRegPNoSp dst, iRegL src) %{ format %{ "mv $dst, $src\t# long -> ptr, #@castX2P" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); if ($dst$$reg != $src$$reg) { __ mv(as_Register($dst$$reg), as_Register($src$$reg)); } @@ -7748,6 +7817,7 @@ instruct castP2X(iRegLNoSp dst, iRegP src) %{ format %{ "mv $dst, $src\t# ptr -> long, #@castP2X" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); if ($dst$$reg != $src$$reg) { __ mv(as_Register($dst$$reg), as_Register($src$$reg)); } @@ -7902,6 +7972,7 @@ instruct convI2UL_reg_reg(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) format %{ "zero_extend $dst, $src, 32\t# i2ul, #@convI2UL_reg_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ zero_extend(as_Register($dst$$reg), as_Register($src$$reg), 32); %} @@ -8056,6 +8127,7 @@ instruct convP2I(iRegINoSp dst, iRegP src) %{ format %{ "zero_extend $dst, $src, 32\t# ptr -> int, #@convP2I" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ zero_extend($dst$$Register, $src$$Register, 32); %} @@ -8073,6 +8145,7 @@ instruct convN2I(iRegINoSp dst, iRegN src) format %{ "mv $dst, $src\t# compressed ptr -> int, #@convN2I" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ mv($dst$$Register, $src$$Register); %} @@ -8169,6 +8242,7 @@ instruct MoveF2I_stack_reg(iRegINoSp dst, stackSlotF src) %{ format %{ "lw $dst, $src\t#@MoveF2I_stack_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ lw(as_Register($dst$$reg), Address(sp, $src$$disp)); %} @@ -8205,6 +8279,7 @@ instruct MoveD2L_stack_reg(iRegLNoSp dst, stackSlotD src) %{ format %{ "ld $dst, $src\t#@MoveD2L_stack_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ ld(as_Register($dst$$reg), Address(sp, $src$$disp)); %} @@ -8223,6 +8298,7 @@ instruct MoveL2D_stack_reg(fRegD dst, stackSlotL src) %{ format %{ "fld $dst, $src\t#@MoveL2D_stack_reg" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ fld(as_FloatRegister($dst$$reg), Address(sp, $src$$disp)); %} @@ -8259,6 +8335,7 @@ instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ format %{ "sw $src, $dst\t#@MoveI2F_reg_stack" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sw(as_Register($src$$reg), Address(sp, $dst$$disp)); %} @@ -8277,6 +8354,7 @@ instruct MoveD2L_reg_stack(stackSlotL dst, fRegD src) %{ format %{ "fsd $dst, $src\t#@MoveD2L_reg_stack" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ fsd(as_FloatRegister($src$$reg), Address(sp, $dst$$disp)); %} @@ -8295,6 +8373,7 @@ instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ format %{ "sd $src, $dst\t#@MoveL2D_reg_stack" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); __ sd(as_Register($src$$reg), Address(sp, $dst$$disp)); %} @@ -9831,6 +9910,7 @@ instruct CallStaticJavaDirect(method meth) riscv64_enc_call_epilog ); ins_pipe(pipe_class_call); + ins_alignment(4); %} // TO HERE @@ -9850,6 +9930,7 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) riscv64_enc_call_epilog ); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction @@ -10430,6 +10511,7 @@ instruct ShouldNotReachHere() %{ format %{ "#@ShouldNotReachHere" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); if (is_reachable()) { __ halt(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 619690a16d1..ce04ae19215 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -116,6 +116,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseRVB, false); } + if (UseRVC && !(_features & CPU_C)) { + warning("RVC is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVC, false); + } + if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true); }