From d1178a65468d1ad2c909825b66b50d6b16e97707 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Mon, 8 Nov 2021 16:24:11 +0800 Subject: [PATCH 01/21] RVC: basic instruction set --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 5 +- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 581 ++++++++++++++++++ src/hotspot/cpu/riscv/globals_riscv.hpp | 3 +- .../cpu/riscv/macroAssembler_riscv.cpp | 5 +- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 7 +- src/hotspot/cpu/riscv/register_riscv.hpp | 18 +- src/hotspot/cpu/riscv/riscv.ad | 19 +- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 6 + 8 files changed, 624 insertions(+), 20 deletions(-) create mode 100644 src/hotspot/cpu/riscv/assembler_riscv_c.hpp diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 100be449879..18cc6f7c879 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -255,6 +255,7 @@ class InternalAddress: public Address { class Assembler : public AbstractAssembler { public: + #include "assembler_riscv_c.hpp" enum { instruction_size = 4 }; @@ -2000,7 +2001,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 +2023,4 @@ enum Nf { }; -class BiasedLockingCounters; - #endif // CPU_RISCV_ASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp new file mode 100644 index 00000000000..2f66644cdd3 --- /dev/null +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -0,0 +1,581 @@ +/* + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP +#define CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP + +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: + + // C-Ext: If an instruction is compressible, then + // we will implicitly emit a 16-bit compressed instruction instead of the 32-bit + // instruction in Assembler. All below logic follows Chapter - + // "C" Standard Extension for Compressed Instructions, Version 2.0. + // We can get code size reduction and performance improvement with this extension, + // considering the reduction of instruction size and the code density increment. + + // Note: + // 1. When UseRVC is enabled, 32-bit instructions under 'CompressibleRegion's will be + // transformed to 16-bit instructions if compressible. + // 2. C-Ext's 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. In some cases, we need to force using one instruction's uncompressed version, + // for instance code being patched should remain its general and longest version + // to cover all possible cases, or code requiring a fixed length. + // So we introduce 'UncompressibleRegion' to force instructions in its range + // to remain its normal 4-byte version. + // An example: + // + // CompressibleRegion cr(_masm); + // __ andr(...); // this instruction could change to c.and if qualified + // { + // UncompressibleRegion ur(_masm); + // __ andr(...); // this instruction would remain the normal 32-bit form of andr + // } + // + // 4. Using -XX:PrintAssemblyOptions=no-aliases could print C-Ext instructions instead of + // normal ones. + // + + // C-Ext: extract a 16-bit instruction. + static inline uint16_t c_extract(uint16_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 15); + unsigned nbits = msb - lsb + 1; + uint16_t mask = (1U << nbits) - 1; + uint16_t result = val >> lsb; + result &= mask; + return result; + } + + static inline int16_t c_sextract(uint16_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 15); + int16_t result = val << (15 - msb); + result >>= (15 - msb + lsb); + return result; + } + + // C-Ext: 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); + } + + // C-Ext: 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()); + } + + // C-Ext: 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()); + } + + // C-Ext: 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()); + } + + // C-Ext: 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()); + } + +public: + +// C-Ext: Compressed Instructions + +// -------------- C-Ext 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, REGISTER_TYPE, CHECK) \ + void NAME(REGISTER_TYPE Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + IF(CHECK, 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); \ + } + +#define IF(BOOL, ...) IF_##BOOL(__VA_ARGS__) +#define IF_true(code) code +#define IF_false(code) + + INSN(c_ldsp, 0b011, 0b10, Register, true); + INSN(c_fldsp, 0b001, 0b10, FloatRegister, false); + +#undef IF_false +#undef IF_true +#undef IF +#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 + +public: +// C-Ext: an abstact compressible region +class AbstractCompressibleRegion : public StackObj { +protected: + Assembler *_masm; + bool _prev_in_compressible_region; +protected: + AbstractCompressibleRegion(Assembler *_masm) + : _masm(_masm) + , _prev_in_compressible_region(_masm->in_compressible_region()) {} +}; + +class CompressibleRegion : public AbstractCompressibleRegion { +public: + CompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { + _masm->set_in_compressible_region(true); + } + ~CompressibleRegion() { + _masm->set_in_compressible_region(_prev_in_compressible_region); + } +}; + +// C-Ext: an uncompressible region +class UncompressibleRegion : public AbstractCompressibleRegion { +public: + UncompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { + _masm->set_in_compressible_region(false); + } + ~UncompressibleRegion() { + _masm->set_in_compressible_region(_prev_in_compressible_region); + } +}; + +#endif // CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP \ No newline at end of file diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index e5292719ff5..f1e57f9e461 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..fb12b6e9064 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1308,7 +1308,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; 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..99c65b13b8a 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, + + // C-Ext: integer registers in the range of [x8~x15] are correspond for 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, + + // C-Ext: float registers in the range of [f8~f15] are correspond for 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..050881755ce 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; diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 619690a16d1..967f1ab56d8 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -101,6 +101,12 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseMD5Intrinsics, false); } + // compressed instruction extension + if (UseRVC && !(_features & CPU_C)) { + warning("RVC is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVC, false); + } + if (UseRVV) { if (!(_features & CPU_V)) { warning("RVV is not supported on this CPU"); From f68f2cb6f9dacf2e52215222e829289f714b4302 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 23 Dec 2021 16:30:07 +0800 Subject: [PATCH 02/21] Enable RVC instructions (based on the basic patch) --- src/hotspot/cpu/riscv/assembler_riscv.cpp | 5 + src/hotspot/cpu/riscv/assembler_riscv.hpp | 183 +++++----- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 323 ++++++++++++++++++ .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 7 +- src/hotspot/cpu/riscv/c2_globals_riscv.hpp | 2 +- .../gc/shared/barrierSetAssembler_riscv.cpp | 7 + .../gc/shared/barrierSetNMethod_riscv.cpp | 15 +- src/hotspot/cpu/riscv/globals_riscv.hpp | 2 +- .../cpu/riscv/macroAssembler_riscv.cpp | 10 +- .../cpu/riscv/macroAssembler_riscv.hpp | 4 +- src/hotspot/cpu/riscv/riscv.ad | 34 +- .../flags/jvmFlagConstraintsCompiler.cpp | 2 +- 12 files changed, 498 insertions(+), 96 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp index 68a72f87cfa..b0363a67bf1 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -84,6 +84,11 @@ void Assembler::zext_w(Register Rd, Register Rs) { } void Assembler::li(Register Rd, int64_t imm) { + CHECK_CEXT_AND_COMPRESSIBLE(is_imm_in_range(imm, 6, 0) && Rd != x0) { + c_li(Rd, imm); + return; + } + // 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 18cc6f7c879..56b91c6e50f 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -380,12 +380,17 @@ class Assembler : public AbstractAssembler { } void halt() { - emit_int32(0); + CHECK_CEXT() { + emit_int16(0); + } else { + emit_int32(0); + } } -// Rigster Instruction -#define INSN(NAME, op, funct3, funct7) \ +// Register Instruction +#define INSN(NAME, op, funct3, funct7, C) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, Rs2) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -396,34 +401,34 @@ 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(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(sllw, 0b0111011, 0b001, 0b0000000); - INSN(sraw, 0b0111011, 0b101, 0b0100000); - INSN(srlw, 0b0111011, 0b101, 0b0000000); - INSN(mul, 0b0110011, 0b000, 0b0000001); - INSN(mulh, 0b0110011, 0b001, 0b0000001); - INSN(mulhsu,0b0110011, 0b010, 0b0000001); - INSN(mulhu, 0b0110011, 0b011, 0b0000001); - INSN(mulw, 0b0111011, 0b000, 0b0000001); - INSN(div, 0b0110011, 0b100, 0b0000001); - INSN(divu, 0b0110011, 0b101, 0b0000001); - INSN(divw, 0b0111011, 0b100, 0b0000001); - INSN(divuw, 0b0111011, 0b101, 0b0000001); - INSN(rem, 0b0110011, 0b110, 0b0000001); - INSN(remu, 0b0110011, 0b111, 0b0000001); - INSN(remw, 0b0111011, 0b110, 0b0000001); - INSN(remuw, 0b0111011, 0b111, 0b0000001); + INSN(add, 0b0110011, 0b000, 0b0000000, COMPRESSIBLE); + INSN(sub, 0b0110011, 0b000, 0b0100000, COMPRESSIBLE); + INSN(andr, 0b0110011, 0b111, 0b0000000, COMPRESSIBLE); + INSN(orr, 0b0110011, 0b110, 0b0000000, COMPRESSIBLE); + INSN(xorr, 0b0110011, 0b100, 0b0000000, COMPRESSIBLE); + INSN(sll, 0b0110011, 0b001, 0b0000000, NOT_COMPRESSIBLE); + INSN(sra, 0b0110011, 0b101, 0b0100000, NOT_COMPRESSIBLE); + INSN(srl, 0b0110011, 0b101, 0b0000000, NOT_COMPRESSIBLE); + INSN(slt, 0b0110011, 0b010, 0b0000000, NOT_COMPRESSIBLE); + INSN(sltu, 0b0110011, 0b011, 0b0000000, NOT_COMPRESSIBLE); + INSN(addw, 0b0111011, 0b000, 0b0000000, COMPRESSIBLE); + INSN(subw, 0b0111011, 0b000, 0b0100000, COMPRESSIBLE); + INSN(sllw, 0b0111011, 0b001, 0b0000000, NOT_COMPRESSIBLE); + INSN(sraw, 0b0111011, 0b101, 0b0100000, NOT_COMPRESSIBLE); + INSN(srlw, 0b0111011, 0b101, 0b0000000, NOT_COMPRESSIBLE); + INSN(mul, 0b0110011, 0b000, 0b0000001, NOT_COMPRESSIBLE); + INSN(mulh, 0b0110011, 0b001, 0b0000001, NOT_COMPRESSIBLE); + INSN(mulhsu,0b0110011, 0b010, 0b0000001, NOT_COMPRESSIBLE); + INSN(mulhu, 0b0110011, 0b011, 0b0000001, NOT_COMPRESSIBLE); + INSN(mulw, 0b0111011, 0b000, 0b0000001, NOT_COMPRESSIBLE); + INSN(div, 0b0110011, 0b100, 0b0000001, NOT_COMPRESSIBLE); + INSN(divu, 0b0110011, 0b101, 0b0000001, NOT_COMPRESSIBLE); + INSN(divw, 0b0111011, 0b100, 0b0000001, NOT_COMPRESSIBLE); + INSN(divuw, 0b0111011, 0b101, 0b0000001, NOT_COMPRESSIBLE); + INSN(rem, 0b0110011, 0b110, 0b0000001, NOT_COMPRESSIBLE); + INSN(remu, 0b0110011, 0b111, 0b0000001, NOT_COMPRESSIBLE); + INSN(remw, 0b0111011, 0b110, 0b0000001, NOT_COMPRESSIBLE); + INSN(remuw, 0b0111011, 0b111, 0b0000001, NOT_COMPRESSIBLE); #undef INSN @@ -435,10 +440,11 @@ class Assembler : public AbstractAssembler { code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); // Load/store register (all modes) -#define INSN(NAME, op, funct3) \ +#define INSN(NAME, op, funct3, C) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ + unsigned insn = 0; \ int32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -492,20 +498,21 @@ 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, 0b0000011, 0b000, NOT_COMPRESSIBLE); + INSN(lbu, 0b0000011, 0b100, NOT_COMPRESSIBLE); + INSN(lh, 0b0000011, 0b001, NOT_COMPRESSIBLE); + INSN(lhu, 0b0000011, 0b101, NOT_COMPRESSIBLE); + INSN(lw, 0b0000011, 0b010, COMPRESSIBLE); + INSN(lwu, 0b0000011, 0b110, NOT_COMPRESSIBLE); + INSN(ld, 0b0000011, 0b011, COMPRESSIBLE); #undef INSN -#define INSN(NAME, op, funct3) \ +#define INSN(NAME, op, funct3, C) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ + unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -551,14 +558,15 @@ class Assembler : public AbstractAssembler { } \ } - INSN(flw, 0b0000111, 0b010); - INSN(fld, 0b0000111, 0b011); + INSN(flw, 0b0000111, 0b010, NOT_COMPRESSIBLE); + INSN(fld, 0b0000111, 0b011, COMPRESSIBLE); #undef INSN -#define INSN(NAME, op, funct3) \ +#define INSN(NAME, op, funct3, C) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - unsigned insn = 0; \ guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rs1, Rs2, offset) \ + unsigned insn = 0; \ uint32_t val = offset & 0x1fff; \ uint32_t val11 = (val >> 11) & 0x1; \ uint32_t val12 = (val >> 12) & 0x1; \ @@ -584,12 +592,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, 0b1100011, 0b000, COMPRESSIBLE); + INSN(bne, 0b1100011, 0b001, COMPRESSIBLE); + INSN(bge, 0b1100011, 0b101, NOT_COMPRESSIBLE); + INSN(bgeu, 0b1100011, 0b111, NOT_COMPRESSIBLE); + INSN(blt, 0b1100011, 0b100, NOT_COMPRESSIBLE); + INSN(bltu, 0b1100011, 0b110, NOT_COMPRESSIBLE); #undef INSN @@ -607,10 +615,11 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, REGISTER, op, funct3) \ +#define INSN(NAME, REGISTER, op, funct3, C) \ void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rs1, Rs2, offset) \ + unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ uint32_t low = val & 0x1f; \ uint32_t high = (val >> 5) & 0x7f; \ @@ -626,12 +635,12 @@ class Assembler : public AbstractAssembler { 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, 0b0100011, 0b000, NOT_COMPRESSIBLE); + INSN(sh, Register, 0b0100011, 0b001, NOT_COMPRESSIBLE); + INSN(sw, Register, 0b0100011, 0b010, COMPRESSIBLE); + INSN(sd, Register, 0b0100011, 0b011, COMPRESSIBLE); + INSN(fsw, FloatRegister, 0b0100111, 0b010, NOT_COMPRESSIBLE); + INSN(fsd, FloatRegister, 0b0100111, 0b011, COMPRESSIBLE); #undef INSN @@ -758,10 +767,11 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, op) \ +#define INSN(NAME, op, C) \ void NAME(Register Rd, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_imm_in_range(offset, 20, 1), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, offset) \ + 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)); \ @@ -787,16 +797,17 @@ class Assembler : public AbstractAssembler { wrap_label(Rd, L, temp, &Assembler::NAME); \ } - INSN(jal, 0b1101111); + INSN(jal, 0b1101111, COMPRESSIBLE); #undef INSN #undef INSN_ENTRY_RELOC -#define INSN(NAME, op, funct) \ +#define INSN(NAME, op, funct, C) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - unsigned insn = 0; \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ + unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch_reg((address)&insn, 7, Rd); \ patch((address)&insn, 14, 12, funct); \ @@ -806,7 +817,7 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(jalr, 0b1100111, 0b000); + INSN(jalr, 0b1100111, 0b000, COMPRESSIBLE); #undef INSN @@ -829,8 +840,9 @@ class Assembler : public AbstractAssembler { emit(insn); } -#define INSN(NAME, op, funct3, funct7) \ +#define INSN(NAME, op, funct3, funct7, C) \ void NAME() { \ + EMIT_MAY_COMPRESS(C, NAME) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 11, 7, 0b00000); \ @@ -840,9 +852,9 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(fence_i, 0b0001111, 0b001, 0b000000000000); - INSN(ecall, 0b1110011, 0b000, 0b000000000000); - INSN(ebreak, 0b1110011, 0b000, 0b000000000001); + INSN(fence_i, 0b0001111, 0b001, 0b000000000000, NOT_COMPRESSIBLE); + INSN(ecall, 0b1110011, 0b000, 0b000000000000, NOT_COMPRESSIBLE); + INSN(ebreak, 0b1110011, 0b000, 0b000000000001, COMPRESSIBLE); #undef INSN enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; @@ -938,9 +950,10 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Immediate Instruction -#define INSN(NAME, op, funct3) \ +#define INSN(NAME, op, funct3, C) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ guarantee(is_imm_in_range(imm, 12, 0), "Immediate is out of validity"); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, imm) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -950,12 +963,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, COMPRESSIBLE); + INSN(slti, 0b0010011, 0b010, NOT_COMPRESSIBLE); + INSN(addiw, 0b0011011, 0b000, COMPRESSIBLE); + INSN(and_imm12, 0b0010011, 0b111, COMPRESSIBLE); + INSN(ori, 0b0010011, 0b110, NOT_COMPRESSIBLE); + INSN(xori, 0b0010011, 0b100, NOT_COMPRESSIBLE); #undef INSN @@ -976,9 +989,10 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Shift Immediate Instruction -#define INSN(NAME, op, funct3, funct6) \ +#define INSN(NAME, op, funct3, funct6, C) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ guarantee(shamt <= 0x3f, "Shamt is invalid"); \ + EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, shamt) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -989,9 +1003,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, COMPRESSIBLE); + INSN(srai, 0b0010011, 0b101, 0b010000, COMPRESSIBLE); + INSN(srli, 0b0010011, 0b101, 0b000000, COMPRESSIBLE); #undef INSN @@ -1016,8 +1030,9 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Upper Immediate Instruction -#define INSN(NAME, op) \ +#define INSN(NAME, op, C) \ void NAME(Register Rd, int32_t imm) { \ + EMIT_MAY_COMPRESS(C, NAME, Rd, imm) \ int32_t upperImm = imm >> 12; \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ @@ -1027,8 +1042,8 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(lui, 0b0110111); - INSN(auipc, 0b0010111); + INSN(lui, 0b0110111, COMPRESSIBLE); + INSN(auipc, 0b0010111, NOT_COMPRESSIBLE); #undef INSN diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp index 2f66644cdd3..738a7c23a79 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -545,6 +545,329 @@ #undef INSN +// -------------- C-Ext Transformation Macros -------------- + +// two C-Ext macros +#define COMPRESSIBLE true +#define NOT_COMPRESSIBLE false + +// a pivotal dispatcher for C-Ext +#define EMIT_MAY_COMPRESS(C, NAME, ...) EMIT_MAY_COMPRESS_##C(NAME, __VA_ARGS__) +#define EMIT_MAY_COMPRESS_true(NAME, ...) EMIT_MAY_COMPRESS_##NAME(__VA_ARGS__) +#define EMIT_MAY_COMPRESS_false(NAME, ...) + +#define IS_COMPRESSIBLE(...) if (__VA_ARGS__) +#define CHECK_CEXT_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) +#define CHECK_CEXT() if (UseRVC && in_compressible_region()) + +// C-Ext transformation macros +#define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ + PREFIX \ + CHECK_CEXT_AND_COMPRESSIBLE(COND) { \ + EMIT; \ + return; \ + } \ + } + +#define EMIT_RVC_cond2(PREFIX, COND1, EMIT1, COND2, EMIT2) { \ + PREFIX \ + CHECK_CEXT() { \ + IS_COMPRESSIBLE(COND1) { \ + EMIT1; \ + return; \ + } else IS_COMPRESSIBLE(COND2) { \ + EMIT2; \ + return; \ + } \ + } \ + } + +#define EMIT_RVC_cond4(PREFIX, COND1, EMIT1, COND2, EMIT2, COND3, EMIT3, COND4, EMIT4) { \ + PREFIX \ + CHECK_CEXT() { \ + IS_COMPRESSIBLE(COND1) { \ + EMIT1; \ + return; \ + } else IS_COMPRESSIBLE(COND2) { \ + EMIT2; \ + return; \ + } else IS_COMPRESSIBLE(COND3) { \ + EMIT3; \ + return; \ + } else IS_COMPRESSIBLE(COND4) { \ + EMIT4; \ + return; \ + } \ + } \ + } + +// -------------------------- +// Register instructions +// -------------------------- +// add -> c.add +#define EMIT_MAY_COMPRESS_add(Rd, Rs1, Rs2) \ + EMIT_RVC_cond( \ + Register src = noreg;, \ + Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ + c_add(Rd, src) \ + ) + +// -------------------------- +// sub/subw -> c.sub/c.subw +#define EMIT_MAY_COMPRESS_sub_helper(C_NAME, Rd, Rs1, Rs2) \ + EMIT_RVC_cond(, \ + Rs1 == Rd && Rd->is_compressed_valid() && Rs2->is_compressed_valid(), \ + C_NAME(Rd, Rs2) \ + ) + +#define EMIT_MAY_COMPRESS_sub(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_sub_helper(c_sub, Rd, Rs1, Rs2) + +#define EMIT_MAY_COMPRESS_subw(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_sub_helper(c_subw, Rd, Rs1, Rs2) + +// -------------------------- +// xor/or/and/addw -> c.xor/c.or/c.and/c.addw +#define EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(C_NAME, Rd, Rs1, Rs2) \ + EMIT_RVC_cond( \ + Register src = noreg;, \ + Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ + C_NAME(Rd, src) \ + ) + +#define EMIT_MAY_COMPRESS_xorr(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_xor, Rd, Rs1, Rs2) + +#define EMIT_MAY_COMPRESS_orr(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_or, Rd, Rs1, Rs2) + +#define EMIT_MAY_COMPRESS_andr(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_and, Rd, Rs1, Rs2) + +#define EMIT_MAY_COMPRESS_addw(Rd, Rs1, Rs2) \ + EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_addw, Rd, Rs1, Rs2) + +// -------------------------- +// Load/store register (all modes) +// -------------------------- +private: + +#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: +// -------------------------- +// ld -> c.ldsp/c.ld +#define EMIT_MAY_COMPRESS_ld(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_ldsdsp(Rs, Rd, offset, true), \ + c_ldsp(Rd, offset), \ + is_c_ldsd(Rs, Rd, offset), \ + c_ld(Rd, Rs, offset) \ + ) + +// -------------------------- +// sd -> c.sdsp/c.sd +#define EMIT_MAY_COMPRESS_sd(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_ldsdsp(Rs, Rd, offset, false), \ + c_sdsp(Rd, offset), \ + is_c_ldsd(Rs, Rd, offset), \ + c_sd(Rd, Rs, offset) \ + ) + +// -------------------------- +// lw -> c.lwsp/c.lw +#define EMIT_MAY_COMPRESS_lw(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_lwswsp(Rs, Rd, offset, true), \ + c_lwsp(Rd, offset), \ + is_c_lwsw(Rs, Rd, offset), \ + c_lw(Rd, Rs, offset) \ + ) + +// -------------------------- +// sw -> c.swsp/c.sw +#define EMIT_MAY_COMPRESS_sw(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_lwswsp(Rs, Rd, offset, false), \ + c_swsp(Rd, offset), \ + is_c_lwsw(Rs, Rd, offset), \ + c_sw(Rd, Rs, offset) \ + ) + +// -------------------------- +// fld -> c.fldsp/c.fld +#define EMIT_MAY_COMPRESS_fld(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_fldsdsp(Rs, offset), \ + c_fldsp(Rd, offset), \ + is_c_fldsd(Rs, Rd, offset), \ + c_fld(Rd, Rs, offset) \ + ) + +// -------------------------- +// fsd -> c.fsdsp/c.fsd +#define EMIT_MAY_COMPRESS_fsd(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_fldsdsp(Rs, offset), \ + c_fsdsp(Rd, offset), \ + is_c_fldsd(Rs, Rd, offset), \ + c_fsd(Rd, Rs, offset) \ + ) + +// -------------------------- +// Conditional branch instructions +// -------------------------- +// beq/bne -> c.beqz/c.bnez + +// Note: offset == 0 means this beqz/benz is jumping forward and we cannot know the future position +// so we cannot compress this instrution. +#define EMIT_MAY_COMPRESS_beqz_bnez_helper(C_NAME, Rs1, Rs2, offset) \ + EMIT_RVC_cond(, \ + offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1), \ + C_NAME(Rs1, offset) \ + ) + +#define EMIT_MAY_COMPRESS_beq(Rs1, Rs2, offset) \ + EMIT_MAY_COMPRESS_beqz_bnez_helper(c_beqz, Rs1, Rs2, offset) + +#define EMIT_MAY_COMPRESS_bne(Rs1, Rs2, offset) \ + EMIT_MAY_COMPRESS_beqz_bnez_helper(c_bnez, Rs1, Rs2, offset) + +// -------------------------- +// Unconditional branch instructions +// -------------------------- +// jalr/jal -> c.jr/c.jalr/c.j + +#define EMIT_MAY_COMPRESS_jalr(Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + offset == 0 && Rd == x1 && Rs != x0, \ + c_jalr(Rs), \ + offset == 0 && Rd == x0 && Rs != x0, \ + c_jr(Rs) \ + ) + +// Note: offset == 0 means this j() is jumping forward and we cannot know the future position +// so we cannot compress this instrution. +#define EMIT_MAY_COMPRESS_jal(Rd, offset) \ + EMIT_RVC_cond(, \ + offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1), \ + c_j(offset) \ + ) + +// -------------------------- +// Upper Immediate Instruction +// -------------------------- +// lui -> c.lui +#define EMIT_MAY_COMPRESS_lui(Rd, imm) \ + EMIT_RVC_cond(, \ + Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0), \ + c_lui(Rd, imm) \ + ) + +// -------------------------- +// Miscellaneous Instructions +// -------------------------- +// ebreak -> c.ebreak +#define EMIT_MAY_COMPRESS_ebreak() \ + EMIT_RVC_cond(, \ + true, \ + c_ebreak() \ + ) + +// -------------------------- +// Immediate Instructions +// -------------------------- +// addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn. +#define EMIT_MAY_COMPRESS_addi(Rd, Rs1, imm) \ + EMIT_RVC_cond4(, \ + Rd == Rs1 && is_imm_in_range(imm, 6, 0), \ + c_addi(Rd, imm), \ + imm == 0 && Rd != x0 && Rs1 != x0, \ + c_mv(Rd, Rs1), \ + Rs1 == sp && Rd == Rs1 && imm != 0 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0), \ + c_addi16sp(imm), \ + Rs1 == sp && Rd->is_compressed_valid() && imm != 0 && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0), \ + c_addi4spn(Rd, imm) \ + ) + +// -------------------------- +// addiw -> c.addiw +#define EMIT_MAY_COMPRESS_addiw(Rd, Rs1, imm) \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0), \ + c_addiw(Rd, imm) \ + ) + +// -------------------------- +// and_imm12 -> c.andi +#define EMIT_MAY_COMPRESS_and_imm12(Rd, Rs1, imm) \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0), \ + c_andi(Rd, imm) \ + ) + +// -------------------------- +// Shift Immediate Instructions +// -------------------------- +// slli -> c.slli +#define EMIT_MAY_COMPRESS_slli(Rd, Rs1, shamt) \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd != x0 && shamt != 0, \ + c_slli(Rd, shamt) \ + ) + +// -------------------------- +// srai/srli -> c.srai/c.srli +#define EMIT_MAY_COMPRESS_srai_srli_helper(C_NAME, Rd, Rs1, shamt) \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0, \ + C_NAME(Rd, shamt) \ + ) + +#define EMIT_MAY_COMPRESS_srai(Rd, Rs1, shamt) \ + EMIT_MAY_COMPRESS_srai_srli_helper(c_srai, Rd, Rs1, shamt) + +#define EMIT_MAY_COMPRESS_srli(Rd, Rs1, shamt) \ + EMIT_MAY_COMPRESS_srai_srli_helper(c_srli, Rd, Rs1, shamt) + +// -------------------------- + public: // C-Ext: an abstact compressible region class AbstractCompressibleRegion : public StackObj { diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index b0406c9fb28..6fdfa734067 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1322,7 +1322,12 @@ 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) { + // C-Ext: With C-Ext a call may get 2-byte aligned. + // the address of jal itself (which will be patched later) should not span the cache line. + // See CallDynamicJavaDirectNode::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)); diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp index 0b01a47bd5c..4a86b964c2f 100644 --- a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp @@ -46,7 +46,7 @@ define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 0); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); -define_pd_global(intx, InteriorEntryAlignment, 16); +define_pd_global(intx, InteriorEntryAlignment, 4); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index f23ff34e3f4..703cd66b291 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -231,6 +231,8 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, __ sd(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); } +extern int nmethod_barrier_guard_offset(); + void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); @@ -238,6 +240,10 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { return; } + // C-Ext: RISCV's amoswap instructions need an alignment for the memory address it swaps + // when we reach here we may get a 2-byte alignment so need to align it + __ align(4, nmethod_barrier_guard_offset()); + Label skip, guard; Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset())); @@ -256,6 +262,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { __ bind(guard); + assert(__ offset() % 4 == 0, "RISCV CAS needs an alignment for memory"); __ emit_int32(0); // nmethod guard value. Skipped over in common case. __ bind(skip); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index ae7ee4c5a44..618c486b471 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -36,11 +36,18 @@ #include "utilities/debug.hpp" class NativeNMethodBarrier: public NativeInstruction { +public: + enum { + guard_offset = 12 * instruction_size, + barrier_size = guard_offset + 4, // guard_offset + an int32 nmethod guard value + }; + +private: address instruction_address() const { return addr_at(0); } int *guard_addr() { /* auipc + lwu + fence + lwu + beq + lui + addi + slli + addi + slli + jalr + j */ - return reinterpret_cast(instruction_address() + 12 * 4); + return reinterpret_cast(instruction_address() + guard_offset); } public: @@ -55,6 +62,10 @@ class NativeNMethodBarrier: public NativeInstruction { void verify() const; }; +int nmethod_barrier_guard_offset() { + return NativeNMethodBarrier::guard_offset; +} + // Store the instruction bitmask, bits and name for checking the barrier. struct CheckInsn { uint32_t mask; @@ -141,7 +152,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { // see BarrierSetAssembler::nmethod_entry_barrier // auipc + lwu + fence + lwu + beq + movptr_with_offset(5 instructions) + jalr + j + int32 -static const int entry_barrier_offset = -4 * 13; +static const int entry_barrier_offset = - NativeNMethodBarrier::barrier_size; static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset; diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index f1e57f9e461..778999b2222 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -37,7 +37,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. -define_pd_global(intx, CodeEntryAlignment, 64); +define_pd_global(intx, CodeEntryAlignment, 16); define_pd_global(intx, OptoLoopAlignment, 16); #define DEFAULT_STACK_YELLOW_PAGES (2) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index fb12b6e9064..74735d1bd61 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 @@ -2920,7 +2922,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(); } + // C-Ext: 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)); @@ -2935,6 +2938,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/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 050881755ce..295f0843111 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1190,6 +1190,34 @@ int MachCallNativeNode::ret_addr_offset() { return -1; } +// C-Ext: With C-Ext a call may get 2-byte aligned. +// The offset encoding in jal ranges bits [12, 31], which could span the cache line. +// Patching this unaligned address will make the write operation not atomic. +// Other threads may be running the same piece of code at full speed, causing concurrency issues. +// So we must ensure that it does not span a cache line so that it can be patched. +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; +} + +// C-Ext: With C-Ext a call may get 2-byte aligned. +// The offset encoding in jal ranges bits [12, 31], which could span the cache line. +// Patching this unaligned address will make the write operation not atomic. +// Other threads may be running the same piece of code at full speed, causing concurrency issues. +// So we must ensure that it does not span a cache line so that it can be patched. +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 C-Ext, + // 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 @@ -1218,13 +1246,14 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); 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); } //============================================================================= @@ -6379,6 +6408,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), @@ -9830,6 +9860,7 @@ instruct CallStaticJavaDirect(method meth) riscv64_enc_call_epilog ); ins_pipe(pipe_class_call); + ins_alignment(4); %} // TO HERE @@ -9849,6 +9880,7 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) riscv64_enc_call_epilog ); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 5b24e062b18..d3fa1578f95 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -329,7 +329,7 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { } int minimum_alignment = 16; -#if defined(X86) && !defined(AMD64) +#if (defined(X86) && !defined(AMD64)) || defined(RISCV) minimum_alignment = 4; #elif defined(S390) minimum_alignment = 2; From 4254d3e12095a6831a32b8edc1819f80ad5407aa Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 23 Dec 2021 16:26:14 +0800 Subject: [PATCH 03/21] Revise as proposed comments, including - Fix macros in assembler_riscv_c.hpp - Remove UncompressibleRegion - Modify comments - Change names: C-Ext to RVC --- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 75 +++++++------------ .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- .../gc/shared/barrierSetAssembler_riscv.cpp | 2 +- .../cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/register_riscv.hpp | 4 +- src/hotspot/cpu/riscv/riscv.ad | 8 +- 6 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp index 738a7c23a79..357a722f27d 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -23,8 +23,8 @@ * */ -#ifndef CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP -#define CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP +#ifndef CPU_RISCV_ASSEMBLER_RISCV_C_HPP +#define CPU_RISCV_ASSEMBLER_RISCV_C_HPP private: bool _in_compressible_region; @@ -33,7 +33,7 @@ void set_in_compressible_region(bool b) { _in_compressible_region = b; } public: - // C-Ext: If an instruction is compressible, then + // RVC: If an instruction is compressible, then // we will implicitly emit a 16-bit compressed instruction instead of the 32-bit // instruction in Assembler. All below logic follows Chapter - // "C" Standard Extension for Compressed Instructions, Version 2.0. @@ -43,27 +43,20 @@ // Note: // 1. When UseRVC is enabled, 32-bit instructions under 'CompressibleRegion's will be // transformed to 16-bit instructions if compressible. - // 2. C-Ext's instructions in Assembler always begin with 'c_' prefix, as 'c_li', + // 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. In some cases, we need to force using one instruction's uncompressed version, - // for instance code being patched should remain its general and longest version - // to cover all possible cases, or code requiring a fixed length. - // So we introduce 'UncompressibleRegion' to force instructions in its range - // to remain its normal 4-byte version. + // 3. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range + // are qualified to change to their 2-byte versions. // An example: // // CompressibleRegion cr(_masm); - // __ andr(...); // this instruction could change to c.and if qualified - // { - // UncompressibleRegion ur(_masm); - // __ andr(...); // this instruction would remain the normal 32-bit form of andr - // } + // __ andr(...); // this instruction could change to c.and if able to // - // 4. Using -XX:PrintAssemblyOptions=no-aliases could print C-Ext instructions instead of + // 4. Using -XX:PrintAssemblyOptions=no-aliases could print RVC instructions instead of // normal ones. // - // C-Ext: extract a 16-bit instruction. + // RVC: extract a 16-bit instruction. static inline uint16_t c_extract(uint16_t val, unsigned msb, unsigned lsb) { assert_cond(msb >= lsb && msb <= 15); unsigned nbits = msb - lsb + 1; @@ -80,7 +73,7 @@ return result; } - // C-Ext: patch a 16-bit instruction. + // RVC: 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); @@ -99,31 +92,31 @@ c_patch(a, bit, bit, val); } - // C-Ext: patch a 16-bit instruction with a general purpose register ranging [0, 31] (5 bits) + // RVC: 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()); } - // C-Ext: patch a 16-bit instruction with a general purpose register ranging [8, 15] (3 bits) + // RVC: 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()); } - // C-Ext: patch a 16-bit instruction with a float register ranging [0, 31] (5 bits) + // RVC: 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()); } - // C-Ext: patch a 16-bit instruction with a float register ranging [8, 15] (3 bits) + // RVC: 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()); } public: -// C-Ext: Compressed Instructions +// RVC: Compressed Instructions -// -------------- C-Ext Instruction Definitions -------------- +// -------------- RVC Instruction Definitions -------------- void c_nop() { c_addi(x0, 0); @@ -545,13 +538,13 @@ #undef INSN -// -------------- C-Ext Transformation Macros -------------- +// -------------- RVC Transformation Macros -------------- -// two C-Ext macros +// two RVC macros #define COMPRESSIBLE true #define NOT_COMPRESSIBLE false -// a pivotal dispatcher for C-Ext +// a pivotal dispatcher for RVC #define EMIT_MAY_COMPRESS(C, NAME, ...) EMIT_MAY_COMPRESS_##C(NAME, __VA_ARGS__) #define EMIT_MAY_COMPRESS_true(NAME, ...) EMIT_MAY_COMPRESS_##NAME(__VA_ARGS__) #define EMIT_MAY_COMPRESS_false(NAME, ...) @@ -560,7 +553,7 @@ #define CHECK_CEXT_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) #define CHECK_CEXT() if (UseRVC && in_compressible_region()) -// C-Ext transformation macros +// RVC transformation macros #define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ PREFIX \ CHECK_CEXT_AND_COMPRESSIBLE(COND) { \ @@ -869,20 +862,15 @@ // -------------------------- public: -// C-Ext: an abstact compressible region -class AbstractCompressibleRegion : public StackObj { +// RVC: a compressible region +class CompressibleRegion : public StackObj { protected: Assembler *_masm; bool _prev_in_compressible_region; -protected: - AbstractCompressibleRegion(Assembler *_masm) - : _masm(_masm) - , _prev_in_compressible_region(_masm->in_compressible_region()) {} -}; - -class CompressibleRegion : public AbstractCompressibleRegion { public: - CompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { + CompressibleRegion(Assembler *_masm) + : _masm(_masm) + , _prev_in_compressible_region(_masm->in_compressible_region()) { _masm->set_in_compressible_region(true); } ~CompressibleRegion() { @@ -890,15 +878,4 @@ class CompressibleRegion : public AbstractCompressibleRegion { } }; -// C-Ext: an uncompressible region -class UncompressibleRegion : public AbstractCompressibleRegion { -public: - UncompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { - _masm->set_in_compressible_region(false); - } - ~UncompressibleRegion() { - _masm->set_in_compressible_region(_prev_in_compressible_region); - } -}; - -#endif // CPU_RISCV_ASSEMBLER_RISCV_CEXT_HPP \ No newline at end of file +#endif // CPU_RISCV_ASSEMBLER_RISCV_C_HPP \ No newline at end of file diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 6fdfa734067..7976e474c95 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1323,7 +1323,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } void LIR_Assembler::align_call(LIR_Code code) { - // C-Ext: With C-Ext a call may get 2-byte aligned. + // RVC: With RVC a call may get 2-byte aligned. // the address of jal itself (which will be patched later) should not span the cache line. // See CallDynamicJavaDirectNode::compute_padding() for more info. __ align(4); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 703cd66b291..8c742993aa2 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -240,7 +240,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { return; } - // C-Ext: RISCV's amoswap instructions need an alignment for the memory address it swaps + // RVC: RISCV's amoswap instructions need an alignment for the memory address it swaps // when we reach here we may get a 2-byte alignment so need to align it __ align(4, nmethod_barrier_guard_offset()); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 74735d1bd61..6539e712bde 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2922,7 +2922,7 @@ 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 - // C-Ext: when we reach here we may get a 2-byte alignment so need to align it + // RVC: 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() + diff --git a/src/hotspot/cpu/riscv/register_riscv.hpp b/src/hotspot/cpu/riscv/register_riscv.hpp index 99c65b13b8a..6f75814d1be 100644 --- a/src/hotspot/cpu/riscv/register_riscv.hpp +++ b/src/hotspot/cpu/riscv/register_riscv.hpp @@ -60,7 +60,7 @@ class RegisterImpl: public AbstractRegisterImpl { number_of_byte_registers = 32, max_slots_per_register = 2, - // C-Ext: integer registers in the range of [x8~x15] are correspond for RVC. Please see Table 16.2 in spec. + // RVC: 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, }; @@ -140,7 +140,7 @@ class FloatRegisterImpl: public AbstractRegisterImpl { number_of_registers = 32, max_slots_per_register = 2, - // C-Ext: float registers in the range of [f8~f15] are correspond for RVC. Please see Table 16.2 in spec. + // RVC: 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, }; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 295f0843111..463af435d6b 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1190,7 +1190,7 @@ int MachCallNativeNode::ret_addr_offset() { return -1; } -// C-Ext: With C-Ext a call may get 2-byte aligned. +// RVC: With RVC a call may get 2-byte aligned. // The offset encoding in jal ranges bits [12, 31], which could span the cache line. // Patching this unaligned address will make the write operation not atomic. // Other threads may be running the same piece of code at full speed, causing concurrency issues. @@ -1201,7 +1201,7 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const return align_up(current_offset, alignment_required()) - current_offset; } -// C-Ext: With C-Ext a call may get 2-byte aligned. +// RVC: With RVC a call may get 2-byte aligned. // The offset encoding in jal ranges bits [12, 31], which could span the cache line. // Patching this unaligned address will make the write operation not atomic. // Other threads may be running the same piece of code at full speed, causing concurrency issues. @@ -1210,7 +1210,7 @@ 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 C-Ext, + // 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; @@ -1246,7 +1246,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { C2_MacroAssembler _masm(&cbuf); - Assembler::CompressibleRegion cr(&_masm); + Assembler::CompressibleRegion cr(&_masm); // RVC: nops shall be 2-byte under RVC for alignment purposes. for (int i = 0; i < _count; i++) { __ nop(); } From ce8866db4d1b52ee82082a54a913253020aeb779 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Fri, 24 Dec 2021 12:24:49 +0800 Subject: [PATCH 04/21] Cover most RVC instructions by using CompressibleRegion to cover minimal functions in C2 --- .../cpu/riscv/macroAssembler_riscv.cpp | 12 ++++ src/hotspot/cpu/riscv/riscv.ad | 56 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 6539e712bde..70ef0e62e88 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -962,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); @@ -983,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); @@ -1005,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); @@ -1024,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); @@ -1044,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 @@ -1065,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 @@ -1087,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); @@ -1101,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())) { @@ -1114,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); @@ -1144,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); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 463af435d6b..31a8e15906d 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1229,6 +1229,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(); } @@ -1515,6 +1516,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 @@ -1535,6 +1537,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 @@ -2072,6 +2075,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); @@ -2098,6 +2102,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); %} @@ -2510,12 +2515,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 @@ -2531,6 +2538,7 @@ encode %{ enc_class riscv64_enc_ret() %{ C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); __ ret(); %} @@ -4515,6 +4523,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)); %} @@ -4530,6 +4539,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)); %} @@ -4560,6 +4570,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)); %} @@ -4591,6 +4602,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)); %} @@ -4621,6 +4633,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)); %} @@ -4666,6 +4679,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)); %} @@ -4950,6 +4964,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)); %} @@ -4979,6 +4994,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)); %} @@ -5009,6 +5025,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)); %} @@ -5039,6 +5056,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)); %} @@ -5083,6 +5101,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)); %} @@ -5098,6 +5117,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)); %} @@ -6393,6 +6413,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)); @@ -6425,6 +6446,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); @@ -6441,6 +6463,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)); @@ -6456,6 +6479,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); %} @@ -6471,6 +6495,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), @@ -6487,6 +6512,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)); @@ -6502,6 +6528,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), @@ -6519,6 +6546,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)); @@ -6535,6 +6563,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), @@ -6551,6 +6580,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)); @@ -6566,6 +6596,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), @@ -6695,6 +6726,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); @@ -6850,6 +6882,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), @@ -6885,6 +6918,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), @@ -6903,6 +6937,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), @@ -6938,6 +6973,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), @@ -7401,6 +7437,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)); @@ -7417,6 +7454,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)); @@ -7433,6 +7471,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)); @@ -7465,6 +7504,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)); @@ -7497,6 +7537,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)); @@ -7513,6 +7554,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)); @@ -7529,6 +7571,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)); @@ -7561,6 +7604,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)); @@ -7762,6 +7806,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)); } @@ -7777,6 +7822,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)); } @@ -7931,6 +7977,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); %} @@ -8085,6 +8132,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); %} @@ -8102,6 +8150,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); %} @@ -8198,6 +8247,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)); %} @@ -8234,6 +8284,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)); %} @@ -8252,6 +8303,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)); %} @@ -8288,6 +8340,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)); %} @@ -8306,6 +8359,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)); %} @@ -8324,6 +8378,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)); %} @@ -10461,6 +10516,7 @@ instruct ShouldNotReachHere() %{ format %{ "#@ShouldNotReachHere" %} ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); if (is_reachable()) { __ halt(); } From 4ddf759d4f0c2886eaa25b0b0db7942492a85193 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Tue, 4 Jan 2022 11:45:01 +0800 Subject: [PATCH 05/21] Update licenses to the new year --- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp index 357a722f27d..a923e745431 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * Copyright (c) 2022, 2022, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From f152578bbea792cab8726bae3e216ea069523209 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Wed, 5 Jan 2022 12:05:29 +0800 Subject: [PATCH 06/21] Remove Alignment-related changes as discussions --- src/hotspot/cpu/riscv/c2_globals_riscv.hpp | 2 +- src/hotspot/cpu/riscv/globals_riscv.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp index 4a86b964c2f..0b01a47bd5c 100644 --- a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp @@ -46,7 +46,7 @@ define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 0); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); -define_pd_global(intx, InteriorEntryAlignment, 4); +define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 778999b2222..f1e57f9e461 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -37,7 +37,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. -define_pd_global(intx, CodeEntryAlignment, 16); +define_pd_global(intx, CodeEntryAlignment, 64); define_pd_global(intx, OptoLoopAlignment, 16); #define DEFAULT_STACK_YELLOW_PAGES (2) From a74cbebad248ce84446de9f6e107ab0db10a14c2 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Wed, 5 Jan 2022 13:55:34 +0800 Subject: [PATCH 07/21] Fix remaining CEXT -> RVC --- src/hotspot/cpu/riscv/assembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/assembler_riscv.hpp | 2 +- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp index b0363a67bf1..321993307f6 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -84,7 +84,7 @@ void Assembler::zext_w(Register Rd, Register Rs) { } void Assembler::li(Register Rd, int64_t imm) { - CHECK_CEXT_AND_COMPRESSIBLE(is_imm_in_range(imm, 6, 0) && Rd != x0) { + CHECK_RVC_AND_COMPRESSIBLE(is_imm_in_range(imm, 6, 0) && Rd != x0) { c_li(Rd, imm); return; } diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 56b91c6e50f..9d7d7c8bbb7 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -380,7 +380,7 @@ class Assembler : public AbstractAssembler { } void halt() { - CHECK_CEXT() { + CHECK_RVC() { emit_int16(0); } else { emit_int32(0); diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp index a923e745431..bae4f58966e 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -550,13 +550,13 @@ #define EMIT_MAY_COMPRESS_false(NAME, ...) #define IS_COMPRESSIBLE(...) if (__VA_ARGS__) -#define CHECK_CEXT_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) -#define CHECK_CEXT() if (UseRVC && in_compressible_region()) +#define CHECK_RVC_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) +#define CHECK_RVC() if (UseRVC && in_compressible_region()) // RVC transformation macros #define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ PREFIX \ - CHECK_CEXT_AND_COMPRESSIBLE(COND) { \ + CHECK_RVC_AND_COMPRESSIBLE(COND) { \ EMIT; \ return; \ } \ @@ -564,7 +564,7 @@ #define EMIT_RVC_cond2(PREFIX, COND1, EMIT1, COND2, EMIT2) { \ PREFIX \ - CHECK_CEXT() { \ + CHECK_RVC() { \ IS_COMPRESSIBLE(COND1) { \ EMIT1; \ return; \ @@ -577,7 +577,7 @@ #define EMIT_RVC_cond4(PREFIX, COND1, EMIT1, COND2, EMIT2, COND3, EMIT3, COND4, EMIT4) { \ PREFIX \ - CHECK_CEXT() { \ + CHECK_RVC() { \ IS_COMPRESSIBLE(COND1) { \ EMIT1; \ return; \ From b2e3ac5e262fa73ff1d29666ce0e3d45cc1e5c1c Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Wed, 5 Jan 2022 16:25:17 +0800 Subject: [PATCH 08/21] Remove COMPRESSIBLE & NOT_COMPRESSIBLE macros by adding one layer as discussions --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 343 ++++++++++++++------ src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 9 +- 2 files changed, 253 insertions(+), 99 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 9d7d7c8bbb7..cffccba6b10 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -388,9 +388,8 @@ class Assembler : public AbstractAssembler { } // Register Instruction -#define INSN(NAME, op, funct3, funct7, C) \ +#define INSN(NAME, op, funct3, funct7) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, Rs2) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -401,34 +400,34 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(add, 0b0110011, 0b000, 0b0000000, COMPRESSIBLE); - INSN(sub, 0b0110011, 0b000, 0b0100000, COMPRESSIBLE); - INSN(andr, 0b0110011, 0b111, 0b0000000, COMPRESSIBLE); - INSN(orr, 0b0110011, 0b110, 0b0000000, COMPRESSIBLE); - INSN(xorr, 0b0110011, 0b100, 0b0000000, COMPRESSIBLE); - INSN(sll, 0b0110011, 0b001, 0b0000000, NOT_COMPRESSIBLE); - INSN(sra, 0b0110011, 0b101, 0b0100000, NOT_COMPRESSIBLE); - INSN(srl, 0b0110011, 0b101, 0b0000000, NOT_COMPRESSIBLE); - INSN(slt, 0b0110011, 0b010, 0b0000000, NOT_COMPRESSIBLE); - INSN(sltu, 0b0110011, 0b011, 0b0000000, NOT_COMPRESSIBLE); - INSN(addw, 0b0111011, 0b000, 0b0000000, COMPRESSIBLE); - INSN(subw, 0b0111011, 0b000, 0b0100000, COMPRESSIBLE); - INSN(sllw, 0b0111011, 0b001, 0b0000000, NOT_COMPRESSIBLE); - INSN(sraw, 0b0111011, 0b101, 0b0100000, NOT_COMPRESSIBLE); - INSN(srlw, 0b0111011, 0b101, 0b0000000, NOT_COMPRESSIBLE); - INSN(mul, 0b0110011, 0b000, 0b0000001, NOT_COMPRESSIBLE); - INSN(mulh, 0b0110011, 0b001, 0b0000001, NOT_COMPRESSIBLE); - INSN(mulhsu,0b0110011, 0b010, 0b0000001, NOT_COMPRESSIBLE); - INSN(mulhu, 0b0110011, 0b011, 0b0000001, NOT_COMPRESSIBLE); - INSN(mulw, 0b0111011, 0b000, 0b0000001, NOT_COMPRESSIBLE); - INSN(div, 0b0110011, 0b100, 0b0000001, NOT_COMPRESSIBLE); - INSN(divu, 0b0110011, 0b101, 0b0000001, NOT_COMPRESSIBLE); - INSN(divw, 0b0111011, 0b100, 0b0000001, NOT_COMPRESSIBLE); - INSN(divuw, 0b0111011, 0b101, 0b0000001, NOT_COMPRESSIBLE); - INSN(rem, 0b0110011, 0b110, 0b0000001, NOT_COMPRESSIBLE); - INSN(remu, 0b0110011, 0b111, 0b0000001, NOT_COMPRESSIBLE); - INSN(remw, 0b0111011, 0b110, 0b0000001, NOT_COMPRESSIBLE); - INSN(remuw, 0b0111011, 0b111, 0b0000001, NOT_COMPRESSIBLE); + 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(sllw, 0b0111011, 0b001, 0b0000000); + INSN(sraw, 0b0111011, 0b101, 0b0100000); + INSN(srlw, 0b0111011, 0b101, 0b0000000); + INSN(mul, 0b0110011, 0b000, 0b0000001); + INSN(mulh, 0b0110011, 0b001, 0b0000001); + INSN(mulhsu,0b0110011, 0b010, 0b0000001); + INSN(mulhu, 0b0110011, 0b011, 0b0000001); + INSN(mulw, 0b0111011, 0b000, 0b0000001); + INSN(div, 0b0110011, 0b100, 0b0000001); + INSN(divu, 0b0110011, 0b101, 0b0000001); + INSN(divw, 0b0111011, 0b100, 0b0000001); + INSN(divuw, 0b0111011, 0b101, 0b0000001); + INSN(rem, 0b0110011, 0b110, 0b0000001); + INSN(remu, 0b0110011, 0b111, 0b0000001); + INSN(remw, 0b0111011, 0b110, 0b0000001); + INSN(remuw, 0b0111011, 0b111, 0b0000001); #undef INSN @@ -440,10 +439,9 @@ class Assembler : public AbstractAssembler { code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); // Load/store register (all modes) -#define INSN(NAME, op, funct3, C) \ +#define INSN(NAME, op, funct3) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ unsigned insn = 0; \ int32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ @@ -452,7 +450,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()); \ @@ -498,20 +508,19 @@ class Assembler : public AbstractAssembler { wrap_label(Rd, L, &Assembler::NAME); \ } - INSN(lb, 0b0000011, 0b000, NOT_COMPRESSIBLE); - INSN(lbu, 0b0000011, 0b100, NOT_COMPRESSIBLE); - INSN(lh, 0b0000011, 0b001, NOT_COMPRESSIBLE); - INSN(lhu, 0b0000011, 0b101, NOT_COMPRESSIBLE); - INSN(lw, 0b0000011, 0b010, COMPRESSIBLE); - INSN(lwu, 0b0000011, 0b110, NOT_COMPRESSIBLE); - INSN(ld, 0b0000011, 0b011, COMPRESSIBLE); + INSN(lb); + INSN(lbu); + INSN(lh); + INSN(lhu); + INSN(lw); + INSN(lwu); + INSN(ld); #undef INSN -#define INSN(NAME, op, funct3, C) \ +#define INSN(NAME, op, funct3) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ patch((address)&insn, 6, 0, op); \ @@ -520,7 +529,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()); \ @@ -558,14 +574,13 @@ class Assembler : public AbstractAssembler { } \ } - INSN(flw, 0b0000111, 0b010, NOT_COMPRESSIBLE); - INSN(fld, 0b0000111, 0b011, COMPRESSIBLE); + INSN(flw); + INSN(fld); #undef INSN -#define INSN(NAME, op, funct3, C) \ +#define INSN(NAME, op, funct3) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rs1, Rs2, offset) \ unsigned insn = 0; \ uint32_t val = offset & 0x1fff; \ uint32_t val11 = (val >> 11) & 0x1; \ @@ -581,7 +596,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()); \ @@ -592,12 +618,12 @@ class Assembler : public AbstractAssembler { NAME(Rs1, Rs2, dest); \ } - INSN(beq, 0b1100011, 0b000, COMPRESSIBLE); - INSN(bne, 0b1100011, 0b001, COMPRESSIBLE); - INSN(bge, 0b1100011, 0b101, NOT_COMPRESSIBLE); - INSN(bgeu, 0b1100011, 0b111, NOT_COMPRESSIBLE); - INSN(blt, 0b1100011, 0b100, NOT_COMPRESSIBLE); - INSN(bltu, 0b1100011, 0b110, NOT_COMPRESSIBLE); + INSN(beq); + INSN(bne); + INSN(bge); + INSN(bgeu); + INSN(blt); + INSN(bltu); #undef INSN @@ -615,10 +641,9 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, REGISTER, op, funct3, C) \ +#define INSN(NAME, REGISTER, op, funct3) \ void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rs1, Rs2, offset) \ unsigned insn = 0; \ uint32_t val = offset & 0xfff; \ uint32_t low = val & 0x1f; \ @@ -631,16 +656,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, NOT_COMPRESSIBLE); - INSN(sh, Register, 0b0100011, 0b001, NOT_COMPRESSIBLE); - INSN(sw, Register, 0b0100011, 0b010, COMPRESSIBLE); - INSN(sd, Register, 0b0100011, 0b011, COMPRESSIBLE); - INSN(fsw, FloatRegister, 0b0100111, 0b010, NOT_COMPRESSIBLE); - INSN(fsd, FloatRegister, 0b0100111, 0b011, COMPRESSIBLE); + INSN(sb, Register); + INSN(sh, Register); + INSN(sw, Register); + INSN(sd, Register); + INSN(fsw, FloatRegister); + INSN(fsd, FloatRegister); #undef INSN @@ -767,10 +803,9 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, op, C) \ +#define INSN(NAME, op) \ void NAME(Register Rd, const int32_t offset) { \ guarantee(is_imm_in_range(offset, 20, 1), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, offset) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch_reg((address)&insn, 7, Rd); \ @@ -779,7 +814,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(); \ @@ -797,16 +838,15 @@ class Assembler : public AbstractAssembler { wrap_label(Rd, L, temp, &Assembler::NAME); \ } - INSN(jal, 0b1101111, COMPRESSIBLE); + INSN(jal); #undef INSN #undef INSN_ENTRY_RELOC -#define INSN(NAME, op, funct, C) \ +#define INSN(NAME, op, funct) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs, offset) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch_reg((address)&insn, 7, Rd); \ @@ -817,7 +857,7 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(jalr, 0b1100111, 0b000, COMPRESSIBLE); + INSN(_jalr, 0b1100111, 0b000); #undef INSN @@ -840,9 +880,8 @@ class Assembler : public AbstractAssembler { emit(insn); } -#define INSN(NAME, op, funct3, funct7, C) \ +#define INSN(NAME, op, funct3, funct7) \ void NAME() { \ - EMIT_MAY_COMPRESS(C, NAME) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 11, 7, 0b00000); \ @@ -852,9 +891,10 @@ class Assembler : public AbstractAssembler { emit(insn); \ } - INSN(fence_i, 0b0001111, 0b001, 0b000000000000, NOT_COMPRESSIBLE); - INSN(ecall, 0b1110011, 0b000, 0b000000000000, NOT_COMPRESSIBLE); - INSN(ebreak, 0b1110011, 0b000, 0b000000000001, COMPRESSIBLE); + INSN(fence_i, 0b0001111, 0b001, 0b000000000000); + INSN(ecall, 0b1110011, 0b000, 0b000000000000); + INSN(_ebreak, 0b1110011, 0b000, 0b000000000001); + #undef INSN enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; @@ -950,10 +990,9 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Immediate Instruction -#define INSN(NAME, op, funct3, C) \ +#define INSN(NAME, op, funct3) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ guarantee(is_imm_in_range(imm, 12, 0), "Immediate is out of validity"); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, imm) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -963,12 +1002,12 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(addi, 0b0010011, 0b000, COMPRESSIBLE); - INSN(slti, 0b0010011, 0b010, NOT_COMPRESSIBLE); - INSN(addiw, 0b0011011, 0b000, COMPRESSIBLE); - INSN(and_imm12, 0b0010011, 0b111, COMPRESSIBLE); - INSN(ori, 0b0010011, 0b110, NOT_COMPRESSIBLE); - INSN(xori, 0b0010011, 0b100, NOT_COMPRESSIBLE); + 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 @@ -989,10 +1028,9 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Shift Immediate Instruction -#define INSN(NAME, op, funct3, funct6, C) \ +#define INSN(NAME, op, funct3, funct6) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ guarantee(shamt <= 0x3f, "Shamt is invalid"); \ - EMIT_MAY_COMPRESS(C, NAME, Rd, Rs1, shamt) \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ patch((address)&insn, 14, 12, funct3); \ @@ -1003,9 +1041,9 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(slli, 0b0010011, 0b001, 0b000000, COMPRESSIBLE); - INSN(srai, 0b0010011, 0b101, 0b010000, COMPRESSIBLE); - INSN(srli, 0b0010011, 0b101, 0b000000, COMPRESSIBLE); + INSN(_slli, 0b0010011, 0b001, 0b000000); + INSN(_srai, 0b0010011, 0b101, 0b010000); + INSN(_srli, 0b0010011, 0b101, 0b000000); #undef INSN @@ -1030,9 +1068,8 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN // Upper Immediate Instruction -#define INSN(NAME, op, C) \ +#define INSN(NAME, op) \ void NAME(Register Rd, int32_t imm) { \ - EMIT_MAY_COMPRESS(C, NAME, Rd, imm) \ int32_t upperImm = imm >> 12; \ unsigned insn = 0; \ patch((address)&insn, 6, 0, op); \ @@ -1042,8 +1079,8 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } - INSN(lui, 0b0110111, COMPRESSIBLE); - INSN(auipc, 0b0010111, NOT_COMPRESSIBLE); + INSN(_lui, 0b0110111); + INSN(auipc, 0b0010111); #undef INSN @@ -2034,6 +2071,130 @@ enum Nf { return uabs(target - branch) < branch_range; } +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs1, Rs2) \ + _##NAME(Rd, Rs1, Rs2); \ + } + + INSN(add); + INSN(sub); + INSN(andr); + INSN(orr); + INSN(xorr); + INSN(addw); + INSN(subw); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ + _##NAME(Rd, Rs, offset); \ + } + + INSN(lw); + INSN(ld); + +#undef INSN + +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ + _##NAME(Rd, Rs, offset); \ + } + + INSN(fld); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rs1, Rs2, offset) \ + _##NAME(Rs1, Rs2, offset); \ + } + + INSN(beq); + INSN(bne); + +#undef INSN + +#define INSN(NAME, REGISTER) \ + void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rs1, Rs2, offset) \ + _##NAME(Rs1, Rs2, offset); \ + } \ + + INSN(sw, Register); + INSN(sd, Register); + INSN(fsd, FloatRegister); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, const int32_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rd, offset) \ + _##NAME(Rd, offset); \ + } + + INSN(jal); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ + _##NAME(Rd, Rs, offset); \ + } + + INSN(jalr); + +#undef INSN + +#define INSN(NAME) \ + void NAME() { \ + EMIT_MAY_COMPRESS(NAME) \ + _##NAME(); \ + } + + INSN(ebreak); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs1, imm) \ + _##NAME(Rd, Rs1, imm); \ + } + + INSN(addi); + INSN(addiw); + INSN(and_imm12); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + EMIT_MAY_COMPRESS(NAME, Rd, Rs1, shamt) \ + _##NAME(Rd, Rs1, shamt); \ + } + + INSN(slli); + INSN(srai); + INSN(srli); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, int32_t imm) { \ + EMIT_MAY_COMPRESS(NAME, Rd, imm) \ + _##NAME(Rd, imm); \ + } + + INSN(lui); + +#undef INSN + virtual ~Assembler() {} }; diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp index bae4f58966e..ede804406d1 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp @@ -540,14 +540,7 @@ // -------------- RVC Transformation Macros -------------- -// two RVC macros -#define COMPRESSIBLE true -#define NOT_COMPRESSIBLE false - -// a pivotal dispatcher for RVC -#define EMIT_MAY_COMPRESS(C, NAME, ...) EMIT_MAY_COMPRESS_##C(NAME, __VA_ARGS__) -#define EMIT_MAY_COMPRESS_true(NAME, ...) EMIT_MAY_COMPRESS_##NAME(__VA_ARGS__) -#define EMIT_MAY_COMPRESS_false(NAME, ...) +#define EMIT_MAY_COMPRESS(NAME, ...) EMIT_MAY_COMPRESS_##NAME(__VA_ARGS__) #define IS_COMPRESSIBLE(...) if (__VA_ARGS__) #define CHECK_RVC_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) From 3a8adfa93987b2b477468112564686916358e4a2 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Wed, 5 Jan 2022 18:08:31 +0800 Subject: [PATCH 09/21] Remove assembler_riscv_c.hpp as discussions --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 894 ++++++++++++++++++-- src/hotspot/cpu/riscv/assembler_riscv_c.hpp | 874 ------------------- 2 files changed, 834 insertions(+), 934 deletions(-) delete mode 100644 src/hotspot/cpu/riscv/assembler_riscv_c.hpp diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index cffccba6b10..bde3feb4ab9 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -255,7 +255,6 @@ class InternalAddress: public Address { class Assembler : public AbstractAssembler { public: - #include "assembler_riscv_c.hpp" enum { instruction_size = 4 }; @@ -379,12 +378,8 @@ class Assembler : public AbstractAssembler { emit_int32((jint)insn); } - void halt() { - CHECK_RVC() { - emit_int16(0); - } else { - emit_int32(0); - } + void _halt() { + emit_int32(0); } // Register Instruction @@ -400,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); @@ -2071,90 +2066,803 @@ enum Nf { return uabs(target - branch) < branch_range; } -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, Register Rs2) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs1, Rs2) \ - _##NAME(Rd, Rs1, Rs2); \ + // --------------------------------------------------------------------------------- + // RVC: If an instruction is compressible, then + // we will implicitly emit a 16-bit compressed instruction instead of the 32-bit + // instruction in Assembler. All below logic follows Chapter - + // "C" Standard Extension for Compressed Instructions, Version 2.0. + // We can get code size reduction and performance improvement with this extension, + // considering the reduction of instruction size and the code density increment. + + // 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range + // are qualified to change to 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 print RVC instructions instead of + // 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: + +// RVC: a compressible region + class CompressibleRegion : public StackObj { + protected: + Assembler *_masm; + bool _prev_in_compressible_region; + public: + CompressibleRegion(Assembler *_masm) + : _masm(_masm) + , _prev_in_compressible_region(_masm->in_compressible_region()) { + _masm->set_in_compressible_region(true); + } + ~CompressibleRegion() { + _masm->set_in_compressible_region(_prev_in_compressible_region); + } + }; + + // RVC: extract a 16-bit instruction. + static inline uint16_t c_extract(uint16_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 15); + unsigned nbits = msb - lsb + 1; + uint16_t mask = (1U << nbits) - 1; + uint16_t result = val >> lsb; + result &= mask; + return result; + } + + static inline int16_t c_sextract(uint16_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 15); + int16_t result = val << (15 - msb); + result >>= (15 - msb + lsb); + return result; + } + + // RVC: 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); + } + + // RVC: 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()); + } + + // RVC: 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()); + } + + // RVC: 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()); + } + + // RVC: 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, REGISTER_TYPE, CHECK) \ + void NAME(REGISTER_TYPE Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + IF(CHECK, 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); \ + } + +#define IF(BOOL, ...) IF_##BOOL(__VA_ARGS__) +#define IF_true(code) code +#define IF_false(code) + + INSN(c_ldsp, 0b011, 0b10, Register, true); + INSN(c_fldsp, 0b001, 0b10, FloatRegister, false); + +#undef IF_false +#undef IF_true +#undef IF +#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 Macros -------------- + +#define IS_COMPRESSIBLE(...) if (__VA_ARGS__) +#define CHECK_RVC_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) +#define CHECK_RVC() if (UseRVC && in_compressible_region()) + +// RVC transformation macros +#define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ + PREFIX \ + CHECK_RVC_AND_COMPRESSIBLE(COND) { \ + EMIT; \ + return; \ + } \ + } + +#define EMIT_RVC_cond2(PREFIX, COND1, EMIT1, COND2, EMIT2) { \ + PREFIX \ + CHECK_RVC() { \ + IS_COMPRESSIBLE(COND1) { \ + EMIT1; \ + return; \ + } else IS_COMPRESSIBLE(COND2) { \ + EMIT2; \ + return; \ + } \ + } \ + } + +#define EMIT_RVC_cond4(PREFIX, COND1, EMIT1, COND2, EMIT2, COND3, EMIT3, COND4, EMIT4) { \ + PREFIX \ + CHECK_RVC() { \ + IS_COMPRESSIBLE(COND1) { \ + EMIT1; \ + return; \ + } else IS_COMPRESSIBLE(COND2) { \ + EMIT2; \ + return; \ + } else IS_COMPRESSIBLE(COND3) { \ + EMIT3; \ + return; \ + } else IS_COMPRESSIBLE(COND4) { \ + EMIT4; \ + return; \ + } \ + } \ + } + +private: + +#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: +// -------------- Wrapper Functions -------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + EMIT_RVC_cond( \ + Register src = noreg;, \ + Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ + c_add(Rd, src) \ + ) \ + _##NAME(Rd, Rs1, Rs2); \ } INSN(add); - INSN(sub); - INSN(andr); - INSN(orr); - INSN(xorr); - INSN(addw); - INSN(subw); + +#undef INSN + +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + EMIT_RVC_cond(, \ + Rs1 == Rd && Rd->is_compressed_valid() && Rs2->is_compressed_valid(), \ + C_NAME(Rd, Rs2) \ + ) \ + _##NAME(Rd, Rs1, Rs2); \ + } + + INSN(sub, c_sub); + INSN(subw, c_subw); + +#undef INSN + +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + EMIT_RVC_cond( \ + Register src = noreg;, \ + Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ + C_NAME(Rd, src) \ + ) \ + _##NAME(Rd, Rs1, Rs2); \ + } + + INSN(andr, c_and); + INSN(orr, c_or); + INSN(xorr, c_xor); + INSN(addw, c_addw); #undef INSN #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ + EMIT_RVC_cond2(, \ + is_c_lwswsp(Rs, Rd, offset, true), \ + c_lwsp(Rd, offset), \ + is_c_lwsw(Rs, Rd, offset), \ + c_lw(Rd, Rs, offset) \ + ) \ _##NAME(Rd, Rs, offset); \ } INSN(lw); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + is_c_ldsdsp(Rs, Rd, offset, true), \ + c_ldsp(Rd, offset), \ + is_c_ldsd(Rs, Rd, offset), \ + c_ld(Rd, Rs, offset) \ + ) \ + _##NAME(Rd, Rs, offset); \ + } + INSN(ld); #undef INSN -#define INSN(NAME) \ - void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ - _##NAME(Rd, Rs, offset); \ +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + is_c_fldsdsp(Rs, offset), \ + c_fldsp(Rd, offset), \ + is_c_fldsd(Rs, Rd, offset), \ + c_fld(Rd, Rs, offset) \ + ) \ + _##NAME(Rd, Rs, offset); \ } INSN(fld); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rs1, Rs2, offset) \ - _##NAME(Rs1, Rs2, offset); \ +#define INSN(NAME, C_NAME) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + EMIT_RVC_cond(, \ + offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1), \ + C_NAME(Rs1, offset) \ + ) \ + _##NAME(Rs1, Rs2, offset); \ } - INSN(beq); - INSN(bne); + INSN(beq, c_beqz); + INSN(bne, c_beqz); #undef INSN -#define INSN(NAME, REGISTER) \ - void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rs1, Rs2, offset) \ - _##NAME(Rs1, Rs2, offset); \ - } \ +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + is_c_ldsdsp(Rs, Rd, offset, false), \ + c_sdsp(Rd, offset), \ + is_c_ldsd(Rs, Rd, offset), \ + c_sd(Rd, Rs, offset) \ + ) \ + _##NAME(Rd, Rs, offset); \ + } - INSN(sw, Register); - INSN(sd, Register); - INSN(fsd, FloatRegister); + INSN(sd); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, const int32_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rd, offset) \ - _##NAME(Rd, offset); \ +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + is_c_lwswsp(Rs, Rd, offset, false), \ + c_swsp(Rd, offset), \ + is_c_lwsw(Rs, Rd, offset), \ + c_sw(Rd, Rs, offset) \ + ) \ + _##NAME(Rd, Rs, offset); \ + } + + INSN(sw); + +#undef INSN + +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + is_c_fldsdsp(Rs, offset), \ + c_fsdsp(Rd, offset), \ + is_c_fldsd(Rs, Rd, offset), \ + c_fsd(Rd, Rs, offset) \ + ) \ + _##NAME(Rd, Rs, offset); \ + } + + INSN(fsd); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, const int32_t offset) { \ + EMIT_RVC_cond(, \ + offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1), \ + c_j(offset) \ + ) \ + _##NAME(Rd, offset); \ } INSN(jal); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs, offset) \ - _##NAME(Rd, Rs, offset); \ +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + EMIT_RVC_cond2(, \ + offset == 0 && Rd == x1 && Rs != x0, \ + c_jalr(Rs), \ + offset == 0 && Rd == x0 && Rs != x0, \ + c_jr(Rs) \ + ) \ + _##NAME(Rd, Rs, offset); \ } INSN(jalr); #undef INSN -#define INSN(NAME) \ - void NAME() { \ - EMIT_MAY_COMPRESS(NAME) \ - _##NAME(); \ +#define INSN(NAME) \ + void NAME() { \ + EMIT_RVC_cond(, \ + true, \ + c_ebreak() \ + ) \ + _##NAME(); \ } INSN(ebreak); @@ -2163,31 +2871,82 @@ enum Nf { #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs1, imm) \ + EMIT_RVC_cond4(, \ + Rd == Rs1 && is_imm_in_range(imm, 6, 0), \ + c_addi(Rd, imm), \ + imm == 0 && Rd != x0 && Rs1 != x0, \ + c_mv(Rd, Rs1), \ + Rs1 == sp && Rd == Rs1 && imm != 0 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0), \ + c_addi16sp(imm), \ + Rs1 == sp && Rd->is_compressed_valid() && imm != 0 && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0), \ + c_addi4spn(Rd, imm) \ + ) \ _##NAME(Rd, Rs1, imm); \ } INSN(addi); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0), \ + c_addiw(Rd, imm) \ + ) \ + _##NAME(Rd, Rs1, imm); \ + } + INSN(addiw); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0), \ + c_andi(Rd, imm) \ + ) \ + _##NAME(Rd, Rs1, imm); \ + } + INSN(and_imm12); #undef INSN #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - EMIT_MAY_COMPRESS(NAME, Rd, Rs1, shamt) \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd != x0 && shamt != 0, \ + c_slli(Rd, shamt) \ + ) \ _##NAME(Rd, Rs1, shamt); \ } INSN(slli); - INSN(srai); - INSN(srli); + +#undef INSN + +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + EMIT_RVC_cond(, \ + Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0, \ + C_NAME(Rd, shamt) \ + ) \ + _##NAME(Rd, Rs1, shamt); \ + } + + INSN(srai, c_srai); + INSN(srli, c_srli); #undef INSN #define INSN(NAME) \ void NAME(Register Rd, int32_t imm) { \ - EMIT_MAY_COMPRESS(NAME, Rd, imm) \ + EMIT_RVC_cond(, \ + Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0), \ + c_lui(Rd, imm) \ + ) \ _##NAME(Rd, imm); \ } @@ -2195,6 +2954,21 @@ enum Nf { #undef INSN +#define INSN(NAME) \ + void NAME() { \ + EMIT_RVC_cond(, \ + true, \ + emit_int16(0) \ + ) \ + _##NAME(); \ + } + + INSN(halt); + +#undef INSN + +// --------------------------------------------------------------------------------------- + virtual ~Assembler() {} }; diff --git a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp b/src/hotspot/cpu/riscv/assembler_riscv_c.hpp deleted file mode 100644 index ede804406d1..00000000000 --- a/src/hotspot/cpu/riscv/assembler_riscv_c.hpp +++ /dev/null @@ -1,874 +0,0 @@ -/* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022, 2022, Alibaba Group Holding Limited. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_RISCV_ASSEMBLER_RISCV_C_HPP -#define CPU_RISCV_ASSEMBLER_RISCV_C_HPP - -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: - - // RVC: If an instruction is compressible, then - // we will implicitly emit a 16-bit compressed instruction instead of the 32-bit - // instruction in Assembler. All below logic follows Chapter - - // "C" Standard Extension for Compressed Instructions, Version 2.0. - // We can get code size reduction and performance improvement with this extension, - // considering the reduction of instruction size and the code density increment. - - // 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range - // are qualified to change to 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 print RVC instructions instead of - // normal ones. - // - - // RVC: extract a 16-bit instruction. - static inline uint16_t c_extract(uint16_t val, unsigned msb, unsigned lsb) { - assert_cond(msb >= lsb && msb <= 15); - unsigned nbits = msb - lsb + 1; - uint16_t mask = (1U << nbits) - 1; - uint16_t result = val >> lsb; - result &= mask; - return result; - } - - static inline int16_t c_sextract(uint16_t val, unsigned msb, unsigned lsb) { - assert_cond(msb >= lsb && msb <= 15); - int16_t result = val << (15 - msb); - result >>= (15 - msb + lsb); - return result; - } - - // RVC: 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); - } - - // RVC: 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()); - } - - // RVC: 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()); - } - - // RVC: 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()); - } - - // RVC: 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()); - } - -public: - -// RVC: Compressed Instructions - -// -------------- 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, REGISTER_TYPE, CHECK) \ - void NAME(REGISTER_TYPE Rd, uint32_t uimm) { \ - assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ - assert_cond((uimm & 0b111) == 0); \ - IF(CHECK, 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); \ - } - -#define IF(BOOL, ...) IF_##BOOL(__VA_ARGS__) -#define IF_true(code) code -#define IF_false(code) - - INSN(c_ldsp, 0b011, 0b10, Register, true); - INSN(c_fldsp, 0b001, 0b10, FloatRegister, false); - -#undef IF_false -#undef IF_true -#undef IF -#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 Macros -------------- - -#define EMIT_MAY_COMPRESS(NAME, ...) EMIT_MAY_COMPRESS_##NAME(__VA_ARGS__) - -#define IS_COMPRESSIBLE(...) if (__VA_ARGS__) -#define CHECK_RVC_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) -#define CHECK_RVC() if (UseRVC && in_compressible_region()) - -// RVC transformation macros -#define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ - PREFIX \ - CHECK_RVC_AND_COMPRESSIBLE(COND) { \ - EMIT; \ - return; \ - } \ - } - -#define EMIT_RVC_cond2(PREFIX, COND1, EMIT1, COND2, EMIT2) { \ - PREFIX \ - CHECK_RVC() { \ - IS_COMPRESSIBLE(COND1) { \ - EMIT1; \ - return; \ - } else IS_COMPRESSIBLE(COND2) { \ - EMIT2; \ - return; \ - } \ - } \ - } - -#define EMIT_RVC_cond4(PREFIX, COND1, EMIT1, COND2, EMIT2, COND3, EMIT3, COND4, EMIT4) { \ - PREFIX \ - CHECK_RVC() { \ - IS_COMPRESSIBLE(COND1) { \ - EMIT1; \ - return; \ - } else IS_COMPRESSIBLE(COND2) { \ - EMIT2; \ - return; \ - } else IS_COMPRESSIBLE(COND3) { \ - EMIT3; \ - return; \ - } else IS_COMPRESSIBLE(COND4) { \ - EMIT4; \ - return; \ - } \ - } \ - } - -// -------------------------- -// Register instructions -// -------------------------- -// add -> c.add -#define EMIT_MAY_COMPRESS_add(Rd, Rs1, Rs2) \ - EMIT_RVC_cond( \ - Register src = noreg;, \ - Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ - c_add(Rd, src) \ - ) - -// -------------------------- -// sub/subw -> c.sub/c.subw -#define EMIT_MAY_COMPRESS_sub_helper(C_NAME, Rd, Rs1, Rs2) \ - EMIT_RVC_cond(, \ - Rs1 == Rd && Rd->is_compressed_valid() && Rs2->is_compressed_valid(), \ - C_NAME(Rd, Rs2) \ - ) - -#define EMIT_MAY_COMPRESS_sub(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_sub_helper(c_sub, Rd, Rs1, Rs2) - -#define EMIT_MAY_COMPRESS_subw(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_sub_helper(c_subw, Rd, Rs1, Rs2) - -// -------------------------- -// xor/or/and/addw -> c.xor/c.or/c.and/c.addw -#define EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(C_NAME, Rd, Rs1, Rs2) \ - EMIT_RVC_cond( \ - Register src = noreg;, \ - Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ - ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ - C_NAME(Rd, src) \ - ) - -#define EMIT_MAY_COMPRESS_xorr(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_xor, Rd, Rs1, Rs2) - -#define EMIT_MAY_COMPRESS_orr(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_or, Rd, Rs1, Rs2) - -#define EMIT_MAY_COMPRESS_andr(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_and, Rd, Rs1, Rs2) - -#define EMIT_MAY_COMPRESS_addw(Rd, Rs1, Rs2) \ - EMIT_MAY_COMPRESS_xorr_orr_andr_addw_helper(c_addw, Rd, Rs1, Rs2) - -// -------------------------- -// Load/store register (all modes) -// -------------------------- -private: - -#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: -// -------------------------- -// ld -> c.ldsp/c.ld -#define EMIT_MAY_COMPRESS_ld(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_ldsdsp(Rs, Rd, offset, true), \ - c_ldsp(Rd, offset), \ - is_c_ldsd(Rs, Rd, offset), \ - c_ld(Rd, Rs, offset) \ - ) - -// -------------------------- -// sd -> c.sdsp/c.sd -#define EMIT_MAY_COMPRESS_sd(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_ldsdsp(Rs, Rd, offset, false), \ - c_sdsp(Rd, offset), \ - is_c_ldsd(Rs, Rd, offset), \ - c_sd(Rd, Rs, offset) \ - ) - -// -------------------------- -// lw -> c.lwsp/c.lw -#define EMIT_MAY_COMPRESS_lw(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_lwswsp(Rs, Rd, offset, true), \ - c_lwsp(Rd, offset), \ - is_c_lwsw(Rs, Rd, offset), \ - c_lw(Rd, Rs, offset) \ - ) - -// -------------------------- -// sw -> c.swsp/c.sw -#define EMIT_MAY_COMPRESS_sw(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_lwswsp(Rs, Rd, offset, false), \ - c_swsp(Rd, offset), \ - is_c_lwsw(Rs, Rd, offset), \ - c_sw(Rd, Rs, offset) \ - ) - -// -------------------------- -// fld -> c.fldsp/c.fld -#define EMIT_MAY_COMPRESS_fld(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_fldsdsp(Rs, offset), \ - c_fldsp(Rd, offset), \ - is_c_fldsd(Rs, Rd, offset), \ - c_fld(Rd, Rs, offset) \ - ) - -// -------------------------- -// fsd -> c.fsdsp/c.fsd -#define EMIT_MAY_COMPRESS_fsd(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - is_c_fldsdsp(Rs, offset), \ - c_fsdsp(Rd, offset), \ - is_c_fldsd(Rs, Rd, offset), \ - c_fsd(Rd, Rs, offset) \ - ) - -// -------------------------- -// Conditional branch instructions -// -------------------------- -// beq/bne -> c.beqz/c.bnez - -// Note: offset == 0 means this beqz/benz is jumping forward and we cannot know the future position -// so we cannot compress this instrution. -#define EMIT_MAY_COMPRESS_beqz_bnez_helper(C_NAME, Rs1, Rs2, offset) \ - EMIT_RVC_cond(, \ - offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ - is_imm_in_range(offset, 8, 1), \ - C_NAME(Rs1, offset) \ - ) - -#define EMIT_MAY_COMPRESS_beq(Rs1, Rs2, offset) \ - EMIT_MAY_COMPRESS_beqz_bnez_helper(c_beqz, Rs1, Rs2, offset) - -#define EMIT_MAY_COMPRESS_bne(Rs1, Rs2, offset) \ - EMIT_MAY_COMPRESS_beqz_bnez_helper(c_bnez, Rs1, Rs2, offset) - -// -------------------------- -// Unconditional branch instructions -// -------------------------- -// jalr/jal -> c.jr/c.jalr/c.j - -#define EMIT_MAY_COMPRESS_jalr(Rd, Rs, offset) \ - EMIT_RVC_cond2(, \ - offset == 0 && Rd == x1 && Rs != x0, \ - c_jalr(Rs), \ - offset == 0 && Rd == x0 && Rs != x0, \ - c_jr(Rs) \ - ) - -// Note: offset == 0 means this j() is jumping forward and we cannot know the future position -// so we cannot compress this instrution. -#define EMIT_MAY_COMPRESS_jal(Rd, offset) \ - EMIT_RVC_cond(, \ - offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1), \ - c_j(offset) \ - ) - -// -------------------------- -// Upper Immediate Instruction -// -------------------------- -// lui -> c.lui -#define EMIT_MAY_COMPRESS_lui(Rd, imm) \ - EMIT_RVC_cond(, \ - Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0), \ - c_lui(Rd, imm) \ - ) - -// -------------------------- -// Miscellaneous Instructions -// -------------------------- -// ebreak -> c.ebreak -#define EMIT_MAY_COMPRESS_ebreak() \ - EMIT_RVC_cond(, \ - true, \ - c_ebreak() \ - ) - -// -------------------------- -// Immediate Instructions -// -------------------------- -// addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn. -#define EMIT_MAY_COMPRESS_addi(Rd, Rs1, imm) \ - EMIT_RVC_cond4(, \ - Rd == Rs1 && is_imm_in_range(imm, 6, 0), \ - c_addi(Rd, imm), \ - imm == 0 && Rd != x0 && Rs1 != x0, \ - c_mv(Rd, Rs1), \ - Rs1 == sp && Rd == Rs1 && imm != 0 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0), \ - c_addi16sp(imm), \ - Rs1 == sp && Rd->is_compressed_valid() && imm != 0 && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0), \ - c_addi4spn(Rd, imm) \ - ) - -// -------------------------- -// addiw -> c.addiw -#define EMIT_MAY_COMPRESS_addiw(Rd, Rs1, imm) \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0), \ - c_addiw(Rd, imm) \ - ) - -// -------------------------- -// and_imm12 -> c.andi -#define EMIT_MAY_COMPRESS_and_imm12(Rd, Rs1, imm) \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0), \ - c_andi(Rd, imm) \ - ) - -// -------------------------- -// Shift Immediate Instructions -// -------------------------- -// slli -> c.slli -#define EMIT_MAY_COMPRESS_slli(Rd, Rs1, shamt) \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd != x0 && shamt != 0, \ - c_slli(Rd, shamt) \ - ) - -// -------------------------- -// srai/srli -> c.srai/c.srli -#define EMIT_MAY_COMPRESS_srai_srli_helper(C_NAME, Rd, Rs1, shamt) \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0, \ - C_NAME(Rd, shamt) \ - ) - -#define EMIT_MAY_COMPRESS_srai(Rd, Rs1, shamt) \ - EMIT_MAY_COMPRESS_srai_srli_helper(c_srai, Rd, Rs1, shamt) - -#define EMIT_MAY_COMPRESS_srli(Rd, Rs1, shamt) \ - EMIT_MAY_COMPRESS_srai_srli_helper(c_srli, Rd, Rs1, shamt) - -// -------------------------- - -public: -// RVC: a compressible region -class CompressibleRegion : public StackObj { -protected: - Assembler *_masm; - bool _prev_in_compressible_region; -public: - CompressibleRegion(Assembler *_masm) - : _masm(_masm) - , _prev_in_compressible_region(_masm->in_compressible_region()) { - _masm->set_in_compressible_region(true); - } - ~CompressibleRegion() { - _masm->set_in_compressible_region(_prev_in_compressible_region); - } -}; - -#endif // CPU_RISCV_ASSEMBLER_RISCV_C_HPP \ No newline at end of file From 654000f6c8f38c76fb4da401356e876334c73b7b Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 6 Jan 2022 13:04:38 +0800 Subject: [PATCH 10/21] Manually inline all macros into functions as discussions --- src/hotspot/cpu/riscv/assembler_riscv.cpp | 7 +- src/hotspot/cpu/riscv/assembler_riscv.hpp | 561 ++++++++++++---------- 2 files changed, 314 insertions(+), 254 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp index 321993307f6..37320d96808 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -83,12 +83,7 @@ void Assembler::zext_w(Register Rd, Register Rs) { add_uw(Rd, Rs, zr); } -void Assembler::li(Register Rd, int64_t imm) { - CHECK_RVC_AND_COMPRESSIBLE(is_imm_in_range(imm, 6, 0) && Rd != x0) { - c_li(Rd, imm); - return; - } - +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 bde3feb4ab9..bdd09ff81da 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); @@ -2591,113 +2591,41 @@ enum Nf { #undef INSN -// -------------- RVC Transformation Macros -------------- - -#define IS_COMPRESSIBLE(...) if (__VA_ARGS__) -#define CHECK_RVC_AND_COMPRESSIBLE(...) IS_COMPRESSIBLE(UseRVC && in_compressible_region() && __VA_ARGS__) -#define CHECK_RVC() if (UseRVC && in_compressible_region()) - -// RVC transformation macros -#define EMIT_RVC_cond(PREFIX, COND, EMIT) { \ - PREFIX \ - CHECK_RVC_AND_COMPRESSIBLE(COND) { \ - EMIT; \ - return; \ - } \ - } - -#define EMIT_RVC_cond2(PREFIX, COND1, EMIT1, COND2, EMIT2) { \ - PREFIX \ - CHECK_RVC() { \ - IS_COMPRESSIBLE(COND1) { \ - EMIT1; \ - return; \ - } else IS_COMPRESSIBLE(COND2) { \ - EMIT2; \ - return; \ - } \ - } \ - } - -#define EMIT_RVC_cond4(PREFIX, COND1, EMIT1, COND2, EMIT2, COND3, EMIT3, COND4, EMIT4) { \ - PREFIX \ - CHECK_RVC() { \ - IS_COMPRESSIBLE(COND1) { \ - EMIT1; \ - return; \ - } else IS_COMPRESSIBLE(COND2) { \ - EMIT2; \ - return; \ - } else IS_COMPRESSIBLE(COND3) { \ - EMIT3; \ - return; \ - } else IS_COMPRESSIBLE(COND4) { \ - EMIT4; \ - return; \ - } \ - } \ - } - -private: - -#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 +// -------------- RVC Transformation Functions -------------- -#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; \ - } \ +#define CHECK_COND(...) if (__VA_ARGS__) { +#define CHECK_RVC() CHECK_COND(UseRVC && in_compressible_region()) +#define CHECK_RETURN return; } - 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: -// -------------- Wrapper Functions -------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, Register Rs2) { \ - EMIT_RVC_cond( \ - Register src = noreg;, \ - Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ - c_add(Rd, src) \ - ) \ - _##NAME(Rd, Rs1, Rs2); \ +// -------------------------- +// Register instructions +// -------------------------- +// add -> c.add +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + CHECK_RVC() \ + Register src = noreg; \ + CHECK_COND(Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) \ + c_add(Rd, src); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, Rs2); \ } INSN(add); #undef INSN -#define INSN(NAME, C_NAME) \ - void NAME(Register Rd, Register Rs1, Register Rs2) { \ - EMIT_RVC_cond(, \ - Rs1 == Rd && Rd->is_compressed_valid() && Rs2->is_compressed_valid(), \ - C_NAME(Rd, Rs2) \ - ) \ - _##NAME(Rd, Rs1, Rs2); \ +// -------------------------- +// sub/subw -> c.sub/c.subw +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid()) \ + C_NAME(Rd, Rs2); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, Rs2); \ } INSN(sub, c_sub); @@ -2705,15 +2633,18 @@ enum Nf { #undef INSN -#define INSN(NAME, C_NAME) \ - void NAME(Register Rd, Register Rs1, Register Rs2) { \ - EMIT_RVC_cond( \ - Register src = noreg;, \ - Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ - ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd)), \ - C_NAME(Rd, src) \ - ) \ - _##NAME(Rd, Rs1, Rs2); \ +// -------------------------- +// xor/or/and/addw -> c.xor/c.or/c.and/c.addw +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + CHECK_RVC() \ + Register src = noreg; \ + CHECK_COND(Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) \ + C_NAME(Rd, src); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, Rs2); \ } INSN(andr, c_and); @@ -2723,145 +2654,232 @@ enum Nf { #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_lwswsp(Rs, Rd, offset, true), \ - c_lwsp(Rd, offset), \ - is_c_lwsw(Rs, Rd, offset), \ - c_lw(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +private: +// some helper functions +#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 +// -------------------------- +// lw -> c.lwsp/c.lw +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_lwswsp(Rs, Rd, offset, true)) \ + c_lwsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_lwsw(Rs, Rd, offset)) \ + c_lw(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } INSN(lw); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_ldsdsp(Rs, Rd, offset, true), \ - c_ldsp(Rd, offset), \ - is_c_ldsd(Rs, Rd, offset), \ - c_ld(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// ld -> c.ldsp/c.ld +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_ldsdsp(Rs, Rd, offset, true)) \ + c_ldsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_ldsd(Rs, Rd, offset)) \ + c_ld(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } INSN(ld); #undef INSN -#define INSN(NAME) \ - void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_fldsdsp(Rs, offset), \ - c_fldsp(Rd, offset), \ - is_c_fldsd(Rs, Rd, offset), \ - c_fld(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// fld -> c.fldsp/c.fld +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_fldsdsp(Rs, offset)) \ + c_fldsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_fldsd(Rs, Rd, offset)) \ + c_fld(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } INSN(fld); #undef INSN -#define INSN(NAME, C_NAME) \ - void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - EMIT_RVC_cond(, \ - offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ - is_imm_in_range(offset, 8, 1), \ - C_NAME(Rs1, offset) \ - ) \ - _##NAME(Rs1, Rs2, offset); \ +// -------------------------- +// sd -> c.sdsp/c.sd +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_ldsdsp(Rs, Rd, offset, false)) \ + c_sdsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_ldsd(Rs, Rd, offset)) \ + c_sd(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } - INSN(beq, c_beqz); - INSN(bne, c_beqz); + INSN(sd); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_ldsdsp(Rs, Rd, offset, false), \ - c_sdsp(Rd, offset), \ - is_c_ldsd(Rs, Rd, offset), \ - c_sd(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// sw -> c.swsp/c.sw +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_lwswsp(Rs, Rd, offset, false)) \ + c_swsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_lwsw(Rs, Rd, offset)) \ + c_sw(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } - INSN(sd); + INSN(sw); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_lwswsp(Rs, Rd, offset, false), \ - c_swsp(Rd, offset), \ - is_c_lwsw(Rs, Rd, offset), \ - c_sw(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// fsd -> c.fsdsp/c.fsd +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(is_c_fldsdsp(Rs, offset)) \ + c_fsdsp(Rd, offset); \ + CHECK_RETURN \ + else CHECK_COND(is_c_fldsd(Rs, Rd, offset)) \ + c_fsd(Rd, Rs, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs, offset); \ } - INSN(sw); + INSN(fsd); #undef INSN -#define INSN(NAME) \ - void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - is_c_fldsdsp(Rs, offset), \ - c_fsdsp(Rd, offset), \ - is_c_fldsd(Rs, Rd, offset), \ - c_fsd(Rd, Rs, offset) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// Conditional branch instructions +// -------------------------- +// beq/bne -> c.beqz/c.bnez + +#define INSN(NAME, C_NAME) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + CHECK_RVC() \ + CHECK_COND(offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1)) \ + C_NAME(Rs1, offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rs1, Rs2, offset); \ } - INSN(fsd); + INSN(beq, c_beqz); + INSN(bne, c_beqz); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, const int32_t offset) { \ - EMIT_RVC_cond(, \ - offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1), \ - c_j(offset) \ - ) \ - _##NAME(Rd, offset); \ +// -------------------------- +// Unconditional branch instructions +// -------------------------- +// jal -> c.j +#define INSN(NAME) \ + void NAME(Register Rd, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) \ + c_j(offset); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, offset); \ } INSN(jal); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - EMIT_RVC_cond2(, \ - offset == 0 && Rd == x1 && Rs != x0, \ - c_jalr(Rs), \ - offset == 0 && Rd == x0 && Rs != x0, \ - c_jr(Rs) \ - ) \ - _##NAME(Rd, Rs, offset); \ +// -------------------------- +// jalr -> c.jr/c.jalr +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + CHECK_RVC() \ + CHECK_COND(offset == 0 && Rs != x0) \ + CHECK_COND(Rd == x1) \ + c_jalr(Rs); \ + CHECK_RETURN \ + else CHECK_COND(Rd == x0) \ + c_jr(Rs); \ + CHECK_RETURN \ + } \ + } \ + _##NAME(Rd, Rs, offset); \ } INSN(jalr); #undef INSN +// -------------------------- +// Miscellaneous Instructions +// -------------------------- +// ebreak -> c.ebreak #define INSN(NAME) \ void NAME() { \ - EMIT_RVC_cond(, \ - true, \ - c_ebreak() \ - ) \ + CHECK_RVC() \ + c_ebreak(); \ + CHECK_RETURN \ _##NAME(); \ } @@ -2869,71 +2887,110 @@ enum Nf { #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, int32_t imm) { \ - EMIT_RVC_cond4(, \ - Rd == Rs1 && is_imm_in_range(imm, 6, 0), \ - c_addi(Rd, imm), \ - imm == 0 && Rd != x0 && Rs1 != x0, \ - c_mv(Rd, Rs1), \ - Rs1 == sp && Rd == Rs1 && imm != 0 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0), \ - c_addi16sp(imm), \ - Rs1 == sp && Rd->is_compressed_valid() && imm != 0 && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0), \ - c_addi4spn(Rd, imm) \ - ) \ - _##NAME(Rd, Rs1, imm); \ +// -------------------------- +// Immediate Instructions +// -------------------------- +// li -> c.li +#define INSN(NAME) \ + void NAME(Register Rd, int64_t imm) { \ + CHECK_RVC() \ + CHECK_COND(is_imm_in_range(imm, 6, 0) && Rd != x0) \ + c_li(Rd, imm); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, imm); \ + } + + INSN(li); + +#undef INSN + +// addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn. +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && is_imm_in_range(imm, 6, 0)) \ + c_addi(Rd, imm); \ + CHECK_RETURN \ + else CHECK_COND(imm == 0 && Rd != x0 && Rs1 != x0) \ + c_mv(Rd, Rs1); \ + CHECK_RETURN \ + else CHECK_COND(Rs1 == sp && imm != 0) \ + CHECK_COND(Rd == Rs1 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0)) \ + c_addi16sp(imm); \ + CHECK_RETURN \ + else CHECK_COND(Rd->is_compressed_valid() && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0)) \ + c_addi4spn(Rd, imm); \ + CHECK_RETURN \ + } \ + } \ + _##NAME(Rd, Rs1, imm); \ } INSN(addi); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, int32_t imm) { \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0), \ - c_addiw(Rd, imm) \ - ) \ - _##NAME(Rd, Rs1, imm); \ +// -------------------------- +// addiw -> c.addiw +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0)) \ + c_addiw(Rd, imm); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, imm); \ } INSN(addiw); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, int32_t imm) { \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0), \ - c_andi(Rd, imm) \ - ) \ - _##NAME(Rd, Rs1, imm); \ +// -------------------------- +// and_imm12 -> c.andi +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0)) \ + c_andi(Rd, imm); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, imm); \ } INSN(and_imm12); #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd != x0 && shamt != 0, \ - c_slli(Rd, shamt) \ - ) \ - _##NAME(Rd, Rs1, shamt); \ +// -------------------------- +// Shift Immediate Instructions +// -------------------------- +// slli -> c.slli +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && Rd != x0 && shamt != 0) \ + c_slli(Rd, shamt); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, shamt); \ } INSN(slli); #undef INSN -#define INSN(NAME, C_NAME) \ - void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - EMIT_RVC_cond(, \ - Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0, \ - C_NAME(Rd, shamt) \ - ) \ - _##NAME(Rd, Rs1, shamt); \ +// -------------------------- +// srai/srli -> c.srai/c.srli +#define INSN(NAME, C_NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + CHECK_RVC() \ + CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0) \ + C_NAME(Rd, shamt); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, Rs1, shamt); \ } INSN(srai, c_srai); @@ -2941,13 +2998,18 @@ enum Nf { #undef INSN -#define INSN(NAME) \ - void NAME(Register Rd, int32_t imm) { \ - EMIT_RVC_cond(, \ - Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0), \ - c_lui(Rd, imm) \ - ) \ - _##NAME(Rd, imm); \ +// -------------------------- +// Upper Immediate Instruction +// -------------------------- +// lui -> c.lui +#define INSN(NAME) \ + void NAME(Register Rd, int32_t imm) { \ + CHECK_RVC() \ + CHECK_COND(Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0)) \ + c_lui(Rd, imm); \ + CHECK_RETURN \ + } \ + _##NAME(Rd, imm); \ } INSN(lui); @@ -2956,10 +3018,9 @@ enum Nf { #define INSN(NAME) \ void NAME() { \ - EMIT_RVC_cond(, \ - true, \ - emit_int16(0) \ - ) \ + CHECK_RVC() \ + emit_int16(0); \ + CHECK_RETURN \ _##NAME(); \ } @@ -2967,6 +3028,10 @@ enum Nf { #undef INSN +#undef CHECK_RETURN +#undef CHECK_RVC +#undef CHECK_COND + // --------------------------------------------------------------------------------------- virtual ~Assembler() {} From d915c7bc7f99307443f5de349992679968d28f4e Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 6 Jan 2022 16:12:49 +0800 Subject: [PATCH 11/21] Remain an 'minimum_alignment' unchanged --- src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index d3fa1578f95..5b24e062b18 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -329,7 +329,7 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { } int minimum_alignment = 16; -#if (defined(X86) && !defined(AMD64)) || defined(RISCV) +#if defined(X86) && !defined(AMD64) minimum_alignment = 4; #elif defined(S390) minimum_alignment = 2; From 8daf01f6a12508e281397376473c92f3635939b2 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 6 Jan 2022 17:10:24 +0800 Subject: [PATCH 12/21] Remove remaining macros as discussions --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 278 +++++++++++----------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index bdd09ff81da..87cd218ef60 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2593,23 +2593,20 @@ enum Nf { // -------------- RVC Transformation Functions -------------- -#define CHECK_COND(...) if (__VA_ARGS__) { -#define CHECK_RVC() CHECK_COND(UseRVC && in_compressible_region()) -#define CHECK_RETURN return; } - // -------------------------- // Register instructions // -------------------------- // add -> c.add #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - CHECK_RVC() \ + if (check_rvc()) { \ Register src = noreg; \ - CHECK_COND(Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) \ + if (Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ c_add(Rd, src); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs1, Rs2); \ + _add(Rd, Rs1, Rs2); \ } INSN(add); @@ -2618,44 +2615,49 @@ enum Nf { // -------------------------- // sub/subw -> c.sub/c.subw -#define INSN(NAME, C_NAME) \ +#define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid()) \ - C_NAME(Rd, Rs2); \ - CHECK_RETURN \ + if (check_rvc() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid())) { \ + C_NAME(Rd, Rs2); \ + return; \ } \ - _##NAME(Rd, Rs1, Rs2); \ + NORMAL_NAME(Rd, Rs1, Rs2); \ } - INSN(sub, c_sub); - INSN(subw, c_subw); + INSN(sub, c_sub, _sub); + INSN(subw, c_subw, _subw); #undef INSN // -------------------------- // xor/or/and/addw -> c.xor/c.or/c.and/c.addw -#define INSN(NAME, C_NAME) \ +#define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - CHECK_RVC() \ + if (check_rvc()) { \ Register src = noreg; \ - CHECK_COND(Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ - ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) \ + if (Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ C_NAME(Rd, src); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs1, Rs2); \ + NORMAL_NAME(Rd, Rs1, Rs2); \ } - INSN(andr, c_and); - INSN(orr, c_or); - INSN(xorr, c_xor); - INSN(addw, c_addw); + 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 check_rvc() 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 && \ @@ -2701,15 +2703,16 @@ enum Nf { // lw -> c.lwsp/c.lw #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_lwswsp(Rs, Rd, offset, true)) \ + if (check_rvc()) { \ + if (is_c_lwswsp(Rs, Rd, offset, true)) { \ c_lwsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_lwsw(Rs, Rd, offset)) \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ c_lw(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _lw(Rd, Rs, offset); \ } INSN(lw); @@ -2720,15 +2723,16 @@ enum Nf { // ld -> c.ldsp/c.ld #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_ldsdsp(Rs, Rd, offset, true)) \ + if (check_rvc()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, true)) { \ c_ldsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_ldsd(Rs, Rd, offset)) \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ c_ld(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _ld(Rd, Rs, offset); \ } INSN(ld); @@ -2739,15 +2743,16 @@ enum Nf { // fld -> c.fldsp/c.fld #define INSN(NAME) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_fldsdsp(Rs, offset)) \ + if (check_rvc()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ c_fldsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_fldsd(Rs, Rd, offset)) \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ c_fld(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _fld(Rd, Rs, offset); \ } INSN(fld); @@ -2758,15 +2763,16 @@ enum Nf { // sd -> c.sdsp/c.sd #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_ldsdsp(Rs, Rd, offset, false)) \ + if (check_rvc()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, false)) { \ c_sdsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_ldsd(Rs, Rd, offset)) \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ c_sd(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _sd(Rd, Rs, offset); \ } INSN(sd); @@ -2777,15 +2783,16 @@ enum Nf { // sw -> c.swsp/c.sw #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_lwswsp(Rs, Rd, offset, false)) \ + if (check_rvc()) { \ + if (is_c_lwswsp(Rs, Rd, offset, false)) { \ c_swsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_lwsw(Rs, Rd, offset)) \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ c_sw(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _sw(Rd, Rs, offset); \ } INSN(sw); @@ -2796,15 +2803,16 @@ enum Nf { // fsd -> c.fsdsp/c.fsd #define INSN(NAME) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(is_c_fldsdsp(Rs, offset)) \ + if (check_rvc()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ c_fsdsp(Rd, offset); \ - CHECK_RETURN \ - else CHECK_COND(is_c_fldsd(Rs, Rd, offset)) \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ c_fsd(Rd, Rs, offset); \ - CHECK_RETURN \ + return; \ + } \ } \ - _##NAME(Rd, Rs, offset); \ + _fsd(Rd, Rs, offset); \ } INSN(fsd); @@ -2816,19 +2824,19 @@ enum Nf { // -------------------------- // beq/bne -> c.beqz/c.bnez -#define INSN(NAME, C_NAME) \ +#define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - CHECK_RVC() \ - CHECK_COND(offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ - is_imm_in_range(offset, 8, 1)) \ - C_NAME(Rs1, offset); \ - CHECK_RETURN \ + if (check_rvc() && \ + (offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1))) { \ + C_NAME(Rs1, offset); \ + return; \ } \ - _##NAME(Rs1, Rs2, offset); \ + NORMAL_NAME(Rs1, Rs2, offset); \ } - INSN(beq, c_beqz); - INSN(bne, c_beqz); + INSN(beq, c_beqz, _beq); + INSN(bne, c_beqz, _bne); #undef INSN @@ -2838,12 +2846,11 @@ enum Nf { // jal -> c.j #define INSN(NAME) \ void NAME(Register Rd, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) \ - c_j(offset); \ - CHECK_RETURN \ + if (check_rvc() && offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) { \ + c_j(offset); \ + return; \ } \ - _##NAME(Rd, offset); \ + _jal(Rd, offset); \ } INSN(jal); @@ -2854,17 +2861,16 @@ enum Nf { // jalr -> c.jr/c.jalr #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - CHECK_RVC() \ - CHECK_COND(offset == 0 && Rs != x0) \ - CHECK_COND(Rd == x1) \ - c_jalr(Rs); \ - CHECK_RETURN \ - else CHECK_COND(Rd == x0) \ - c_jr(Rs); \ - CHECK_RETURN \ + if (check_rvc() && (offset == 0 && Rs != x0)) { \ + if (Rd == x1) { \ + c_jalr(Rs); \ + return; \ + } else if (Rd == x0) { \ + c_jr(Rs); \ + return; \ } \ } \ - _##NAME(Rd, Rs, offset); \ + _jalr(Rd, Rs, offset); \ } INSN(jalr); @@ -2877,10 +2883,11 @@ enum Nf { // ebreak -> c.ebreak #define INSN(NAME) \ void NAME() { \ - CHECK_RVC() \ + if (check_rvc()) { \ c_ebreak(); \ - CHECK_RETURN \ - _##NAME(); \ + return; \ + } \ + _ebreak(); \ } INSN(ebreak); @@ -2893,12 +2900,11 @@ enum Nf { // li -> c.li #define INSN(NAME) \ void NAME(Register Rd, int64_t imm) { \ - CHECK_RVC() \ - CHECK_COND(is_imm_in_range(imm, 6, 0) && Rd != x0) \ - c_li(Rd, imm); \ - CHECK_RETURN \ + if (check_rvc() && (is_imm_in_range(imm, 6, 0) && Rd != x0)) { \ + c_li(Rd, imm); \ + return; \ } \ - _##NAME(Rd, imm); \ + _li(Rd, imm); \ } INSN(li); @@ -2908,23 +2914,24 @@ enum Nf { // addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn. #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && is_imm_in_range(imm, 6, 0)) \ + if (check_rvc()) { \ + if (Rd == Rs1 && is_imm_in_range(imm, 6, 0)) { \ c_addi(Rd, imm); \ - CHECK_RETURN \ - else CHECK_COND(imm == 0 && Rd != x0 && Rs1 != x0) \ + return; \ + } else if (imm == 0 && Rd != x0 && Rs1 != x0) { \ c_mv(Rd, Rs1); \ - CHECK_RETURN \ - else CHECK_COND(Rs1 == sp && imm != 0) \ - CHECK_COND(Rd == Rs1 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0)) \ + return; \ + } else if (Rs1 == sp && imm != 0) { \ + if (Rd == Rs1 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0)) { \ c_addi16sp(imm); \ - CHECK_RETURN \ - else CHECK_COND(Rd->is_compressed_valid() && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0)) \ + return; \ + } else if (Rd->is_compressed_valid() && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0)) { \ c_addi4spn(Rd, imm); \ - CHECK_RETURN \ + return; \ + } \ } \ } \ - _##NAME(Rd, Rs1, imm); \ + _addi(Rd, Rs1, imm); \ } INSN(addi); @@ -2935,12 +2942,11 @@ enum Nf { // addiw -> c.addiw #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0)) \ - c_addiw(Rd, imm); \ - CHECK_RETURN \ + if (check_rvc() && (Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0))) { \ + c_addiw(Rd, imm); \ + return; \ } \ - _##NAME(Rd, Rs1, imm); \ + _addiw(Rd, Rs1, imm); \ } INSN(addiw); @@ -2951,12 +2957,12 @@ enum Nf { // and_imm12 -> c.andi #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0)) \ - c_andi(Rd, imm); \ - CHECK_RETURN \ + if (check_rvc() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0))) { \ + c_andi(Rd, imm); \ + return; \ } \ - _##NAME(Rd, Rs1, imm); \ + _and_imm12(Rd, Rs1, imm); \ } INSN(and_imm12); @@ -2969,12 +2975,11 @@ enum Nf { // slli -> c.slli #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && Rd != x0 && shamt != 0) \ - c_slli(Rd, shamt); \ - CHECK_RETURN \ + if (check_rvc() && (Rd == Rs1 && Rd != x0 && shamt != 0)) { \ + c_slli(Rd, shamt); \ + return; \ } \ - _##NAME(Rd, Rs1, shamt); \ + _slli(Rd, Rs1, shamt); \ } INSN(slli); @@ -2983,18 +2988,17 @@ enum Nf { // -------------------------- // srai/srli -> c.srai/c.srli -#define INSN(NAME, C_NAME) \ +#define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - CHECK_RVC() \ - CHECK_COND(Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0) \ - C_NAME(Rd, shamt); \ - CHECK_RETURN \ + if (check_rvc() && (Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0)) { \ + C_NAME(Rd, shamt); \ + return; \ } \ - _##NAME(Rd, Rs1, shamt); \ + NORMAL_NAME(Rd, Rs1, shamt); \ } - INSN(srai, c_srai); - INSN(srli, c_srli); + INSN(srai, c_srai, _srai); + INSN(srli, c_srli, _srli); #undef INSN @@ -3004,12 +3008,11 @@ enum Nf { // lui -> c.lui #define INSN(NAME) \ void NAME(Register Rd, int32_t imm) { \ - CHECK_RVC() \ - CHECK_COND(Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0)) \ - c_lui(Rd, imm); \ - CHECK_RETURN \ + if (check_rvc() && (Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0))) { \ + c_lui(Rd, imm); \ + return; \ } \ - _##NAME(Rd, imm); \ + _lui(Rd, imm); \ } INSN(lui); @@ -3018,20 +3021,17 @@ enum Nf { #define INSN(NAME) \ void NAME() { \ - CHECK_RVC() \ + if (check_rvc()) { \ emit_int16(0); \ - CHECK_RETURN \ - _##NAME(); \ + return; \ + } \ + _halt(); \ } INSN(halt); #undef INSN -#undef CHECK_RETURN -#undef CHECK_RVC -#undef CHECK_COND - // --------------------------------------------------------------------------------------- virtual ~Assembler() {} From b9b3632e688746c35eb22d0ed96841317af09785 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 6 Jan 2022 17:29:11 +0800 Subject: [PATCH 13/21] Rename misc functions and change the positions of some comments --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 93 ++++++++++++----------- src/hotspot/cpu/riscv/globals_riscv.hpp | 2 +- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 87cd218ef60..b49e0de703d 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2101,15 +2101,15 @@ enum Nf { class CompressibleRegion : public StackObj { protected: Assembler *_masm; - bool _prev_in_compressible_region; + bool _saved_in_compressible_region; public: CompressibleRegion(Assembler *_masm) : _masm(_masm) - , _prev_in_compressible_region(_masm->in_compressible_region()) { + , _saved_in_compressible_region(_masm->in_compressible_region()) { _masm->set_in_compressible_region(true); } ~CompressibleRegion() { - _masm->set_in_compressible_region(_prev_in_compressible_region); + _masm->set_in_compressible_region(_saved_in_compressible_region); } }; @@ -2596,10 +2596,10 @@ enum Nf { // -------------------------- // Register instructions // -------------------------- -// add -> c.add #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - if (check_rvc()) { \ + /* 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); \ @@ -2614,10 +2614,10 @@ enum Nf { #undef INSN // -------------------------- -// sub/subw -> c.sub/c.subw #define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - if (check_rvc() && \ + /* sub/subw -> c.sub/c.subw */ \ + if (do_compress() && \ (Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid())) { \ C_NAME(Rd, Rs2); \ return; \ @@ -2631,10 +2631,10 @@ enum Nf { #undef INSN // -------------------------- -// xor/or/and/addw -> c.xor/c.or/c.and/c.addw #define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, Register Rs2) { \ - if (check_rvc()) { \ + /* 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))) { \ @@ -2654,7 +2654,7 @@ enum Nf { private: // some helper functions - bool check_rvc() const { + bool do_compress() const { return UseRVC && in_compressible_region(); } @@ -2700,10 +2700,10 @@ enum Nf { // -------------------------- // Load/store register // -------------------------- -// lw -> c.lwsp/c.lw #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* lw -> c.lwsp/c.lw */ \ + if (do_compress()) { \ if (is_c_lwswsp(Rs, Rd, offset, true)) { \ c_lwsp(Rd, offset); \ return; \ @@ -2720,10 +2720,10 @@ enum Nf { #undef INSN // -------------------------- -// ld -> c.ldsp/c.ld #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* ld -> c.ldsp/c.ld */ \ + if (do_compress()) { \ if (is_c_ldsdsp(Rs, Rd, offset, true)) { \ c_ldsp(Rd, offset); \ return; \ @@ -2740,10 +2740,10 @@ enum Nf { #undef INSN // -------------------------- -// fld -> c.fldsp/c.fld #define INSN(NAME) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* fld -> c.fldsp/c.fld */ \ + if (do_compress()) { \ if (is_c_fldsdsp(Rs, offset)) { \ c_fldsp(Rd, offset); \ return; \ @@ -2760,10 +2760,10 @@ enum Nf { #undef INSN // -------------------------- -// sd -> c.sdsp/c.sd #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* sd -> c.sdsp/c.sd */ \ + if (do_compress()) { \ if (is_c_ldsdsp(Rs, Rd, offset, false)) { \ c_sdsp(Rd, offset); \ return; \ @@ -2780,10 +2780,10 @@ enum Nf { #undef INSN // -------------------------- -// sw -> c.swsp/c.sw #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* sw -> c.swsp/c.sw */ \ + if (do_compress()) { \ if (is_c_lwswsp(Rs, Rd, offset, false)) { \ c_swsp(Rd, offset); \ return; \ @@ -2800,10 +2800,10 @@ enum Nf { #undef INSN // -------------------------- -// fsd -> c.fsdsp/c.fsd #define INSN(NAME) \ void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - if (check_rvc()) { \ + /* fsd -> c.fsdsp/c.fsd */ \ + if (do_compress()) { \ if (is_c_fldsdsp(Rs, offset)) { \ c_fsdsp(Rd, offset); \ return; \ @@ -2822,11 +2822,10 @@ enum Nf { // -------------------------- // Conditional branch instructions // -------------------------- -// beq/bne -> c.beqz/c.bnez - #define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ - if (check_rvc() && \ + /* 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); \ @@ -2843,10 +2842,10 @@ enum Nf { // -------------------------- // Unconditional branch instructions // -------------------------- -// jal -> c.j #define INSN(NAME) \ void NAME(Register Rd, const int32_t offset) { \ - if (check_rvc() && offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) { \ + /* jal -> c.j */ \ + if (do_compress() && offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) { \ c_j(offset); \ return; \ } \ @@ -2858,10 +2857,10 @@ enum Nf { #undef INSN // -------------------------- -// jalr -> c.jr/c.jalr #define INSN(NAME) \ void NAME(Register Rd, Register Rs, const int32_t offset) { \ - if (check_rvc() && (offset == 0 && Rs != x0)) { \ + /* jalr -> c.jr/c.jalr */ \ + if (do_compress() && (offset == 0 && Rs != x0)) { \ if (Rd == x1) { \ c_jalr(Rs); \ return; \ @@ -2880,10 +2879,10 @@ enum Nf { // -------------------------- // Miscellaneous Instructions // -------------------------- -// ebreak -> c.ebreak #define INSN(NAME) \ void NAME() { \ - if (check_rvc()) { \ + /* ebreak -> c.ebreak */ \ + if (do_compress()) { \ c_ebreak(); \ return; \ } \ @@ -2897,10 +2896,10 @@ enum Nf { // -------------------------- // Immediate Instructions // -------------------------- -// li -> c.li #define INSN(NAME) \ void NAME(Register Rd, int64_t imm) { \ - if (check_rvc() && (is_imm_in_range(imm, 6, 0) && Rd != x0)) { \ + /* li -> c.li */ \ + if (do_compress() && (is_imm_in_range(imm, 6, 0) && Rd != x0)) { \ c_li(Rd, imm); \ return; \ } \ @@ -2911,10 +2910,11 @@ enum Nf { #undef INSN -// addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn. +// -------------------------- #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - if (check_rvc()) { \ + /* 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; \ @@ -2939,10 +2939,10 @@ enum Nf { #undef INSN // -------------------------- -// addiw -> c.addiw #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - if (check_rvc() && (Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0))) { \ + /* addiw -> c.addiw */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0))) { \ c_addiw(Rd, imm); \ return; \ } \ @@ -2954,10 +2954,10 @@ enum Nf { #undef INSN // -------------------------- -// and_imm12 -> c.andi #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, int32_t imm) { \ - if (check_rvc() && \ + /* 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; \ @@ -2972,10 +2972,10 @@ enum Nf { // -------------------------- // Shift Immediate Instructions // -------------------------- -// slli -> c.slli #define INSN(NAME) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - if (check_rvc() && (Rd == Rs1 && Rd != x0 && shamt != 0)) { \ + /* slli -> c.slli */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && shamt != 0)) { \ c_slli(Rd, shamt); \ return; \ } \ @@ -2987,10 +2987,10 @@ enum Nf { #undef INSN // -------------------------- -// srai/srli -> c.srai/c.srli #define INSN(NAME, C_NAME, NORMAL_NAME) \ void NAME(Register Rd, Register Rs1, unsigned shamt) { \ - if (check_rvc() && (Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0)) { \ + /* srai/srli -> c.srai/c.srli */ \ + if (do_compress() && (Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0)) { \ C_NAME(Rd, shamt); \ return; \ } \ @@ -3005,10 +3005,10 @@ enum Nf { // -------------------------- // Upper Immediate Instruction // -------------------------- -// lui -> c.lui #define INSN(NAME) \ void NAME(Register Rd, int32_t imm) { \ - if (check_rvc() && (Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0))) { \ + /* lui -> c.lui */ \ + if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0))) { \ c_lui(Rd, imm); \ return; \ } \ @@ -3021,7 +3021,8 @@ enum Nf { #define INSN(NAME) \ void NAME() { \ - if (check_rvc()) { \ + /* The illegal instruction in RVC is presented by a 16-bit 0. */ \ + if (do_compress()) { \ emit_int16(0); \ return; \ } \ diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index f1e57f9e461..004b12f15a9 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -92,6 +92,6 @@ define_pd_global(intx, InlineSmallCode, 1000); "Avoid generating unaligned memory accesses") \ product(bool, UseRVV, false, EXPERIMENTAL, "Use RVV instructions") \ product(bool, UseRVB, false, EXPERIMENTAL, "Use RVB instructions") \ - product(bool, UseRVC, false, EXPERIMENTAL, "Use RVC instructions") \ + product(bool, UseRVC, false, EXPERIMENTAL, "Use RVC instructions") #endif // CPU_RISCV_GLOBALS_RISCV_HPP From 206956774216333b9e83c0ab8dd46742dc5cf14a Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Fri, 7 Jan 2022 16:11:04 +0800 Subject: [PATCH 14/21] Move RVC code to the proper location after rebasing (#42) --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 157 +++++++++++----------- 1 file changed, 76 insertions(+), 81 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index b49e0de703d..094032cff8c 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2019,76 +2019,24 @@ enum Nf { #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); - void bleu(Register Rs, Register Rt, const address &dest); - void bgt(Register Rs, Register Rt, Label &l, bool is_far = false); - void ble(Register Rs, Register Rt, Label &l, bool is_far = false); - void bgtu(Register Rs, Register Rt, Label &l, bool is_far = false); - void bleu(Register Rs, Register Rt, Label &l, bool is_far = false); - - typedef void (Assembler::* jal_jalr_insn)(Register Rt, address dest); - typedef void (Assembler::* load_insn_by_temp)(Register Rt, address dest, Register temp); - typedef void (Assembler::* compare_and_branch_insn)(Register Rs1, Register Rs2, const address dest); - typedef void (Assembler::* compare_and_branch_label_insn)(Register Rs1, Register Rs2, Label &L, bool is_far); - - void wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn, - compare_and_branch_label_insn neg_insn, bool is_far); - void wrap_label(Register r, Label &L, Register t, load_insn_by_temp insn); - void wrap_label(Register r, Label &L, jal_jalr_insn insn); - - // calculate pseudoinstruction - void add(Register Rd, Register Rn, int64_t increment, Register temp = t0); - void addw(Register Rd, Register Rn, int64_t increment, Register temp = t0); - void sub(Register Rd, Register Rn, int64_t decrement, Register temp = t0); - void subw(Register Rd, Register Rn, int64_t decrement, Register temp = t0); - - // RVB pseudo instructions - // zero extend word - void zext_w(Register Rd, Register Rs); - - Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(false) { - } - - // Stack overflow checking - virtual void bang_stack_with_offset(int offset) { Unimplemented(); } - - static bool operand_valid_for_add_immediate(long imm) { - return is_imm_in_range(imm, 12, 0); - } - - // The maximum range of a branch is fixed for the riscv64 - // architecture. - static const unsigned long branch_range = 1 * M; - - static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; - } - - // --------------------------------------------------------------------------------- - // RVC: If an instruction is compressible, then - // we will implicitly emit a 16-bit compressed instruction instead of the 32-bit - // instruction in Assembler. All below logic follows Chapter - - // "C" Standard Extension for Compressed Instructions, Version 2.0. - // We can get code size reduction and performance improvement with this extension, - // considering the reduction of instruction size and the code density increment. - - // 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range - // are qualified to change to 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 print RVC instructions instead of - // normal ones. - // +// ======================================== +// 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range +// are qualified to change to 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 print RVC instructions instead of +// normal ones. +// private: bool _in_compressible_region; @@ -2893,6 +2841,20 @@ enum Nf { #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 // -------------------------- @@ -3019,21 +2981,54 @@ enum Nf { #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(); \ +// --------------------------------------------------------------------------------------- + + 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); + void bleu(Register Rs, Register Rt, const address &dest); + void bgt(Register Rs, Register Rt, Label &l, bool is_far = false); + void ble(Register Rs, Register Rt, Label &l, bool is_far = false); + void bgtu(Register Rs, Register Rt, Label &l, bool is_far = false); + void bleu(Register Rs, Register Rt, Label &l, bool is_far = false); + + typedef void (Assembler::* jal_jalr_insn)(Register Rt, address dest); + typedef void (Assembler::* load_insn_by_temp)(Register Rt, address dest, Register temp); + typedef void (Assembler::* compare_and_branch_insn)(Register Rs1, Register Rs2, const address dest); + typedef void (Assembler::* compare_and_branch_label_insn)(Register Rs1, Register Rs2, Label &L, bool is_far); + + void wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn, + compare_and_branch_label_insn neg_insn, bool is_far); + void wrap_label(Register r, Label &L, Register t, load_insn_by_temp insn); + void wrap_label(Register r, Label &L, jal_jalr_insn insn); + + // calculate pseudoinstruction + void add(Register Rd, Register Rn, int64_t increment, Register temp = t0); + void addw(Register Rd, Register Rn, int64_t increment, Register temp = t0); + void sub(Register Rd, Register Rn, int64_t decrement, Register temp = t0); + void subw(Register Rd, Register Rn, int64_t decrement, Register temp = t0); + + // RVB pseudo instructions + // zero extend word + void zext_w(Register Rd, Register Rs); + + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(false) { } - INSN(halt); + // Stack overflow checking + virtual void bang_stack_with_offset(int offset) { Unimplemented(); } -#undef INSN + static bool operand_valid_for_add_immediate(long imm) { + return is_imm_in_range(imm, 12, 0); + } -// --------------------------------------------------------------------------------------- + // The maximum range of a branch is fixed for the riscv64 + // architecture. + static const unsigned long branch_range = 1 * M; + + static bool reachable_from_branch_at(address branch, address target) { + return uabs(target - branch) < branch_range; + } virtual ~Assembler() {} From 7accc38e411d801aa26d10d765a73338ebd7ecec Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Fri, 7 Jan 2022 17:02:47 +0800 Subject: [PATCH 15/21] Remove useless and polish comments --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 39 ++++++------------- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/riscv.ad | 8 +--- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 11 +++--- 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 094032cff8c..b0459605b74 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2023,19 +2023,19 @@ enum Nf { // 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range -// are qualified to change to their 2-byte versions. -// An example: +// 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range +// are qualified to change to their 2-byte versions. +// An example: // -// CompressibleRegion cr(_masm); -// __ andr(...); // this instruction could change to c.and if able to +// CompressibleRegion cr(_masm); +// __ andr(...); // this instruction could change to c.and if able to // -// 4. Using -XX:PrintAssemblyOptions=no-aliases could print RVC instructions instead of -// normal ones. +// 4. Using -XX:PrintAssemblyOptions=no-aliases could print RVC instructions instead of +// normal ones. // private: @@ -2061,23 +2061,6 @@ enum Nf { } }; - // RVC: extract a 16-bit instruction. - static inline uint16_t c_extract(uint16_t val, unsigned msb, unsigned lsb) { - assert_cond(msb >= lsb && msb <= 15); - unsigned nbits = msb - lsb + 1; - uint16_t mask = (1U << nbits) - 1; - uint16_t result = val >> lsb; - result &= mask; - return result; - } - - static inline int16_t c_sextract(uint16_t val, unsigned msb, unsigned lsb) { - assert_cond(msb >= lsb && msb <= 15); - int16_t result = val << (15 - msb); - result >>= (15 - msb + lsb); - return result; - } - // RVC: patch a 16-bit instruction. static void c_patch(address a, unsigned msb, unsigned lsb, uint16_t val) { assert_cond(a != NULL); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 7976e474c95..ebdc144c1dd 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1325,7 +1325,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op void LIR_Assembler::align_call(LIR_Code code) { // RVC: With RVC a call may get 2-byte aligned. // the address of jal itself (which will be patched later) should not span the cache line. - // See CallDynamicJavaDirectNode::compute_padding() for more info. + // See CallStaticJavaDirectNode::compute_padding() for more info. __ align(4); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 31a8e15906d..282fddcaddf 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1191,7 +1191,7 @@ int MachCallNativeNode::ret_addr_offset() { } // RVC: With RVC a call may get 2-byte aligned. -// The offset encoding in jal ranges bits [12, 31], which could span the cache line. +// The offset encoding in jal ranges bits [12, 31] could span the cache line. // Patching this unaligned address will make the write operation not atomic. // Other threads may be running the same piece of code at full speed, causing concurrency issues. // So we must ensure that it does not span a cache line so that it can be patched. @@ -1201,11 +1201,7 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const return align_up(current_offset, alignment_required()) - current_offset; } -// RVC: With RVC a call may get 2-byte aligned. -// The offset encoding in jal ranges bits [12, 31], which could span the cache line. -// Patching this unaligned address will make the write operation not atomic. -// Other threads may be running the same piece of code at full speed, causing concurrency issues. -// So we must ensure that it does not span a cache line so that it can be patched. +// RVC: See CallStaticJavaDirectNode::compute_padding() for more info. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { // skip the movptr in MacroAssembler::ic_call(): diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 967f1ab56d8..ce04ae19215 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -101,12 +101,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseMD5Intrinsics, false); } - // compressed instruction extension - if (UseRVC && !(_features & CPU_C)) { - warning("RVC is not supported on this CPU"); - FLAG_SET_DEFAULT(UseRVC, false); - } - if (UseRVV) { if (!(_features & CPU_V)) { warning("RVV is not supported on this CPU"); @@ -122,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); } From 807513de865f3da15705bfcad1c7df5319b1e2c2 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Mon, 10 Jan 2022 11:41:42 +0800 Subject: [PATCH 16/21] Split c_ldsp and c_fldsp --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 32 +++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index b0459605b74..f28e46d40ee 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2386,11 +2386,11 @@ enum Nf { #undef INSN -#define INSN(NAME, funct3, op, REGISTER_TYPE, CHECK) \ - void NAME(REGISTER_TYPE Rd, uint32_t uimm) { \ +#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); \ - IF(CHECK, assert_cond(Rd != x0);) \ + 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); \ @@ -2401,16 +2401,26 @@ enum Nf { emit_int16(insn); \ } -#define IF(BOOL, ...) IF_##BOOL(__VA_ARGS__) -#define IF_true(code) code -#define IF_false(code) + 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_ldsp, 0b011, 0b10, Register, true); - INSN(c_fldsp, 0b001, 0b10, FloatRegister, false); + INSN(c_fldsp, 0b001, 0b10); -#undef IF_false -#undef IF_true -#undef IF #undef INSN #define INSN(NAME, funct3, op, REGISTER_TYPE) \ From 03b947f50b4071c8f291628627fa2911b0f9f6a5 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Mon, 10 Jan 2022 15:12:26 +0800 Subject: [PATCH 17/21] Remove `nmethod_entry_barrier`-related things --- .../riscv/gc/shared/barrierSetAssembler_riscv.cpp | 4 +--- .../riscv/gc/shared/barrierSetNMethod_riscv.cpp | 15 ++------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 8c742993aa2..1fdf3da405d 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -231,8 +231,6 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, __ sd(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); } -extern int nmethod_barrier_guard_offset(); - void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); @@ -242,7 +240,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { // RVC: RISCV's amoswap instructions need an alignment for the memory address it swaps // when we reach here we may get a 2-byte alignment so need to align it - __ align(4, nmethod_barrier_guard_offset()); + __ align(4); Label skip, guard; Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset())); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index 618c486b471..ae7ee4c5a44 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -36,18 +36,11 @@ #include "utilities/debug.hpp" class NativeNMethodBarrier: public NativeInstruction { -public: - enum { - guard_offset = 12 * instruction_size, - barrier_size = guard_offset + 4, // guard_offset + an int32 nmethod guard value - }; - -private: address instruction_address() const { return addr_at(0); } int *guard_addr() { /* auipc + lwu + fence + lwu + beq + lui + addi + slli + addi + slli + jalr + j */ - return reinterpret_cast(instruction_address() + guard_offset); + return reinterpret_cast(instruction_address() + 12 * 4); } public: @@ -62,10 +55,6 @@ class NativeNMethodBarrier: public NativeInstruction { void verify() const; }; -int nmethod_barrier_guard_offset() { - return NativeNMethodBarrier::guard_offset; -} - // Store the instruction bitmask, bits and name for checking the barrier. struct CheckInsn { uint32_t mask; @@ -152,7 +141,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { // see BarrierSetAssembler::nmethod_entry_barrier // auipc + lwu + fence + lwu + beq + movptr_with_offset(5 instructions) + jalr + j + int32 -static const int entry_barrier_offset = - NativeNMethodBarrier::barrier_size; +static const int entry_barrier_offset = -4 * 13; static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset; From 4d1abfc2935fc88ba0a6feb9eeab7b5a80e0f5c9 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Mon, 10 Jan 2022 15:23:59 +0800 Subject: [PATCH 18/21] Polish `nmethod_entry_barrier` and RISC-V CAS related comments --- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 1fdf3da405d..7dc66e05232 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -238,8 +238,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { return; } - // RVC: RISCV's amoswap instructions need an alignment for the memory address it swaps - // when we reach here we may get a 2-byte alignment so need to align it + // RISCV's amoswap instructions need a 4-byte alignment for the 4-byte word it swaps in memory __ align(4); Label skip, guard; @@ -260,7 +259,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { __ bind(guard); - assert(__ offset() % 4 == 0, "RISCV CAS needs an alignment for memory"); + assert(__ offset() % 4 == 0, "RISCV CAS needs a 4-byte alignment for the 4-byte word it swaps in memory"); __ emit_int32(0); // nmethod guard value. Skipped over in common case. __ bind(skip); From e5d89f43dd839f424e7a7de68fa49ca7b732a4c7 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Thu, 13 Jan 2022 17:57:31 +0800 Subject: [PATCH 19/21] Polish comments: remove the 'RVC:' prefix --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 12 ++++++------ src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/register_riscv.hpp | 4 ++-- src/hotspot/cpu/riscv/riscv.ad | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index f28e46d40ee..3b64cc4d599 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2045,7 +2045,7 @@ enum Nf { void set_in_compressible_region(bool b) { _in_compressible_region = b; } public: -// RVC: a compressible region + // a compressible region class CompressibleRegion : public StackObj { protected: Assembler *_masm; @@ -2061,7 +2061,7 @@ enum Nf { } }; - // RVC: patch a 16-bit instruction. + // 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); @@ -2080,22 +2080,22 @@ enum Nf { c_patch(a, bit, bit, val); } - // RVC: patch a 16-bit instruction with a general purpose register ranging [0, 31] (5 bits) + // 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()); } - // RVC: patch a 16-bit instruction with a general purpose register ranging [8, 15] (3 bits) + // 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()); } - // RVC: patch a 16-bit instruction with a float register ranging [0, 31] (5 bits) + // 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()); } - // RVC: patch a 16-bit instruction with a float register ranging [8, 15] (3 bits) + // 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()); } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index ebdc144c1dd..e1b7b2ec3ca 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1323,7 +1323,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } void LIR_Assembler::align_call(LIR_Code code) { - // RVC: With RVC a call may get 2-byte aligned. + // With RVC a call may get 2-byte aligned. // the address of jal itself (which will be patched later) should not span the cache line. // See CallStaticJavaDirectNode::compute_padding() for more info. __ align(4); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 70ef0e62e88..5255abe0762 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2934,7 +2934,7 @@ 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 - // RVC: when we reach here we may get a 2-byte alignment so need to align it + // 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() + diff --git a/src/hotspot/cpu/riscv/register_riscv.hpp b/src/hotspot/cpu/riscv/register_riscv.hpp index 6f75814d1be..771d78f9429 100644 --- a/src/hotspot/cpu/riscv/register_riscv.hpp +++ b/src/hotspot/cpu/riscv/register_riscv.hpp @@ -60,7 +60,7 @@ class RegisterImpl: public AbstractRegisterImpl { number_of_byte_registers = 32, max_slots_per_register = 2, - // RVC: integer registers in the range of [x8~x15] correspond to RVC. Please see Table 16.2 in spec. + // 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, }; @@ -140,7 +140,7 @@ class FloatRegisterImpl: public AbstractRegisterImpl { number_of_registers = 32, max_slots_per_register = 2, - // RVC: float registers in the range of [f8~f15] correspond to RVC. Please see Table 16.2 in spec. + // 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, }; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 282fddcaddf..cd8ea8eef28 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1190,7 +1190,7 @@ int MachCallNativeNode::ret_addr_offset() { return -1; } -// RVC: With RVC a call may get 2-byte aligned. +// With RVC a call may get 2-byte aligned. // The offset encoding in jal ranges bits [12, 31] could span the cache line. // Patching this unaligned address will make the write operation not atomic. // Other threads may be running the same piece of code at full speed, causing concurrency issues. @@ -1201,7 +1201,7 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const return align_up(current_offset, alignment_required()) - current_offset; } -// RVC: See CallStaticJavaDirectNode::compute_padding() for more info. +// Please see CallStaticJavaDirectNode::compute_padding() for more info. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { // skip the movptr in MacroAssembler::ic_call(): @@ -1243,7 +1243,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { C2_MacroAssembler _masm(&cbuf); - Assembler::CompressibleRegion cr(&_masm); // RVC: nops shall be 2-byte under RVC for alignment purposes. + Assembler::CompressibleRegion cr(&_masm); // nops shall be 2-byte under RVC for alignment purposes. for (int i = 0; i < _count; i++) { __ nop(); } From 37899306bf51d2c3560842876d3ff75384d5f8f0 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Sat, 15 Jan 2022 12:03:10 +0800 Subject: [PATCH 20/21] Add an assertion for patchable jals' alignment --- src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index e1b7b2ec3ca..11771638185 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1349,6 +1349,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 pc (patchable jals) must be aligned to maintain atomicity"); address stub = __ start_a_stub(call_stub_size()); if (stub == NULL) { bailout("static call stub overflow"); From 502ff3d8cd95f5dc0304ab6e37c31bbed8f4e225 Mon Sep 17 00:00:00 2001 From: "yunyao.zxl" Date: Mon, 17 Jan 2022 20:22:46 +0800 Subject: [PATCH 21/21] Polish English comments as suggestions --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 6 +++--- src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 7 +++---- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp | 4 ++-- src/hotspot/cpu/riscv/riscv.ad | 9 ++++----- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 3b64cc4d599..4bb9f0a8338 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2027,14 +2027,14 @@ enum Nf { // 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. We introduce 'CompressibleRegion' to hint instructions in this Region's RTTI range -// are qualified to change to their 2-byte versions. +// 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 print RVC instructions instead of +// 4. Using -XX:PrintAssemblyOptions=no-aliases could distinguish RVC instructions from // normal ones. // diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 11771638185..e45deb49191 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1323,9 +1323,8 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } void LIR_Assembler::align_call(LIR_Code code) { - // With RVC a call may get 2-byte aligned. - // the address of jal itself (which will be patched later) should not span the cache line. - // See CallStaticJavaDirectNode::compute_padding() for more info. + // 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); } @@ -1349,7 +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 pc (patchable jals) must be aligned to maintain atomicity"); + 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 7dc66e05232..bd39bfc29a2 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -238,7 +238,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { return; } - // RISCV's amoswap instructions need a 4-byte alignment for the 4-byte word it swaps in memory + // RISCV's amoswap instructions require that the memory address must be naturally aligned. __ align(4); Label skip, guard; @@ -259,7 +259,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { __ bind(guard); - assert(__ offset() % 4 == 0, "RISCV CAS needs a 4-byte alignment for the 4-byte word it swaps in memory"); + 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/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index cd8ea8eef28..0f5e4742e33 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1190,11 +1190,10 @@ int MachCallNativeNode::ret_addr_offset() { return -1; } -// With RVC a call may get 2-byte aligned. -// The offset encoding in jal ranges bits [12, 31] could span the cache line. -// Patching this unaligned address will make the write operation not atomic. -// Other threads may be running the same piece of code at full speed, causing concurrency issues. -// So we must ensure that it does not span a cache line so that it can be patched. +// 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.