8315856: RISC-V: Use Zacas extension for cmpxchg
Reviewed-by: rehn, fyang
This commit is contained in:
parent
3bc5679cab
commit
6313223bcd
@ -758,6 +758,8 @@ enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11};
|
|||||||
INSN(amomax_d , 0b0101111, 0b011, 0b10100);
|
INSN(amomax_d , 0b0101111, 0b011, 0b10100);
|
||||||
INSN(amominu_d, 0b0101111, 0b011, 0b11000);
|
INSN(amominu_d, 0b0101111, 0b011, 0b11000);
|
||||||
INSN(amomaxu_d, 0b0101111, 0b011, 0b11100);
|
INSN(amomaxu_d, 0b0101111, 0b011, 0b11100);
|
||||||
|
INSN(amocas_w, 0b0101111, 0b010, 0b00101);
|
||||||
|
INSN(amocas_d, 0b0101111, 0b011, 0b00101);
|
||||||
#undef INSN
|
#undef INSN
|
||||||
|
|
||||||
enum operand_size { int8, int16, int32, uint32, int64 };
|
enum operand_size { int8, int16, int32, uint32, int64 };
|
||||||
|
@ -105,6 +105,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
|||||||
product(bool, UseZba, false, "Use Zba instructions") \
|
product(bool, UseZba, false, "Use Zba instructions") \
|
||||||
product(bool, UseZbb, false, "Use Zbb instructions") \
|
product(bool, UseZbb, false, "Use Zbb instructions") \
|
||||||
product(bool, UseZbs, false, "Use Zbs instructions") \
|
product(bool, UseZbs, false, "Use Zbs instructions") \
|
||||||
|
product(bool, UseZacas, false, EXPERIMENTAL, "Use Zacas instructions") \
|
||||||
product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \
|
product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \
|
||||||
product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \
|
product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \
|
||||||
product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \
|
product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \
|
||||||
|
@ -2732,20 +2732,29 @@ void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Reg
|
|||||||
// oldv holds comparison value
|
// oldv holds comparison value
|
||||||
// newv holds value to write in exchange
|
// newv holds value to write in exchange
|
||||||
// addr identifies memory word to compare against/update
|
// addr identifies memory word to compare against/update
|
||||||
Label retry_load, nope;
|
if (UseZacas) {
|
||||||
bind(retry_load);
|
mv(tmp, oldv);
|
||||||
// Load reserved from the memory location
|
atomic_cas(tmp, newv, addr, Assembler::int64, Assembler::aq, Assembler::rl);
|
||||||
load_reserved(tmp, addr, int64, Assembler::aqrl);
|
beq(tmp, oldv, succeed);
|
||||||
// Fail and exit if it is not what we expect
|
} else {
|
||||||
bne(tmp, oldv, nope);
|
Label retry_load, nope;
|
||||||
// If the store conditional succeeds, tmp will be zero
|
bind(retry_load);
|
||||||
store_conditional(tmp, newv, addr, int64, Assembler::rl);
|
// Load reserved from the memory location
|
||||||
beqz(tmp, succeed);
|
load_reserved(tmp, addr, int64, Assembler::aqrl);
|
||||||
// Retry only when the store conditional failed
|
// Fail and exit if it is not what we expect
|
||||||
j(retry_load);
|
bne(tmp, oldv, nope);
|
||||||
|
// If the store conditional succeeds, tmp will be zero
|
||||||
|
store_conditional(tmp, newv, addr, int64, Assembler::rl);
|
||||||
|
beqz(tmp, succeed);
|
||||||
|
// Retry only when the store conditional failed
|
||||||
|
j(retry_load);
|
||||||
|
|
||||||
bind(nope);
|
bind(nope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// neither amocas nor lr/sc have an implied barrier in the failing case
|
||||||
membar(AnyAny);
|
membar(AnyAny);
|
||||||
|
|
||||||
mv(oldv, tmp);
|
mv(oldv, tmp);
|
||||||
if (fail != nullptr) {
|
if (fail != nullptr) {
|
||||||
j(*fail);
|
j(*fail);
|
||||||
@ -2819,7 +2828,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
|
|||||||
}
|
}
|
||||||
sll(mask, mask, shift);
|
sll(mask, mask, shift);
|
||||||
|
|
||||||
xori(not_mask, mask, -1);
|
notr(not_mask, mask);
|
||||||
|
|
||||||
sll(expected, expected, shift);
|
sll(expected, expected, shift);
|
||||||
andr(expected, expected, mask);
|
andr(expected, expected, mask);
|
||||||
@ -2829,7 +2838,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cmpxchg_narrow_value will kill t0, t1, expected, new_val and tmps.
|
// cmpxchg_narrow_value will kill t0, t1, expected, new_val and tmps.
|
||||||
// It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w,
|
// It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w or amocas.w,
|
||||||
// which are forced to work with 4-byte aligned address.
|
// which are forced to work with 4-byte aligned address.
|
||||||
void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
|
void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
|
||||||
Register new_val,
|
Register new_val,
|
||||||
@ -2844,14 +2853,29 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
|
|||||||
Label retry, fail, done;
|
Label retry, fail, done;
|
||||||
|
|
||||||
bind(retry);
|
bind(retry);
|
||||||
lr_w(old, aligned_addr, acquire);
|
|
||||||
andr(tmp, old, mask);
|
|
||||||
bne(tmp, expected, fail);
|
|
||||||
|
|
||||||
andr(tmp, old, not_mask);
|
if (UseZacas) {
|
||||||
orr(tmp, tmp, new_val);
|
lw(old, aligned_addr);
|
||||||
sc_w(tmp, tmp, aligned_addr, release);
|
|
||||||
bnez(tmp, retry);
|
// if old & mask != expected
|
||||||
|
andr(tmp, old, mask);
|
||||||
|
bne(tmp, expected, fail);
|
||||||
|
|
||||||
|
andr(tmp, old, not_mask);
|
||||||
|
orr(tmp, tmp, new_val);
|
||||||
|
|
||||||
|
atomic_cas(old, tmp, aligned_addr, operand_size::int32, acquire, release);
|
||||||
|
bne(tmp, old, retry);
|
||||||
|
} else {
|
||||||
|
lr_w(old, aligned_addr, acquire);
|
||||||
|
andr(tmp, old, mask);
|
||||||
|
bne(tmp, expected, fail);
|
||||||
|
|
||||||
|
andr(tmp, old, not_mask);
|
||||||
|
orr(tmp, tmp, new_val);
|
||||||
|
sc_w(tmp, tmp, aligned_addr, release);
|
||||||
|
bnez(tmp, retry);
|
||||||
|
}
|
||||||
|
|
||||||
if (result_as_bool) {
|
if (result_as_bool) {
|
||||||
mv(result, 1);
|
mv(result, 1);
|
||||||
@ -2891,14 +2915,28 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected,
|
|||||||
|
|
||||||
Label fail, done;
|
Label fail, done;
|
||||||
|
|
||||||
lr_w(old, aligned_addr, acquire);
|
if (UseZacas) {
|
||||||
andr(tmp, old, mask);
|
lw(old, aligned_addr);
|
||||||
bne(tmp, expected, fail);
|
|
||||||
|
|
||||||
andr(tmp, old, not_mask);
|
// if old & mask != expected
|
||||||
orr(tmp, tmp, new_val);
|
andr(tmp, old, mask);
|
||||||
sc_w(tmp, tmp, aligned_addr, release);
|
bne(tmp, expected, fail);
|
||||||
bnez(tmp, fail);
|
|
||||||
|
andr(tmp, old, not_mask);
|
||||||
|
orr(tmp, tmp, new_val);
|
||||||
|
|
||||||
|
atomic_cas(tmp, new_val, addr, operand_size::int32, acquire, release);
|
||||||
|
bne(tmp, old, fail);
|
||||||
|
} else {
|
||||||
|
lr_w(old, aligned_addr, acquire);
|
||||||
|
andr(tmp, old, mask);
|
||||||
|
bne(tmp, expected, fail);
|
||||||
|
|
||||||
|
andr(tmp, old, not_mask);
|
||||||
|
orr(tmp, tmp, new_val);
|
||||||
|
sc_w(tmp, tmp, aligned_addr, release);
|
||||||
|
bnez(tmp, fail);
|
||||||
|
}
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
mv(result, 1);
|
mv(result, 1);
|
||||||
@ -2921,6 +2959,19 @@ void MacroAssembler::cmpxchg(Register addr, Register expected,
|
|||||||
assert_different_registers(expected, t0);
|
assert_different_registers(expected, t0);
|
||||||
assert_different_registers(new_val, t0);
|
assert_different_registers(new_val, t0);
|
||||||
|
|
||||||
|
if (UseZacas) {
|
||||||
|
if (result_as_bool) {
|
||||||
|
mv(t0, expected);
|
||||||
|
atomic_cas(t0, new_val, addr, size, acquire, release);
|
||||||
|
xorr(t0, t0, expected);
|
||||||
|
seqz(result, t0);
|
||||||
|
} else {
|
||||||
|
mv(result, expected);
|
||||||
|
atomic_cas(result, new_val, addr, size, acquire, release);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Label retry_load, done, ne_done;
|
Label retry_load, done, ne_done;
|
||||||
bind(retry_load);
|
bind(retry_load);
|
||||||
load_reserved(t0, addr, size, acquire);
|
load_reserved(t0, addr, size, acquire);
|
||||||
@ -2952,6 +3003,11 @@ void MacroAssembler::cmpxchg_weak(Register addr, Register expected,
|
|||||||
enum operand_size size,
|
enum operand_size size,
|
||||||
Assembler::Aqrl acquire, Assembler::Aqrl release,
|
Assembler::Aqrl acquire, Assembler::Aqrl release,
|
||||||
Register result) {
|
Register result) {
|
||||||
|
if (UseZacas) {
|
||||||
|
cmpxchg(addr, expected, new_val, size, acquire, release, result, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert_different_registers(addr, t0);
|
assert_different_registers(addr, t0);
|
||||||
assert_different_registers(expected, t0);
|
assert_different_registers(expected, t0);
|
||||||
assert_different_registers(new_val, t0);
|
assert_different_registers(new_val, t0);
|
||||||
@ -3018,6 +3074,89 @@ ATOMIC_XCHGU(xchgalwu, xchgalw)
|
|||||||
|
|
||||||
#undef ATOMIC_XCHGU
|
#undef ATOMIC_XCHGU
|
||||||
|
|
||||||
|
#define ATOMIC_CAS(OP, AOP, ACQUIRE, RELEASE) \
|
||||||
|
void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) { \
|
||||||
|
assert(UseZacas, "invariant"); \
|
||||||
|
prev = prev->is_valid() ? prev : zr; \
|
||||||
|
AOP(prev, addr, newv, (Assembler::Aqrl)(ACQUIRE | RELEASE)); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
ATOMIC_CAS(cas, amocas_d, Assembler::relaxed, Assembler::relaxed)
|
||||||
|
ATOMIC_CAS(casw, amocas_w, Assembler::relaxed, Assembler::relaxed)
|
||||||
|
ATOMIC_CAS(casl, amocas_d, Assembler::relaxed, Assembler::rl)
|
||||||
|
ATOMIC_CAS(caslw, amocas_w, Assembler::relaxed, Assembler::rl)
|
||||||
|
ATOMIC_CAS(casal, amocas_d, Assembler::aq, Assembler::rl)
|
||||||
|
ATOMIC_CAS(casalw, amocas_w, Assembler::aq, Assembler::rl)
|
||||||
|
|
||||||
|
#undef ATOMIC_CAS
|
||||||
|
|
||||||
|
#define ATOMIC_CASU(OP1, OP2) \
|
||||||
|
void MacroAssembler::atomic_##OP1(Register prev, Register newv, Register addr) { \
|
||||||
|
atomic_##OP2(prev, newv, addr); \
|
||||||
|
zero_extend(prev, prev, 32); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
ATOMIC_CASU(caswu, casw)
|
||||||
|
ATOMIC_CASU(caslwu, caslw)
|
||||||
|
ATOMIC_CASU(casalwu, casalw)
|
||||||
|
|
||||||
|
#undef ATOMIC_CASU
|
||||||
|
|
||||||
|
void MacroAssembler::atomic_cas(
|
||||||
|
Register prev, Register newv, Register addr, enum operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release) {
|
||||||
|
switch (size) {
|
||||||
|
case int64:
|
||||||
|
switch ((Assembler::Aqrl)(acquire | release)) {
|
||||||
|
case Assembler::relaxed:
|
||||||
|
atomic_cas(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::rl:
|
||||||
|
atomic_casl(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::aqrl:
|
||||||
|
atomic_casal(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case int32:
|
||||||
|
switch ((Assembler::Aqrl)(acquire | release)) {
|
||||||
|
case Assembler::relaxed:
|
||||||
|
atomic_casw(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::rl:
|
||||||
|
atomic_caslw(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::aqrl:
|
||||||
|
atomic_casalw(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case uint32:
|
||||||
|
switch ((Assembler::Aqrl)(acquire | release)) {
|
||||||
|
case Assembler::relaxed:
|
||||||
|
atomic_caswu(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::rl:
|
||||||
|
atomic_caslwu(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
case Assembler::aqrl:
|
||||||
|
atomic_casalwu(prev, newv, addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MacroAssembler::far_jump(const Address &entry, Register tmp) {
|
void MacroAssembler::far_jump(const Address &entry, Register tmp) {
|
||||||
assert(ReservedCodeCacheSize < 4*G, "branch out of range");
|
assert(ReservedCodeCacheSize < 4*G, "branch out of range");
|
||||||
assert(CodeCache::find_blob(entry.target()) != nullptr,
|
assert(CodeCache::find_blob(entry.target()) != nullptr,
|
||||||
|
@ -1063,6 +1063,19 @@ public:
|
|||||||
void atomic_xchgwu(Register prev, Register newv, Register addr);
|
void atomic_xchgwu(Register prev, Register newv, Register addr);
|
||||||
void atomic_xchgalwu(Register prev, Register newv, Register addr);
|
void atomic_xchgalwu(Register prev, Register newv, Register addr);
|
||||||
|
|
||||||
|
void atomic_cas(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_casw(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_casl(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_caslw(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_casal(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_casalw(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_caswu(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_caslwu(Register prev, Register newv, Register addr);
|
||||||
|
void atomic_casalwu(Register prev, Register newv, Register addr);
|
||||||
|
|
||||||
|
void atomic_cas(Register prev, Register newv, Register addr, enum operand_size size,
|
||||||
|
Assembler::Aqrl acquire = Assembler::relaxed, Assembler::Aqrl release = Assembler::relaxed);
|
||||||
|
|
||||||
// Emit a far call/jump. Only invalidates the tmp register which
|
// Emit a far call/jump. Only invalidates the tmp register which
|
||||||
// is used to keep the entry address for jalr.
|
// is used to keep the entry address for jalr.
|
||||||
// The address must be inside the code cache.
|
// The address must be inside the code cache.
|
||||||
|
@ -142,6 +142,7 @@ class VM_Version : public Abstract_VM_Version {
|
|||||||
decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
|
decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
|
||||||
decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
|
decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
|
||||||
decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
|
decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
|
||||||
|
decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
|
||||||
decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||||
decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||||
decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||||
|
Loading…
Reference in New Issue
Block a user