mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-21 10:57:56 +00:00
8332265: RISC-V: Materialize pointers faster by using a temp register
Reviewed-by: fyang, luhenry, mli
This commit is contained in:
parent
aa4c83a5bf
commit
7b52d0acfc
@ -135,7 +135,7 @@ static jlong as_long(LIR_Opr data) {
|
||||
Address LIR_Assembler::as_Address(LIR_Address* addr, Register tmp) {
|
||||
if (addr->base()->is_illegal()) {
|
||||
assert(addr->index()->is_illegal(), "must be illegal too");
|
||||
__ movptr(tmp, addr->disp());
|
||||
__ movptr(tmp, (address)addr->disp());
|
||||
return Address(tmp, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -42,8 +42,10 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMC
|
||||
return pc_offset + NativeCall::instruction_size;
|
||||
} else if (inst->is_jump()) {
|
||||
return pc_offset + NativeJump::instruction_size;
|
||||
} else if (inst->is_movptr()) {
|
||||
return pc_offset + NativeMovConstReg::movptr_instruction_size;
|
||||
} else if (inst->is_movptr1()) {
|
||||
return pc_offset + NativeMovConstReg::movptr1_instruction_size;
|
||||
} else if (inst->is_movptr2()) {
|
||||
return pc_offset + NativeMovConstReg::movptr2_instruction_size;
|
||||
} else {
|
||||
JVMCI_ERROR_0("unsupported type of instruction for call site");
|
||||
}
|
||||
|
||||
@ -640,7 +640,7 @@ void MacroAssembler::emit_static_call_stub() {
|
||||
|
||||
// Jump to the entry point of the c2i stub.
|
||||
int32_t offset = 0;
|
||||
movptr(t0, 0, offset);
|
||||
movptr(t0, 0, offset, t1); // lui + lui + slli + add
|
||||
jr(t0, offset);
|
||||
}
|
||||
|
||||
@ -1425,15 +1425,34 @@ static int patch_offset_in_pc_relative(address branch, int64_t offset) {
|
||||
return PC_RELATIVE_INSTRUCTION_NUM * NativeInstruction::instruction_size;
|
||||
}
|
||||
|
||||
static int patch_addr_in_movptr(address branch, address target) {
|
||||
const int MOVPTR_INSTRUCTIONS_NUM = 6; // lui + addi + slli + addi + slli + addi/jalr/load
|
||||
static int patch_addr_in_movptr1(address branch, address target) {
|
||||
int32_t lower = ((intptr_t)target << 35) >> 35;
|
||||
int64_t upper = ((intptr_t)target - lower) >> 29;
|
||||
Assembler::patch(branch + 0, 31, 12, upper & 0xfffff); // Lui. target[48:29] + target[28] ==> branch[31:12]
|
||||
Assembler::patch(branch + 4, 31, 20, (lower >> 17) & 0xfff); // Addi. target[28:17] ==> branch[31:20]
|
||||
Assembler::patch(branch + 12, 31, 20, (lower >> 6) & 0x7ff); // Addi. target[16: 6] ==> branch[31:20]
|
||||
Assembler::patch(branch + 20, 31, 20, lower & 0x3f); // Addi/Jalr/Load. target[ 5: 0] ==> branch[31:20]
|
||||
return MOVPTR_INSTRUCTIONS_NUM * NativeInstruction::instruction_size;
|
||||
return NativeMovConstReg::movptr1_instruction_size;
|
||||
}
|
||||
|
||||
static int patch_addr_in_movptr2(address instruction_address, address target) {
|
||||
uintptr_t addr = (uintptr_t)target;
|
||||
|
||||
assert(addr < (1ull << 48), "48-bit overflow in address constant");
|
||||
unsigned int upper18 = (addr >> 30ull);
|
||||
int lower30 = (addr & 0x3fffffffu);
|
||||
int low12 = (lower30 << 20) >> 20;
|
||||
int mid18 = ((lower30 - low12) >> 12);
|
||||
|
||||
Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 0), 31, 12, (upper18 & 0xfffff)); // Lui
|
||||
Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 1), 31, 12, (mid18 & 0xfffff)); // Lui
|
||||
// Slli
|
||||
// Add
|
||||
Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 4), 31, 20, low12 & 0xfff); // Addi/Jalr/Load
|
||||
|
||||
assert(MacroAssembler::target_addr_for_insn(instruction_address) == target, "Must be");
|
||||
|
||||
return NativeMovConstReg::movptr2_instruction_size;
|
||||
}
|
||||
|
||||
static int patch_imm_in_li64(address branch, address target) {
|
||||
@ -1507,7 +1526,7 @@ static long get_offset_of_pc_relative(address insn_addr) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
static address get_target_of_movptr(address insn_addr) {
|
||||
static address get_target_of_movptr1(address insn_addr) {
|
||||
assert_cond(insn_addr != nullptr);
|
||||
intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 29; // Lui.
|
||||
target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 4), 31, 20)) << 17; // Addi.
|
||||
@ -1516,6 +1535,17 @@ static address get_target_of_movptr(address insn_addr) {
|
||||
return (address) target_address;
|
||||
}
|
||||
|
||||
static address get_target_of_movptr2(address insn_addr) {
|
||||
assert_cond(insn_addr != nullptr);
|
||||
int32_t upper18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 0), 31, 12)) & 0xfffff); // Lui
|
||||
int32_t mid18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 1), 31, 12)) & 0xfffff); // Lui
|
||||
// 2 // Slli
|
||||
// 3 // Add
|
||||
int32_t low12 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 4), 31, 20))); // Addi/Jalr/Load.
|
||||
address ret = (address)(((intptr_t)upper18<<30ll) + ((intptr_t)mid18<<12ll) + low12);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static address get_target_of_li64(address insn_addr) {
|
||||
assert_cond(insn_addr != nullptr);
|
||||
intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 44; // Lui.
|
||||
@ -1535,30 +1565,32 @@ address MacroAssembler::get_target_of_li32(address insn_addr) {
|
||||
|
||||
// Patch any kind of instruction; there may be several instructions.
|
||||
// Return the total length (in bytes) of the instructions.
|
||||
int MacroAssembler::pd_patch_instruction_size(address branch, address target) {
|
||||
assert_cond(branch != nullptr);
|
||||
int64_t offset = target - branch;
|
||||
if (NativeInstruction::is_jal_at(branch)) { // jal
|
||||
return patch_offset_in_jal(branch, offset);
|
||||
} else if (NativeInstruction::is_branch_at(branch)) { // beq/bge/bgeu/blt/bltu/bne
|
||||
return patch_offset_in_conditional_branch(branch, offset);
|
||||
} else if (NativeInstruction::is_pc_relative_at(branch)) { // auipc, addi/jalr/load
|
||||
return patch_offset_in_pc_relative(branch, offset);
|
||||
} else if (NativeInstruction::is_movptr_at(branch)) { // movptr
|
||||
return patch_addr_in_movptr(branch, target);
|
||||
} else if (NativeInstruction::is_li64_at(branch)) { // li64
|
||||
return patch_imm_in_li64(branch, target);
|
||||
} else if (NativeInstruction::is_li32_at(branch)) { // li32
|
||||
int MacroAssembler::pd_patch_instruction_size(address instruction_address, address target) {
|
||||
assert_cond(instruction_address != nullptr);
|
||||
int64_t offset = target - instruction_address;
|
||||
if (NativeInstruction::is_jal_at(instruction_address)) { // jal
|
||||
return patch_offset_in_jal(instruction_address, offset);
|
||||
} else if (NativeInstruction::is_branch_at(instruction_address)) { // beq/bge/bgeu/blt/bltu/bne
|
||||
return patch_offset_in_conditional_branch(instruction_address, offset);
|
||||
} else if (NativeInstruction::is_pc_relative_at(instruction_address)) { // auipc, addi/jalr/load
|
||||
return patch_offset_in_pc_relative(instruction_address, offset);
|
||||
} else if (NativeInstruction::is_movptr1_at(instruction_address)) { // movptr1
|
||||
return patch_addr_in_movptr1(instruction_address, target);
|
||||
} else if (NativeInstruction::is_movptr2_at(instruction_address)) { // movptr2
|
||||
return patch_addr_in_movptr2(instruction_address, target);
|
||||
} else if (NativeInstruction::is_li64_at(instruction_address)) { // li64
|
||||
return patch_imm_in_li64(instruction_address, target);
|
||||
} else if (NativeInstruction::is_li32_at(instruction_address)) { // li32
|
||||
int64_t imm = (intptr_t)target;
|
||||
return patch_imm_in_li32(branch, (int32_t)imm);
|
||||
} else if (NativeInstruction::is_li16u_at(branch)) {
|
||||
return patch_imm_in_li32(instruction_address, (int32_t)imm);
|
||||
} else if (NativeInstruction::is_li16u_at(instruction_address)) {
|
||||
int64_t imm = (intptr_t)target;
|
||||
return patch_imm_in_li16u(branch, (uint16_t)imm);
|
||||
return patch_imm_in_li16u(instruction_address, (uint16_t)imm);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
tty->print_cr("pd_patch_instruction_size: instruction 0x%x at " INTPTR_FORMAT " could not be patched!\n",
|
||||
Assembler::ld_instr(branch), p2i(branch));
|
||||
Disassembler::decode(branch - 16, branch + 16);
|
||||
Assembler::ld_instr(instruction_address), p2i(instruction_address));
|
||||
Disassembler::decode(instruction_address - 16, instruction_address + 16);
|
||||
#endif
|
||||
ShouldNotReachHere();
|
||||
return -1;
|
||||
@ -1574,8 +1606,10 @@ address MacroAssembler::target_addr_for_insn(address insn_addr) {
|
||||
offset = get_offset_of_conditional_branch(insn_addr);
|
||||
} else if (NativeInstruction::is_pc_relative_at(insn_addr)) { // auipc, addi/jalr/load
|
||||
offset = get_offset_of_pc_relative(insn_addr);
|
||||
} else if (NativeInstruction::is_movptr_at(insn_addr)) { // movptr
|
||||
return get_target_of_movptr(insn_addr);
|
||||
} else if (NativeInstruction::is_movptr1_at(insn_addr)) { // movptr1
|
||||
return get_target_of_movptr1(insn_addr);
|
||||
} else if (NativeInstruction::is_movptr2_at(insn_addr)) { // movptr2
|
||||
return get_target_of_movptr2(insn_addr);
|
||||
} else if (NativeInstruction::is_li64_at(insn_addr)) { // li64
|
||||
return get_target_of_li64(insn_addr);
|
||||
} else if (NativeInstruction::is_li32_at(insn_addr)) { // li32
|
||||
@ -1594,9 +1628,12 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
|
||||
// Move narrow OOP
|
||||
uint32_t n = CompressedOops::narrow_oop_value(cast_to_oop(o));
|
||||
return patch_imm_in_li32(insn_addr, (int32_t)n);
|
||||
} else if (NativeInstruction::is_movptr_at(insn_addr)) {
|
||||
} else if (NativeInstruction::is_movptr1_at(insn_addr)) {
|
||||
// Move wide OOP
|
||||
return patch_addr_in_movptr(insn_addr, o);
|
||||
return patch_addr_in_movptr1(insn_addr, o);
|
||||
} else if (NativeInstruction::is_movptr2_at(insn_addr)) {
|
||||
// Move wide OOP
|
||||
return patch_addr_in_movptr2(insn_addr, o);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return -1;
|
||||
@ -1617,16 +1654,31 @@ void MacroAssembler::reinit_heapbase() {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset) {
|
||||
int64_t imm64 = (int64_t)addr;
|
||||
void MacroAssembler::movptr(Register Rd, address addr, Register temp) {
|
||||
int offset = 0;
|
||||
movptr(Rd, addr, offset, temp);
|
||||
addi(Rd, Rd, offset);
|
||||
}
|
||||
|
||||
void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset, Register temp) {
|
||||
uint64_t uimm64 = (uint64_t)addr;
|
||||
#ifndef PRODUCT
|
||||
{
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "0x%" PRIx64, imm64);
|
||||
snprintf(buffer, sizeof(buffer), "0x%" PRIx64, uimm64);
|
||||
block_comment(buffer);
|
||||
}
|
||||
#endif
|
||||
assert((uintptr_t)imm64 < (1ull << 48), "48-bit overflow in address constant");
|
||||
assert(uimm64 < (1ull << 48), "48-bit overflow in address constant");
|
||||
|
||||
if (temp == noreg) {
|
||||
movptr1(Rd, uimm64, offset);
|
||||
} else {
|
||||
movptr2(Rd, uimm64, offset, temp);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::movptr1(Register Rd, uint64_t imm64, int32_t &offset) {
|
||||
// Load upper 31 bits
|
||||
int64_t imm = imm64 >> 17;
|
||||
int64_t upper = imm, lower = imm;
|
||||
@ -1645,6 +1697,23 @@ void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset) {
|
||||
offset = imm64 & 0x3f;
|
||||
}
|
||||
|
||||
void MacroAssembler::movptr2(Register Rd, uint64_t addr, int32_t &offset, Register tmp) {
|
||||
assert_different_registers(Rd, tmp, noreg);
|
||||
|
||||
uint32_t upper18 = (addr >> 30ull);
|
||||
int32_t lower30 = (addr & 0x3fffffffu);
|
||||
int32_t low12 = (lower30 << 20) >> 20;
|
||||
int32_t mid18 = ((lower30 - low12) >> 12);
|
||||
|
||||
lui(tmp, upper18 << 12);
|
||||
lui(Rd, mid18 << 12);
|
||||
|
||||
slli(tmp, tmp, 18);
|
||||
add(Rd, Rd, tmp);
|
||||
|
||||
offset = low12;
|
||||
}
|
||||
|
||||
void MacroAssembler::add(Register Rd, Register Rn, int64_t increment, Register temp) {
|
||||
if (is_simm12(increment)) {
|
||||
addi(Rd, Rn, increment);
|
||||
@ -2120,6 +2189,7 @@ void MacroAssembler::movoop(Register dst, jobject obj) {
|
||||
|
||||
// Move a metadata address into a register.
|
||||
void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
|
||||
assert((uintptr_t)obj < (1ull << 48), "48-bit overflow in metadata");
|
||||
int oop_index;
|
||||
if (obj == nullptr) {
|
||||
oop_index = oop_recorder()->allocate_metadata_index(obj);
|
||||
@ -3554,7 +3624,7 @@ address MacroAssembler::trampoline_call(Address entry) {
|
||||
address MacroAssembler::ic_call(address entry, jint method_index) {
|
||||
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
|
||||
IncompressibleRegion ir(this); // relocations
|
||||
movptr(t1, (address)Universe::non_oop_word());
|
||||
movptr(t1, (address)Universe::non_oop_word(), t0);
|
||||
assert_cond(entry != nullptr);
|
||||
return trampoline_call(Address(entry, rh));
|
||||
}
|
||||
@ -3661,8 +3731,8 @@ int MacroAssembler::max_trampoline_stub_size() {
|
||||
}
|
||||
|
||||
int MacroAssembler::static_call_stub_size() {
|
||||
// (lui, addi, slli, addi, slli, addi) + (lui, addi, slli, addi, slli) + jalr
|
||||
return 12 * NativeInstruction::instruction_size;
|
||||
// (lui, addi, slli, addi, slli, addi) + (lui + lui + slli + add) + jalr
|
||||
return 11 * NativeInstruction::instruction_size;
|
||||
}
|
||||
|
||||
Address MacroAssembler::add_memory_helper(const Address dst, Register tmp) {
|
||||
|
||||
@ -804,17 +804,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void movptr(Register Rd, address addr, int32_t &offset);
|
||||
|
||||
void movptr(Register Rd, address addr) {
|
||||
int offset = 0;
|
||||
movptr(Rd, addr, offset);
|
||||
addi(Rd, Rd, offset);
|
||||
}
|
||||
|
||||
inline void movptr(Register Rd, uintptr_t imm64) {
|
||||
movptr(Rd, (address)imm64);
|
||||
}
|
||||
// Generates a load of a 48-bit constant which can be
|
||||
// patched to any 48-bit constant, i.e. address.
|
||||
// If common case supply additional temp register
|
||||
// to shorten the instruction sequence.
|
||||
void movptr(Register Rd, address addr, Register tmp = noreg);
|
||||
void movptr(Register Rd, address addr, int32_t &offset, Register tmp = noreg);
|
||||
private:
|
||||
void movptr1(Register Rd, uintptr_t addr, int32_t &offset);
|
||||
void movptr2(Register Rd, uintptr_t addr, int32_t &offset, Register tmp);
|
||||
public:
|
||||
|
||||
// arith
|
||||
void add (Register Rd, Register Rn, int64_t increment, Register temp = t0);
|
||||
|
||||
@ -84,7 +84,7 @@ bool NativeInstruction::is_load_pc_relative_at(address instr) {
|
||||
check_load_pc_relative_data_dependency(instr);
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_movptr_at(address instr) {
|
||||
bool NativeInstruction::is_movptr1_at(address instr) {
|
||||
return is_lui_at(instr) && // Lui
|
||||
is_addi_at(instr + instruction_size) && // Addi
|
||||
is_slli_shift_at(instr + instruction_size * 2, 11) && // Slli Rd, Rs, 11
|
||||
@ -93,7 +93,18 @@ bool NativeInstruction::is_movptr_at(address instr) {
|
||||
(is_addi_at(instr + instruction_size * 5) ||
|
||||
is_jalr_at(instr + instruction_size * 5) ||
|
||||
is_load_at(instr + instruction_size * 5)) && // Addi/Jalr/Load
|
||||
check_movptr_data_dependency(instr);
|
||||
check_movptr1_data_dependency(instr);
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_movptr2_at(address instr) {
|
||||
return is_lui_at(instr) && // lui
|
||||
is_lui_at(instr + instruction_size) && // lui
|
||||
is_slli_shift_at(instr + instruction_size * 2, 18) && // slli Rd, Rs, 18
|
||||
is_add_at(instr + instruction_size * 3) &&
|
||||
(is_addi_at(instr + instruction_size * 4) ||
|
||||
is_jalr_at(instr + instruction_size * 4) ||
|
||||
is_load_at(instr + instruction_size * 4)) && // Addi/Jalr/Load
|
||||
check_movptr2_data_dependency(instr);
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_li16u_at(address instr) {
|
||||
@ -201,10 +212,11 @@ void NativeCall::insert(address code_pos, address entry) { Unimplemented(); }
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void NativeMovConstReg::verify() {
|
||||
if (!(nativeInstruction_at(instruction_address())->is_movptr() ||
|
||||
is_auipc_at(instruction_address()))) {
|
||||
fatal("should be MOVPTR or AUIPC");
|
||||
NativeInstruction* ni = nativeInstruction_at(instruction_address());
|
||||
if (ni->is_movptr() || ni->is_auipc()) {
|
||||
return;
|
||||
}
|
||||
fatal("should be MOVPTR or AUIPC");
|
||||
}
|
||||
|
||||
intptr_t NativeMovConstReg::data() const {
|
||||
@ -223,7 +235,7 @@ void NativeMovConstReg::set_data(intptr_t x) {
|
||||
} else {
|
||||
// Store x into the instruction stream.
|
||||
MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)x);
|
||||
ICache::invalidate_range(instruction_address(), movptr_instruction_size);
|
||||
ICache::invalidate_range(instruction_address(), movptr1_instruction_size /* > movptr2_instruction_size */ );
|
||||
}
|
||||
|
||||
// Find and replace the oop/metadata corresponding to this
|
||||
@ -393,13 +405,15 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add
|
||||
ICache::invalidate_range(verified_entry, instruction_size);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
|
||||
CodeBuffer cb(code_pos, instruction_size);
|
||||
MacroAssembler a(&cb);
|
||||
Assembler::IncompressibleRegion ir(&a); // Fixed length: see NativeGeneralJump::get_instruction_size()
|
||||
|
||||
int32_t offset = 0;
|
||||
a.movptr(t0, entry, offset); // lui, addi, slli, addi, slli
|
||||
a.movptr(t0, entry, offset, t1); // lui, lui, slli, add
|
||||
a.jr(t0, offset); // jalr
|
||||
|
||||
ICache::invalidate_range(code_pos, instruction_size);
|
||||
@ -410,6 +424,8 @@ void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer)
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
address NativeCallTrampolineStub::destination(nmethod *nm) const {
|
||||
return ptr_at(data_offset);
|
||||
}
|
||||
|
||||
@ -64,7 +64,11 @@ class NativeInstruction {
|
||||
}
|
||||
|
||||
bool is_jal() const { return is_jal_at(addr_at(0)); }
|
||||
bool is_movptr() const { return is_movptr_at(addr_at(0)); }
|
||||
bool is_movptr() const { return is_movptr1_at(addr_at(0)) ||
|
||||
is_movptr2_at(addr_at(0)); }
|
||||
bool is_movptr1() const { return is_movptr1_at(addr_at(0)); }
|
||||
bool is_movptr2() const { return is_movptr2_at(addr_at(0)); }
|
||||
bool is_auipc() const { return is_auipc_at(addr_at(0)); }
|
||||
bool is_call() const { return is_call_at(addr_at(0)); }
|
||||
bool is_jump() const { return is_jump_at(addr_at(0)); }
|
||||
|
||||
@ -76,9 +80,10 @@ class NativeInstruction {
|
||||
static bool is_float_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000111; }
|
||||
static bool is_auipc_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010111; }
|
||||
static bool is_jump_at(address instr) { assert_cond(instr != nullptr); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); }
|
||||
static bool is_add_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110011 && extract_funct3(instr) == 0b000; }
|
||||
static bool is_addi_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; }
|
||||
static bool is_addiw_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; }
|
||||
static bool is_addiw_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; }
|
||||
static bool is_addiw_to_zr_at(address instr){ assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; }
|
||||
static bool is_lui_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110111; }
|
||||
static bool is_lui_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_lui_at(instr) && extract_rd(instr) == zr; }
|
||||
|
||||
@ -109,7 +114,7 @@ class NativeInstruction {
|
||||
// addi
|
||||
// slli
|
||||
// addi/jalr/load
|
||||
static bool check_movptr_data_dependency(address instr) {
|
||||
static bool check_movptr1_data_dependency(address instr) {
|
||||
address lui = instr;
|
||||
address addi1 = lui + instruction_size;
|
||||
address slli1 = addi1 + instruction_size;
|
||||
@ -127,6 +132,26 @@ class NativeInstruction {
|
||||
extract_rs1(last_instr) == extract_rd(slli2);
|
||||
}
|
||||
|
||||
// the instruction sequence of movptr2 is as below:
|
||||
// lui
|
||||
// lui
|
||||
// slli
|
||||
// add
|
||||
// addi/jalr/load
|
||||
static bool check_movptr2_data_dependency(address instr) {
|
||||
address lui1 = instr;
|
||||
address lui2 = lui1 + instruction_size;
|
||||
address slli = lui2 + instruction_size;
|
||||
address add = slli + instruction_size;
|
||||
address last_instr = add + instruction_size;
|
||||
return extract_rd(add) == extract_rd(lui2) &&
|
||||
extract_rs1(add) == extract_rd(lui2) &&
|
||||
extract_rs2(add) == extract_rd(slli) &&
|
||||
extract_rs1(slli) == extract_rd(lui1) &&
|
||||
extract_rd(slli) == extract_rd(lui1) &&
|
||||
extract_rs1(last_instr) == extract_rd(add);
|
||||
}
|
||||
|
||||
// the instruction sequence of li64 is as below:
|
||||
// lui
|
||||
// addi
|
||||
@ -204,7 +229,8 @@ class NativeInstruction {
|
||||
extract_rs1(load) == extract_rd(load);
|
||||
}
|
||||
|
||||
static bool is_movptr_at(address instr);
|
||||
static bool is_movptr1_at(address instr);
|
||||
static bool is_movptr2_at(address instr);
|
||||
static bool is_li16u_at(address instr);
|
||||
static bool is_li32_at(address instr);
|
||||
static bool is_li64_at(address instr);
|
||||
@ -351,26 +377,33 @@ inline NativeCall* nativeCall_before(address return_address) {
|
||||
class NativeMovConstReg: public NativeInstruction {
|
||||
public:
|
||||
enum RISCV_specific_constants {
|
||||
movptr_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr().
|
||||
load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size, // auipc, ld
|
||||
instruction_offset = 0,
|
||||
displacement_offset = 0
|
||||
movptr1_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr1().
|
||||
movptr2_instruction_size = 5 * NativeInstruction::instruction_size, // lui, lui, slli, add, addi. See movptr2().
|
||||
load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size // auipc, ld
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address instruction_address() const { return addr_at(0); }
|
||||
address next_instruction_address() const {
|
||||
// if the instruction at 5 * instruction_size is addi,
|
||||
// it means a lui + addi + slli + addi + slli + addi instruction sequence,
|
||||
// and the next instruction address should be addr_at(6 * instruction_size).
|
||||
// However, when the instruction at 5 * instruction_size isn't addi,
|
||||
// the next instruction address should be addr_at(5 * instruction_size)
|
||||
if (nativeInstruction_at(instruction_address())->is_movptr()) {
|
||||
if (is_addi_at(addr_at(movptr_instruction_size - NativeInstruction::instruction_size))) {
|
||||
if (is_movptr1_at(instruction_address())) {
|
||||
if (is_addi_at(addr_at(movptr1_instruction_size - NativeInstruction::instruction_size))) {
|
||||
// Assume: lui, addi, slli, addi, slli, addi
|
||||
return addr_at(movptr_instruction_size);
|
||||
return addr_at(movptr1_instruction_size);
|
||||
} else {
|
||||
// Assume: lui, addi, slli, addi, slli
|
||||
return addr_at(movptr_instruction_size - NativeInstruction::instruction_size);
|
||||
return addr_at(movptr1_instruction_size - NativeInstruction::instruction_size);
|
||||
}
|
||||
} else if (is_movptr2_at(instruction_address())) {
|
||||
if (is_addi_at(addr_at(movptr2_instruction_size - NativeInstruction::instruction_size))) {
|
||||
// Assume: lui, lui, slli, add, addi
|
||||
return addr_at(movptr2_instruction_size);
|
||||
} else {
|
||||
// Assume: lui, lui, slli, add
|
||||
return addr_at(movptr2_instruction_size - NativeInstruction::instruction_size);
|
||||
}
|
||||
} else if (is_load_pc_relative_at(instruction_address())) {
|
||||
// Assume: auipc, ld
|
||||
@ -383,12 +416,6 @@ class NativeMovConstReg: public NativeInstruction {
|
||||
intptr_t data() const;
|
||||
void set_data(intptr_t x);
|
||||
|
||||
void flush() {
|
||||
if (!maybe_cpool_ref(instruction_address())) {
|
||||
ICache::invalidate_range(instruction_address(), movptr_instruction_size);
|
||||
}
|
||||
}
|
||||
|
||||
void verify();
|
||||
void print();
|
||||
|
||||
@ -399,14 +426,14 @@ class NativeMovConstReg: public NativeInstruction {
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_at(address addr) {
|
||||
assert_cond(addr != nullptr);
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_offset);
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(addr);
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_before(address addr) {
|
||||
assert_cond(addr != nullptr);
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size);
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
@ -484,10 +511,7 @@ inline NativeJump* nativeJump_at(address addr) {
|
||||
class NativeGeneralJump: public NativeJump {
|
||||
public:
|
||||
enum RISCV_specific_constants {
|
||||
instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, jalr
|
||||
instruction_offset = 0,
|
||||
data_offset = 0,
|
||||
next_instruction_offset = 6 * NativeInstruction::instruction_size // lui, addi, slli, addi, slli, jalr
|
||||
instruction_size = 5 * NativeInstruction::instruction_size, // lui, lui, slli, add, jalr
|
||||
};
|
||||
|
||||
address jump_destination() const;
|
||||
|
||||
@ -1244,7 +1244,7 @@ int MachCallStaticJavaNode::ret_addr_offset()
|
||||
|
||||
int MachCallDynamicJavaNode::ret_addr_offset()
|
||||
{
|
||||
return 7 * NativeInstruction::instruction_size; // movptr, jal
|
||||
return NativeMovConstReg::movptr2_instruction_size + NativeInstruction::instruction_size; // movptr2, jal
|
||||
}
|
||||
|
||||
int MachCallRuntimeNode::ret_addr_offset() {
|
||||
@ -1285,12 +1285,11 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const
|
||||
// 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 RVC,
|
||||
// skip the movptr2 in MacroAssembler::ic_call():
|
||||
// lui, lui, slli, add, addi
|
||||
// Though movptr2() 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;
|
||||
current_offset += NativeMovConstReg::movptr2_instruction_size;
|
||||
// to make sure the address of jal 4-byte aligned.
|
||||
return align_up(current_offset, alignment_required()) - current_offset;
|
||||
}
|
||||
@ -10014,7 +10013,7 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr)
|
||||
|
||||
effect(USE meth, KILL cr);
|
||||
|
||||
ins_cost(BRANCH_COST + ALU_COST * 6);
|
||||
ins_cost(BRANCH_COST + ALU_COST * 5);
|
||||
|
||||
format %{ "CALL,dynamic $meth\t#@CallDynamicJavaDirect" %}
|
||||
|
||||
|
||||
@ -223,7 +223,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
|
||||
|
||||
__ block_comment("{ on_entry");
|
||||
__ la(c_rarg0, Address(sp, frame_data_offset));
|
||||
__ movptr(c_rarg1, (intptr_t) receiver);
|
||||
__ movptr(c_rarg1, (address) receiver);
|
||||
__ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry));
|
||||
__ mv(xthread, x10);
|
||||
__ reinit_heapbase();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user