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

View file

@ -1852,6 +1852,8 @@ GpVar X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) {
return real_address; return real_address;
} }
uint64_t X64Emitter::reserved_addr_ = 0;
GpVar X64Emitter::ReadMemory( GpVar X64Emitter::ReadMemory(
uint32_t cia, GpVar& addr, uint32_t size, bool acquire) { uint32_t cia, GpVar& addr, uint32_t size, bool acquire) {
X86Compiler& c = compiler_; X86Compiler& c = compiler_;
@ -1859,12 +1861,15 @@ GpVar X64Emitter::ReadMemory(
// Rebase off of memory base pointer. // Rebase off of memory base pointer.
GpVar real_address = TouchMemoryAddress(cia, addr); GpVar real_address = TouchMemoryAddress(cia, addr);
// Acquire semantics -- make reservation for address.
// Note that we overwrite any other reservation.
if (acquire) { if (acquire) {
// TODO(benvanik): acquire semantics. GpVar reservation(c.newGpVar());
// load_value->setAlignment(size); c.mov(reservation, real_address);
// load_value->setVolatile(true); GpVar reserved_addr(c.newGpVar());
// load_value->setAtomic(Acquire); c.mov(reserved_addr, imm((sysint_t)&X64Emitter::reserved_addr_));
XELOGE("Ignoring acquire semantics on read -- TODO"); c.lock();
c.xchg(reservation, qword_ptr(reserved_addr));
} }
GpVar value(c.newGpVar()); GpVar value(c.newGpVar());
@ -1904,6 +1909,31 @@ void X64Emitter::WriteMemory(
// Rebase off of memory base pointer. // Rebase off of memory base pointer.
GpVar real_address = TouchMemoryAddress(cia, addr); 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; GpVar tmp;
switch (size) { switch (size) {
case 1: case 1:
@ -1932,12 +1962,8 @@ void X64Emitter::WriteMemory(
return; return;
} }
// TODO(benvanik): release semantics
if (release) { if (release) {
// store_value->setAlignment(size); c.bind(reservation_mismatch);
// store_value->setVolatile(true);
// store_value->setAtomic(Release);
XELOGE("Ignoring release semantics on write -- TODO");
} }
} }

View file

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