8349727: [PPC] C1: Improve Class.isInstance intrinsic

Reviewed-by: rrich, varadam
This commit is contained in:
Martin Doerr 2025-02-20 12:03:08 +00:00
parent 1e87ff0199
commit 735805d925
4 changed files with 95 additions and 23 deletions

View File

@ -2839,25 +2839,28 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
void LIR_Assembler::rt_call(LIR_Opr result, address dest,
const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
// Stubs: Called via rt_call, but dest is a stub address (no function descriptor).
// Stubs: Called via rt_call, but dest is a stub address (no FunctionDescriptor).
if (dest == Runtime1::entry_for(C1StubId::register_finalizer_id) ||
dest == Runtime1::entry_for(C1StubId::new_multi_array_id )) {
dest == Runtime1::entry_for(C1StubId::new_multi_array_id ) ||
dest == Runtime1::entry_for(C1StubId::is_instance_of_id )) {
assert(CodeCache::contains(dest), "simplified call is only for special C1 stubs");
//__ load_const_optimized(R0, dest);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest));
__ mtctr(R0);
__ bctrl();
assert(info != nullptr, "sanity");
add_call_info_here(info);
__ post_call_nop();
if (info != nullptr) {
add_call_info_here(info);
__ post_call_nop();
}
return;
}
__ call_c(dest, relocInfo::runtime_call_type);
assert(__ last_calls_return_pc() == __ pc(), "pcn not at return pc");
if (info != nullptr) {
add_call_info_here(info);
__ post_call_nop();
}
assert(__ last_calls_return_pc() == __ pc(), "pcn not at return pc");
__ post_call_nop();
}

View File

@ -1128,9 +1128,10 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of);
return Runtime1::entry_for(C1StubId::is_instance_of_id);
}

View File

@ -609,6 +609,73 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
}
break;
case C1StubId::is_instance_of_id:
{
// Called like a C function, but without FunctionDescriptor (see LIR_Assembler::rt_call).
// Arguments and return value.
Register mirror = R3_ARG1;
Register obj = R4_ARG2;
Register result = R3_RET;
// Other argument registers can be used as temp registers.
Register klass = R5;
Register offset = R6;
Register sub_klass = R7;
Label is_secondary, success;
// Get the Klass*.
__ ld(klass, java_lang_Class::klass_offset(), mirror);
// Return false if obj or klass is null.
mirror = noreg; // killed by next instruction
__ li(result, 0); // assume result is false
__ cmpdi(CR0, obj, 0);
__ cmpdi(CR1, klass, 0);
__ cror(CR0, Assembler::equal, CR1, Assembler::equal);
__ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CR0, Assembler::equal), Assembler::bhintbhBCLRisReturn);
__ lwz(offset, in_bytes(Klass::super_check_offset_offset()), klass);
__ load_klass(sub_klass, obj);
__ cmpwi(CR0, offset, in_bytes(Klass::secondary_super_cache_offset()));
__ beq(CR0, is_secondary); // Klass is a secondary superclass
// Klass is a concrete class
__ ldx(R0, sub_klass, offset);
__ cmpd(CR0, klass, R0);
if (VM_Version::has_brw()) {
// Power10 can set the result by one instruction. No need for a branch.
__ setbc(result, CR0, Assembler::equal);
} else {
__ beq(CR0, success);
}
__ blr();
__ bind(is_secondary);
// This is necessary because I am never in my own secondary_super list.
__ cmpd(CR0, sub_klass, klass);
__ beq(CR0, success);
__ lookup_secondary_supers_table_var(sub_klass, klass,
/*temps*/R9, R10, R11, R12,
/*result*/R8);
__ cmpdi(CR0, R8, 0); // 0 means is subclass
if (VM_Version::has_brw()) {
// Power10 can set the result by one instruction. No need for a branch.
__ setbc(result, CR0, Assembler::equal);
} else {
__ beq(CR0, success);
}
__ blr();
__ bind(success);
__ li(result, 1);
__ blr();
}
break;
case C1StubId::monitorenter_nofpu_id:
case C1StubId::monitorenter_id:
{

View File

@ -2265,27 +2265,28 @@ void MacroAssembler::check_klass_subtype(Register sub_klass,
// generic (count must be >0)
// iff found: CR0 eq, scratch == 0
void MacroAssembler::repne_scan(Register addr, Register value, Register count, Register scratch) {
Label Lloop, Lexit;
Label Lloop, Lafter_loop, Lexit;
#ifdef ASSERT
{
Label ok;
cmpdi(CR0, count, 0);
bgt(CR0, ok);
stop("count must be positive");
bind(ok);
}
#endif
srdi_(scratch, count, 1);
beq(CR0, Lafter_loop);
mtctr(scratch);
mtctr(count);
bind(Lloop);
ld(scratch, 0 , addr);
bind(Lloop); // 2x unrolled
ld(scratch, 0, addr);
xor_(scratch, scratch, value);
beq(CR0, Lexit);
addi(addr, addr, wordSize);
ld(scratch, 8, addr);
xor_(scratch, scratch, value);
beq(CR0, Lexit);
addi(addr, addr, 2 * wordSize);
bdnz(Lloop);
bind(Lafter_loop);
andi_(scratch, count, 1);
beq(CR0, Lexit); // if taken: CR0 eq and scratch == 0
ld(scratch, 0, addr);
xor_(scratch, scratch, value);
bind(Lexit);
}