8331418: ZGC: generalize barrier liveness logic

Reviewed-by: mdoerr, aboldtch, fyang, eosterlund
This commit is contained in:
Roberto Castañeda Lozano 2024-05-06 09:26:53 +00:00
parent 15862a2f11
commit 6c7764118e
9 changed files with 75 additions and 52 deletions

@ -476,7 +476,7 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
GrowableArray<RegisterData> registers;
VMReg prev_vm_reg = VMRegImpl::Bad();
RegMaskIterator rmi(stub->live());
RegMaskIterator rmi(stub->preserve_set());
while (rmi.has_next()) {
OptoReg::Name opto_reg = rmi.next();
VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
@ -491,7 +491,7 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
index = registers.append(reg_data);
}
} else if (vm_reg->is_FloatRegister()) {
// We have size encoding in OptoReg of stub->live()
// We have size encoding in OptoReg of stub->preserve_set()
// After encoding, float/neon/sve register has only one slot in regmask
// Decode it to get the actual size
VMReg vm_reg_base = vm_reg->as_FloatRegister()->as_VMReg();
@ -532,12 +532,8 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
}
}
// Remove C-ABI SOE registers, scratch regs and _ref register that will be updated
if (stub->result() != noreg) {
_gp_regs -= RegSet::range(r19, r30) + RegSet::of(r8, r9, stub->result());
} else {
_gp_regs -= RegSet::range(r19, r30) + RegSet::of(r8, r9);
}
// Remove C-ABI SOE registers and scratch regs
_gp_regs -= RegSet::range(r19, r30) + RegSet::of(r8, r9);
// Remove C-ABI SOE fp registers
_fp_regs -= FloatRegSet::range(v8, v15);

@ -282,7 +282,7 @@ OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Na
#define __ _masm->
SaveLiveRegisters::SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub)
: _masm(masm), _reg_mask(stub->live()), _result_reg(stub->result()) {
: _masm(masm), _reg_mask(stub->preserve_set()) {
const int register_save_size = iterate_over_register_mask(ACTION_COUNT_ONLY) * BytesPerWord;
_frame_size = align_up(register_save_size, frame::alignment_in_bytes)
@ -317,11 +317,6 @@ int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int of
if (vm_reg->is_Register()) {
Register std_reg = vm_reg->as_Register();
// '_result_reg' will hold the end result of the operation. Its content must thus not be preserved.
if (std_reg == _result_reg) {
continue;
}
if (std_reg->encoding() >= R2->encoding() && std_reg->encoding() <= R12->encoding()) {
reg_save_index++;

@ -98,7 +98,6 @@ public:
class SaveLiveRegisters {
MacroAssembler* _masm;
RegMask _reg_mask;
Register _result_reg;
int _frame_size;
public:

@ -396,7 +396,7 @@ OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Na
void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
// Record registers that needs to be saved/restored
RegMaskIterator rmi(stub->live());
RegMaskIterator rmi(stub->preserve_set());
while (rmi.has_next()) {
const OptoReg::Name opto_reg = rmi.next();
if (OptoReg::is_reg(opto_reg)) {
@ -414,12 +414,8 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
}
}
// Remove C-ABI SOE registers, tmp regs and _ref register that will be updated
if (stub->result() != noreg) {
_gp_regs -= RegSet::range(x18, x27) + RegSet::of(x2) + RegSet::of(x8, x9) + RegSet::of(x5, stub->result());
} else {
_gp_regs -= RegSet::range(x18, x27) + RegSet::of(x2, x5) + RegSet::of(x8, x9);
}
// Remove C-ABI SOE registers and tmp regs
_gp_regs -= RegSet::range(x18, x27) + RegSet::of(x2, x5) + RegSet::of(x8, x9);
}
SaveLiveRegisters::SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub)

@ -613,19 +613,12 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
caller_saved.Insert(OptoReg::as_OptoReg(r10->as_VMReg()));
caller_saved.Insert(OptoReg::as_OptoReg(r11->as_VMReg()));
if (stub->result() != noreg) {
caller_saved.Remove(OptoReg::as_OptoReg(stub->result()->as_VMReg()));
}
// Create mask of live registers
RegMask live = stub->live();
int gp_spill_size = 0;
int opmask_spill_size = 0;
int xmm_spill_size = 0;
// Record registers that needs to be saved/restored
RegMaskIterator rmi(live);
RegMaskIterator rmi(stub->preserve_set());
while (rmi.has_next()) {
const OptoReg::Name opto_reg = rmi.next();
const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);

@ -87,15 +87,16 @@ static BarrierSetC2State* barrier_set_state() {
return reinterpret_cast<BarrierSetC2State*>(Compile::current()->barrier_set_state());
}
BarrierStubC2::BarrierStubC2(const MachNode* node)
: _node(node),
_entry(),
_continuation() {}
RegMask& BarrierStubC2::live() const {
return *barrier_set_state()->live(_node);
}
BarrierStubC2::BarrierStubC2(const MachNode* node)
: _node(node),
_entry(),
_continuation(),
_preserve(live()) {}
Label* BarrierStubC2::entry() {
// The _entry will never be bound when in_scratch_emit_size() is true.
// However, we still need to return a label that is not bound now, but
@ -108,6 +109,27 @@ Label* BarrierStubC2::continuation() {
return &_continuation;
}
void BarrierStubC2::preserve(Register r) {
const VMReg vm_reg = r->as_VMReg();
assert(vm_reg->is_Register(), "r must be a general-purpose register");
_preserve.Insert(OptoReg::as_OptoReg(vm_reg));
}
void BarrierStubC2::dont_preserve(Register r) {
VMReg vm_reg = r->as_VMReg();
assert(vm_reg->is_Register(), "r must be a general-purpose register");
// Subtract the given register and all its sub-registers (e.g. {R11, R11_H}
// for r11 in aarch64).
do {
_preserve.Remove(OptoReg::as_OptoReg(vm_reg));
vm_reg = vm_reg->next();
} while (vm_reg->is_Register() && !vm_reg->is_concrete());
}
const RegMask& BarrierStubC2::preserve_set() const {
return _preserve;
}
Node* BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {
DecoratorSet decorators = access.decorators();
@ -828,6 +850,7 @@ void BarrierSetC2::compute_liveness_at_stubs() const {
PhaseRegAlloc* const regalloc = C->regalloc();
RegMask* const live = NEW_ARENA_ARRAY(A, RegMask, cfg->number_of_blocks() * sizeof(RegMask));
BarrierSetAssembler* const bs = BarrierSet::barrier_set()->barrier_set_assembler();
BarrierSetC2State* bs_state = barrier_set_state();
Block_List worklist;
for (uint i = 0; i < cfg->number_of_blocks(); ++i) {
@ -850,6 +873,14 @@ void BarrierSetC2::compute_liveness_at_stubs() const {
for (int i = block->number_of_nodes() - 1; i >= 0; --i) {
const Node* const node = block->get_node(i);
// If this node tracks out-liveness, update it
if (!bs_state->needs_livein_data()) {
RegMask* const regs = bs_state->live(node);
if (regs != nullptr) {
regs->OR(new_live);
}
}
// Remove def bits
const OptoReg::Name first = bs->refine_register(node, regalloc->get_reg_first(node));
const OptoReg::Name second = bs->refine_register(node, regalloc->get_reg_second(node));
@ -873,10 +904,12 @@ void BarrierSetC2::compute_liveness_at_stubs() const {
}
}
// If this node tracks liveness, update it
RegMask* const regs = barrier_set_state()->live(node);
if (regs != NULL) {
regs->OR(new_live);
// If this node tracks in-liveness, update it
if (bs_state->needs_livein_data()) {
RegMask* const regs = bs_state->live(node);
if (regs != nullptr) {
regs->OR(new_live);
}
}
}

@ -227,6 +227,7 @@ public:
}
virtual bool needs_liveness_data(const MachNode* mach) const = 0;
virtual bool needs_livein_data() const = 0;
};
// This class represents the slow path in a C2 barrier. It is defined by a
@ -238,14 +239,28 @@ protected:
const MachNode* _node;
Label _entry;
Label _continuation;
RegMask _preserve;
// Registers that are live-in/live-out of the entire memory access
// implementation (possibly including multiple barriers). Whether live-in or
// live-out registers are returned depends on
// BarrierSetC2State::needs_livein_data().
RegMask& live() const;
public:
BarrierStubC2(const MachNode* node);
RegMask& live() const;
// Entry point to the stub.
Label* entry();
// Return point from the stub (typically end of barrier).
Label* continuation();
virtual Register result() const = 0;
// Preserve the value in reg across runtime calls in this barrier.
void preserve(Register reg);
// Do not preserve the value in reg across runtime calls in this barrier.
void dont_preserve(Register reg);
// Set of registers whose value needs to be preserved across runtime calls in this barrier.
const RegMask& preserve_set() const;
};
// This is the top-level class for the backend of the Access API in C2.

@ -142,6 +142,10 @@ public:
return mach->barrier_data() != ZBarrierElided;
}
bool needs_livein_data() const {
return true;
}
void inc_trampoline_stubs_count() {
assert(_trampoline_stubs_count != INT_MAX, "Overflow");
++_trampoline_stubs_count;
@ -200,6 +204,9 @@ ZLoadBarrierStubC2::ZLoadBarrierStubC2(const MachNode* node, Address ref_addr, R
_ref(ref) {
assert_different_registers(ref, ref_addr.base());
assert_different_registers(ref, ref_addr.index());
// The runtime call updates the value of ref, so we should not spill and
// reload its outdated value.
dont_preserve(ref);
}
Address ZLoadBarrierStubC2::ref_addr() const {
@ -210,10 +217,6 @@ Register ZLoadBarrierStubC2::ref() const {
return _ref;
}
Register ZLoadBarrierStubC2::result() const {
return ref();
}
address ZLoadBarrierStubC2::slow_path() const {
const uint8_t barrier_data = _node->barrier_data();
DecoratorSet decorators = DECORATORS_NONE;
@ -272,10 +275,6 @@ bool ZStoreBarrierStubC2::is_atomic() const {
return _is_atomic;
}
Register ZStoreBarrierStubC2::result() const {
return noreg;
}
void ZStoreBarrierStubC2::emit_code(MacroAssembler& masm) {
ZBarrierSet::assembler()->generate_c2_store_barrier_stub(&masm, static_cast<ZStoreBarrierStubC2*>(this));
}

@ -51,7 +51,6 @@ static int stubs_start_offset();
ZBarrierStubC2(const MachNode* node);
public:
virtual Register result() const = 0;
virtual void emit_code(MacroAssembler& masm) = 0;
};
@ -70,7 +69,6 @@ public:
Register ref() const;
address slow_path() const;
virtual Register result() const;
virtual void emit_code(MacroAssembler& masm);
};
@ -94,7 +92,6 @@ public:
bool is_native() const;
bool is_atomic() const;
virtual Register result() const;
virtual void emit_code(MacroAssembler& masm);
};