ldarx/lwarx/stdcx/stwcx. Probably.

This commit is contained in:
Ben Vanik 2013-10-18 21:17:20 -07:00
parent f2550bd017
commit 0746e6feb2
3 changed files with 38 additions and 24 deletions

View File

@ -1000,8 +1000,6 @@ XEEMITTER(ldarx, 0x7C0000A8, X )(X64Emitter& e, X86Compiler& c, InstrDat
// RESERVE_ADDR <- real_addr(EA)
// RT <- MEM(EA, 8)
// TODO(benvanik): make this right
GpVar ea(c.newGpVar());
c.mov(ea, e.gpr_value(i.X.RB));
if (i.X.RA) {
@ -1026,8 +1024,6 @@ XEEMITTER(lwarx, 0x7C000028, X )(X64Emitter& e, X86Compiler& c, InstrDat
// RESERVE_ADDR <- real_addr(EA)
// RT <- i32.0 || MEM(EA, 4)
// TODO(benvanik): make this right
GpVar ea(c.newGpVar());
c.mov(ea, e.gpr_value(i.X.RB));
if (i.X.RA) {
@ -1052,8 +1048,6 @@ XEEMITTER(stdcx, 0x7C0001AD, X )(X64Emitter& e, X86Compiler& c, InstrDat
// n <- 1 if store performed
// CR0[LT GT EQ SO] = 0b00 || n || XER[SO]
// TODO(benvanik): make this right
GpVar ea(c.newGpVar());
c.mov(ea, e.gpr_value(i.X.RB));
if (i.X.RA) {
@ -1062,9 +1056,6 @@ XEEMITTER(stdcx, 0x7C0001AD, X )(X64Emitter& e, X86Compiler& c, InstrDat
GpVar v = e.gpr_value(i.X.RT);
e.WriteMemory(i.address, ea, 8, v, /* release */ true);
// We always succeed.
e.update_cr_value(0, e.get_uint64(1 << 2));
return 0;
}
@ -1079,8 +1070,6 @@ XEEMITTER(stwcx, 0x7C00012D, X )(X64Emitter& e, X86Compiler& c, InstrDat
// n <- 1 if store performed
// CR0[LT GT EQ SO] = 0b00 || n || XER[SO]
// TODO(benvanik): make this right
GpVar ea(c.newGpVar());
c.mov(ea, e.gpr_value(i.X.RB));
if (i.X.RA) {
@ -1089,9 +1078,6 @@ XEEMITTER(stwcx, 0x7C00012D, X )(X64Emitter& e, X86Compiler& c, InstrDat
GpVar v = e.gpr_value(i.X.RT);
e.WriteMemory(i.address, ea, 4, v, /* release */ true);
// We always succeed.
e.update_cr_value(0, e.get_uint64(1 << 2));
return 0;
}

View File

@ -1852,6 +1852,8 @@ GpVar X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) {
return real_address;
}
uint64_t X64Emitter::reserved_addr_ = 0;
GpVar X64Emitter::ReadMemory(
uint32_t cia, GpVar& addr, uint32_t size, bool acquire) {
X86Compiler& c = compiler_;
@ -1859,12 +1861,15 @@ GpVar X64Emitter::ReadMemory(
// Rebase off of memory base pointer.
GpVar real_address = TouchMemoryAddress(cia, addr);
// Acquire semantics -- make reservation for address.
// Note that we overwrite any other reservation.
if (acquire) {
// TODO(benvanik): acquire semantics.
// load_value->setAlignment(size);
// load_value->setVolatile(true);
// load_value->setAtomic(Acquire);
XELOGE("Ignoring acquire semantics on read -- TODO");
GpVar reservation(c.newGpVar());
c.mov(reservation, real_address);
GpVar reserved_addr(c.newGpVar());
c.mov(reserved_addr, imm((sysint_t)&X64Emitter::reserved_addr_));
c.lock();
c.xchg(reservation, qword_ptr(reserved_addr));
}
GpVar value(c.newGpVar());
@ -1904,6 +1909,31 @@ void X64Emitter::WriteMemory(
// Rebase off of memory base pointer.
GpVar real_address = TouchMemoryAddress(cia, addr);
// Release semantics - clear reservation.
Label reservation_mismatch(c.newLabel());
if (release) {
// Atomically swap 0 with the reserved_addr_ -- this clears the reservation
// and lets us compare -- if we match, we can write.
GpVar reservation(c.newGpVar());
c.alloc(reservation, rax);
c.xor_(reservation, reservation);
GpVar reserved_addr(c.newGpVar());
c.mov(reserved_addr, imm((sysint_t)&X64Emitter::reserved_addr_));
c.lock();
c.xchg(reservation, qword_ptr(reserved_addr));
// If reservation was not for address, skip write.
GpVar cr(c.newGpVar());
c.xor_(cr, cr);
GpVar cr_set(c.newGpVar());
c.mov(cr_set, imm(1 << 2));
c.cmp(reservation, real_address);
c.unuse(reservation);
c.cmove(cr, cr_set);
update_cr_value(0, cr);
c.test(cr, cr);
c.jz(reservation_mismatch, kCondHintUnlikely);
}
GpVar tmp;
switch (size) {
case 1:
@ -1932,12 +1962,8 @@ void X64Emitter::WriteMemory(
return;
}
// TODO(benvanik): release semantics
if (release) {
// store_value->setAlignment(size);
// store_value->setVolatile(true);
// store_value->setAtomic(Release);
XELOGE("Ignoring release semantics on write -- TODO");
c.bind(reservation_mismatch);
}
}

View File

@ -142,6 +142,8 @@ private:
void* gpu_read_;
void* gpu_write_;
static uint64_t reserved_addr_;
AsmJit::Logger* logger_;
AsmJit::X86Assembler assembler_;
AsmJit::X86Compiler compiler_;