Most of the memory instructions.
Not sure this is correct, as it crashes pretty early on.
This commit is contained in:
parent
e724fe3e60
commit
e6320dada5
|
@ -642,7 +642,7 @@ XEEMITTER(andisx, 0x74000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
|
|
||||||
GpVar v(c.newGpVar());
|
GpVar v(c.newGpVar());
|
||||||
c.mov(v, e.gpr_value(i.D.RT));
|
c.mov(v, e.gpr_value(i.D.RT));
|
||||||
c.and_(v, imm(((uint64_t)i.D.DS) << 16));
|
c.and_(v, imm(i.D.DS << 16));
|
||||||
e.update_gpr_value(i.D.RA, v);
|
e.update_gpr_value(i.D.RA, v);
|
||||||
|
|
||||||
// With cr0 update.
|
// With cr0 update.
|
||||||
|
@ -764,7 +764,7 @@ XEEMITTER(ori, 0x60000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
|
|
||||||
GpVar v(c.newGpVar());
|
GpVar v(c.newGpVar());
|
||||||
c.mov(v, e.gpr_value(i.D.RT));
|
c.mov(v, e.gpr_value(i.D.RT));
|
||||||
c.or_(v, imm((uint64_t)i.D.DS));
|
c.or_(v, imm(i.D.DS));
|
||||||
e.update_gpr_value(i.D.RA, v);
|
e.update_gpr_value(i.D.RA, v);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -775,7 +775,7 @@ XEEMITTER(oris, 0x64000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
|
|
||||||
GpVar v(c.newGpVar());
|
GpVar v(c.newGpVar());
|
||||||
c.mov(v, e.gpr_value(i.D.RT));
|
c.mov(v, e.gpr_value(i.D.RT));
|
||||||
c.or_(v, imm(((uint64_t)i.D.DS) << 16));
|
c.or_(v, imm(i.D.DS << 16));
|
||||||
e.update_gpr_value(i.D.RA, v);
|
e.update_gpr_value(i.D.RA, v);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -802,7 +802,7 @@ XEEMITTER(xori, 0x68000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
|
|
||||||
GpVar v(c.newGpVar());
|
GpVar v(c.newGpVar());
|
||||||
c.mov(v, e.gpr_value(i.D.RT));
|
c.mov(v, e.gpr_value(i.D.RT));
|
||||||
c.xor_(v, imm((uint64_t)i.D.DS));
|
c.xor_(v, imm(i.D.DS));
|
||||||
e.update_gpr_value(i.D.RA, v);
|
e.update_gpr_value(i.D.RA, v);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -813,7 +813,7 @@ XEEMITTER(xoris, 0x6C000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
|
|
||||||
GpVar v(c.newGpVar());
|
GpVar v(c.newGpVar());
|
||||||
c.mov(v, e.gpr_value(i.D.RT));
|
c.mov(v, e.gpr_value(i.D.RT));
|
||||||
c.xor_(v, imm(((uint64_t)i.D.DS) << 16));
|
c.xor_(v, imm(i.D.DS << 16));
|
||||||
e.update_gpr_value(i.D.RA, v);
|
e.update_gpr_value(i.D.RA, v);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -561,8 +561,8 @@ XEEMITTER(tw, 0x7C000008, X )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
// if (a = b) & TO[2] then TRAP
|
// if (a = b) & TO[2] then TRAP
|
||||||
// if (a <u b) & TO[3] then TRAP
|
// if (a <u b) & TO[3] then TRAP
|
||||||
// if (a >u b) & TO[4] then TRAP
|
// if (a >u b) & TO[4] then TRAP
|
||||||
GpVar va = e.sign_extend(e.trunc(e.gpr_value(i.X.RA), 4), 8);
|
GpVar va = e.sign_extend(e.gpr_value(i.X.RA), 4, 8);
|
||||||
GpVar vb = e.sign_extend(e.trunc(e.gpr_value(i.X.RA), 4), 8);
|
GpVar vb = e.sign_extend(e.gpr_value(i.X.RA), 4, 8);
|
||||||
return XeEmitTrap(e, c, i, va, vb, i.X.RT);
|
return XeEmitTrap(e, c, i, va, vb, i.X.RT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,7 +573,7 @@ XEEMITTER(twi, 0x0C000000, D )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
// if (a = EXTS(SI)) & TO[2] then TRAP
|
// if (a = EXTS(SI)) & TO[2] then TRAP
|
||||||
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
||||||
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
||||||
GpVar va = e.sign_extend(e.trunc(e.gpr_value(i.D.RA), 4), 8);
|
GpVar va = e.sign_extend(e.gpr_value(i.D.RA), 4, 8);
|
||||||
GpVar vb(c.newGpVar());
|
GpVar vb(c.newGpVar());
|
||||||
c.mov(vb, imm(XEEXTS16(i.D.DS)));
|
c.mov(vb, imm(XEEXTS16(i.D.DS)));
|
||||||
return XeEmitTrap(e, c, i, va, vb, i.D.RT);
|
return XeEmitTrap(e, c, i, va, vb, i.D.RT);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -585,7 +585,7 @@ void X64Emitter::GenerateBasicBlock(FunctionBlock* block) {
|
||||||
InstrEmitter emit = (InstrEmitter)i.type->emit;
|
InstrEmitter emit = (InstrEmitter)i.type->emit;
|
||||||
if (!i.type->emit || emit(*this, compiler_, i)) {
|
if (!i.type->emit || emit(*this, compiler_, i)) {
|
||||||
// This printf is handy for sort/uniquify to find instructions.
|
// This printf is handy for sort/uniquify to find instructions.
|
||||||
//printf("unimplinstr %s\n", i.type->name);
|
printf("unimplinstr %s\n", i.type->name);
|
||||||
|
|
||||||
XELOGCPU("Unimplemented instr %.8X %.8X %s",
|
XELOGCPU("Unimplemented instr %.8X %.8X %s",
|
||||||
ia, i.code, i.type->name);
|
ia, i.code, i.type->name);
|
||||||
|
@ -1166,10 +1166,10 @@ void X64Emitter::update_xer_value(GpVar& value) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
if (FLAGS_cache_registers) {
|
if (FLAGS_cache_registers) {
|
||||||
XEASSERT(locals_.xer.getId() != kInvalidValue);
|
XEASSERT(locals_.xer.getId() != kInvalidValue);
|
||||||
c.mov(locals_.xer, zero_extend(value, 8));
|
c.mov(locals_.xer, zero_extend(value, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, xer)),
|
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, xer)),
|
||||||
zero_extend(value, 8));
|
zero_extend(value, 0, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,7 +1180,7 @@ void X64Emitter::update_xer_with_overflow(GpVar& value) {
|
||||||
|
|
||||||
// Expects a i1 indicating overflow.
|
// Expects a i1 indicating overflow.
|
||||||
// Trust the caller that if it's larger than that it's already truncated.
|
// Trust the caller that if it's larger than that it's already truncated.
|
||||||
value = zero_extend(value, 8);
|
value = zero_extend(value, 1, 8);
|
||||||
|
|
||||||
GpVar& xer = xer_value();
|
GpVar& xer = xer_value();
|
||||||
xer = jit_insn_and(fn_, xer, get_uint64(0xFFFFFFFFBFFFFFFF)); // clear bit 30
|
xer = jit_insn_and(fn_, xer, get_uint64(0xFFFFFFFFBFFFFFFF)); // clear bit 30
|
||||||
|
@ -1213,7 +1213,7 @@ void X64Emitter::update_xer_with_overflow_and_carry(GpVar& value) {
|
||||||
|
|
||||||
// Expects a i1 indicating overflow.
|
// Expects a i1 indicating overflow.
|
||||||
// Trust the caller that if it's larger than that it's already truncated.
|
// Trust the caller that if it's larger than that it's already truncated.
|
||||||
value = zero_extend(value, jit_type_nuint);
|
value = zero_extend(value, 1, 8);
|
||||||
|
|
||||||
// This is effectively an update_xer_with_overflow followed by an
|
// This is effectively an update_xer_with_overflow followed by an
|
||||||
// update_xer_with_carry, but since the logic is largely the same share it.
|
// update_xer_with_carry, but since the logic is largely the same share it.
|
||||||
|
@ -1244,10 +1244,10 @@ void X64Emitter::update_lr_value(GpVar& value) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
if (FLAGS_cache_registers) {
|
if (FLAGS_cache_registers) {
|
||||||
XEASSERT(locals_.lr.getId() != kInvalidValue);
|
XEASSERT(locals_.lr.getId() != kInvalidValue);
|
||||||
c.mov(locals_.lr, zero_extend(value, 8));
|
c.mov(locals_.lr, zero_extend(value, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, lr)),
|
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, lr)),
|
||||||
zero_extend(value, 8));
|
zero_extend(value, 0, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,10 +1279,10 @@ void X64Emitter::update_ctr_value(GpVar& value) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
if (FLAGS_cache_registers) {
|
if (FLAGS_cache_registers) {
|
||||||
XEASSERT(locals_.ctr.getId() != kInvalidValue);
|
XEASSERT(locals_.ctr.getId() != kInvalidValue);
|
||||||
c.mov(locals_.ctr, zero_extend(value, 8));
|
c.mov(locals_.ctr, zero_extend(value, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, ctr)),
|
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, ctr)),
|
||||||
zero_extend(value, 8));
|
zero_extend(value, 0, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1409,10 +1409,10 @@ void X64Emitter::update_gpr_value(uint32_t n, GpVar& value) {
|
||||||
|
|
||||||
if (FLAGS_cache_registers) {
|
if (FLAGS_cache_registers) {
|
||||||
XEASSERT(locals_.gpr[n].getId() != kInvalidValue);
|
XEASSERT(locals_.gpr[n].getId() != kInvalidValue);
|
||||||
c.mov(locals_.gpr[n], zero_extend(value, 8));
|
c.mov(locals_.gpr[n], zero_extend(value, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, r) + 8 * n),
|
c.mov(qword_ptr(c.getGpArg(0), offsetof(xe_ppc_state_t, r) + 8 * n),
|
||||||
zero_extend(value, 8));
|
zero_extend(value, 0, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1442,135 +1442,126 @@ void X64Emitter::update_fpr_value(uint32_t n, GpVar& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GpVar& X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) {
|
GpVar X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) {
|
||||||
// // Input address is always in 32-bit space.
|
X86Compiler& c = compiler_;
|
||||||
// addr = jit_insn_and(fn_,
|
|
||||||
// zero_extend(addr, jit_type_nuint),
|
|
||||||
// jit_value_create_nint_constant(fn_, jit_type_uint, UINT_MAX));
|
|
||||||
|
|
||||||
// // Add runtime memory address checks, if needed.
|
// Input address is always in 32-bit space.
|
||||||
// // if (FLAGS_memory_address_verification) {
|
GpVar real_address(c.newGpVar());
|
||||||
// // BasicBlock* invalid_bb = BasicBlock::Create(*context_, "", fn_);
|
c.mov(real_address, addr.r32());
|
||||||
// // BasicBlock* valid_bb = BasicBlock::Create(*context_, "", fn_);
|
|
||||||
|
|
||||||
// // // The heap starts at 0x1000 - if we write below that we're boned.
|
// Add runtime memory address checks, if needed.
|
||||||
// // jit_value_t gt = b.CreateICmpUGE(addr, b.getInt64(0x00001000));
|
if (FLAGS_memory_address_verification) {
|
||||||
// // b.CreateCondBr(gt, valid_bb, invalid_bb);
|
// BasicBlock* invalid_bb = BasicBlock::Create(*context_, "", fn_);
|
||||||
|
// BasicBlock* valid_bb = BasicBlock::Create(*context_, "", fn_);
|
||||||
|
|
||||||
// // b.SetInsertPoint(invalid_bb);
|
// // The heap starts at 0x1000 - if we write below that we're boned.
|
||||||
// // jit_value_t access_violation = gen_module_->getFunction("XeAccessViolation");
|
// jit_value_t gt = b.CreateICmpUGE(addr, b.getInt64(0x00001000));
|
||||||
// // SpillRegisters();
|
// b.CreateCondBr(gt, valid_bb, invalid_bb);
|
||||||
// // b.CreateCall3(access_violation,
|
|
||||||
// // fn_->arg_begin(),
|
|
||||||
// // b.getInt32(cia),
|
|
||||||
// // addr);
|
|
||||||
// // b.CreateBr(valid_bb);
|
|
||||||
|
|
||||||
// // b.SetInsertPoint(valid_bb);
|
// b.SetInsertPoint(invalid_bb);
|
||||||
// // }
|
// jit_value_t access_violation = gen_module_->getFunction("XeAccessViolation");
|
||||||
|
// SpillRegisters();
|
||||||
|
// b.CreateCall3(access_violation,
|
||||||
|
// fn_->arg_begin(),
|
||||||
|
// b.getInt32(cia),
|
||||||
|
// addr);
|
||||||
|
// b.CreateBr(valid_bb);
|
||||||
|
|
||||||
// // Rebase off of memory pointer.
|
// b.SetInsertPoint(valid_bb);
|
||||||
// addr = jit_insn_add(fn_,
|
}
|
||||||
// addr,
|
|
||||||
// jit_value_create_nint_constant(fn_,
|
|
||||||
// jit_type_nuint, (jit_nuint)xe_memory_addr(memory_, 0)));
|
|
||||||
|
|
||||||
// return addr;
|
// Rebase off of memory pointer.
|
||||||
// }
|
uint64_t membase = (uint64_t)xe_memory_addr(memory_, 0);
|
||||||
|
c.add(real_address, get_uint64(membase));
|
||||||
|
return real_address;
|
||||||
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
// jit_type_t data_type = NULL;
|
X86Compiler& c = compiler_;
|
||||||
// bool needs_swap = false;
|
|
||||||
// switch (size) {
|
|
||||||
// case 1:
|
|
||||||
// data_type = jit_type_ubyte;
|
|
||||||
// break;
|
|
||||||
// case 2:
|
|
||||||
// data_type = jit_type_ushort;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// case 4:
|
|
||||||
// data_type = jit_type_uint;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// case 8:
|
|
||||||
// data_type = jit_type_ulong;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// XEASSERTALWAYS();
|
|
||||||
// return NULL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Rebase off of memory base pointer.
|
// Rebase off of memory base pointer.
|
||||||
// jit_value_t address = TouchMemoryAddress(cia, addr);
|
GpVar real_address = TouchMemoryAddress(cia, addr);
|
||||||
// jit_value_t value = jit_insn_load_relative(fn_, address, 0, data_type);
|
|
||||||
// if (acquire) {
|
|
||||||
// // TODO(benvanik): acquire semantics.
|
|
||||||
// // load_value->setAlignment(size);
|
|
||||||
// // load_value->setVolatile(true);
|
|
||||||
// // load_value->setAtomic(Acquire);
|
|
||||||
// jit_value_set_volatile(value);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Swap after loading.
|
if (acquire) {
|
||||||
// // TODO(benvanik): find a way to avoid this!
|
// TODO(benvanik): acquire semantics.
|
||||||
// if (needs_swap) {
|
// load_value->setAlignment(size);
|
||||||
// value = jit_insn_bswap(fn_, value);
|
// load_value->setVolatile(true);
|
||||||
// }
|
// load_value->setAtomic(Acquire);
|
||||||
|
XELOGE("Ignoring acquire semantics on read -- TODO");
|
||||||
|
}
|
||||||
|
|
||||||
// return value;
|
GpVar value(c.newGpVar());
|
||||||
// }
|
bool needs_swap = false;
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
c.mov(value, byte_ptr(real_address));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c.mov(value, word_ptr(real_address));
|
||||||
|
c.xchg(value.r8Lo(), value.r8Hi());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c.mov(value, dword_ptr(real_address));
|
||||||
|
c.bswap(value.r32());
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
c.mov(value, qword_ptr(real_address));
|
||||||
|
c.bswap(value.r64());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
c.mov(value, imm(0xDEADBEEF));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// void X64Emitter::WriteMemory(
|
return value;
|
||||||
// uint32_t cia, GpVar& addr, uint32_t size, GpVar& value,
|
}
|
||||||
// bool release) {
|
|
||||||
// jit_type_t data_type = NULL;
|
|
||||||
// bool needs_swap = false;
|
|
||||||
// switch (size) {
|
|
||||||
// case 1:
|
|
||||||
// data_type = jit_type_ubyte;
|
|
||||||
// break;
|
|
||||||
// case 2:
|
|
||||||
// data_type = jit_type_ushort;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// case 4:
|
|
||||||
// data_type = jit_type_uint;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// case 8:
|
|
||||||
// data_type = jit_type_ulong;
|
|
||||||
// needs_swap = true;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// XEASSERTALWAYS();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Truncate, if required.
|
void X64Emitter::WriteMemory(
|
||||||
// if (jit_value_get_type(value) != data_type) {
|
uint32_t cia, GpVar& addr, uint32_t size, GpVar& value,
|
||||||
// value = jit_insn_convert(fn_, value, data_type, 0);
|
bool release) {
|
||||||
// }
|
X86Compiler& c = compiler_;
|
||||||
|
|
||||||
// // Swap before storing.
|
// Rebase off of memory base pointer.
|
||||||
// // TODO(benvanik): find a way to avoid this!
|
GpVar real_address = TouchMemoryAddress(cia, addr);
|
||||||
// if (needs_swap) {
|
|
||||||
// value = jit_insn_bswap(fn_, value);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // TODO(benvanik): release semantics
|
GpVar tmp;
|
||||||
// // if (release) {
|
switch (size) {
|
||||||
// // store_value->setAlignment(size);
|
case 1:
|
||||||
// // store_value->setVolatile(true);
|
c.mov(byte_ptr(real_address), value);
|
||||||
// // store_value->setAtomic(Release);
|
break;
|
||||||
// // }
|
case 2:
|
||||||
|
tmp = c.newGpVar();
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.xchg(tmp.r8Lo(), tmp.r8Hi());
|
||||||
|
c.mov(word_ptr(real_address), tmp);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
tmp = c.newGpVar();
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.bswap(tmp.r32());
|
||||||
|
c.mov(dword_ptr(real_address), tmp);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
tmp = c.newGpVar();
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.bswap(tmp.r64());
|
||||||
|
c.mov(qword_ptr(real_address), tmp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// // Rebase off of memory base pointer.
|
// TODO(benvanik): release semantics
|
||||||
// jit_value_t address = TouchMemoryAddress(cia, addr);
|
if (release) {
|
||||||
// jit_insn_store_relative(fn_, address, 0, value);
|
// store_value->setAlignment(size);
|
||||||
// }
|
// store_value->setVolatile(true);
|
||||||
|
// store_value->setAtomic(Release);
|
||||||
|
XELOGE("Ignoring release semantics on write -- TODO");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GpVar X64Emitter::get_uint64(uint64_t value) {
|
GpVar X64Emitter::get_uint64(uint64_t value) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
|
@ -1579,11 +1570,15 @@ GpVar X64Emitter::get_uint64(uint64_t value) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpVar X64Emitter::sign_extend(GpVar& value, int size) {
|
GpVar X64Emitter::sign_extend(GpVar& value, int from_size, int to_size) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
|
|
||||||
|
if (!from_size) {
|
||||||
|
from_size = value.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
// No-op if the same size.
|
// No-op if the same size.
|
||||||
if (value.getSize() == size) {
|
if (from_size == to_size) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1593,62 +1588,116 @@ GpVar X64Emitter::sign_extend(GpVar& value, int size) {
|
||||||
// or, could use shift trick (may be slower):
|
// or, could use shift trick (may be slower):
|
||||||
// shlq $(target_len-src_len), reg
|
// shlq $(target_len-src_len), reg
|
||||||
// sarq $(target_len-src_len), reg
|
// sarq $(target_len-src_len), reg
|
||||||
GpVar tmp;
|
GpVar tmp(c.newGpVar());
|
||||||
switch (size) {
|
switch (from_size) {
|
||||||
case 1:
|
case 1:
|
||||||
XEASSERTALWAYS();
|
switch (to_size) {
|
||||||
return value;
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
case 2:
|
case 2:
|
||||||
XEASSERTALWAYS();
|
|
||||||
return value;
|
|
||||||
case 4:
|
|
||||||
XEASSERTALWAYS();
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
case 8:
|
|
||||||
tmp = c.newGpVar(kX86VarTypeGpq);
|
|
||||||
c.mov(tmp, value);
|
c.mov(tmp, value);
|
||||||
switch (value.getSize()) {
|
c.cbw(tmp); // b->w
|
||||||
case 1: c.cbw(value); // b->w->d->q
|
return tmp;
|
||||||
case 2: c.cwde(value); // w->d->q
|
case 4:
|
||||||
case 4: c.cdqe(value); // d->q
|
c.mov(tmp, value);
|
||||||
|
c.cbw(tmp); // b->w
|
||||||
|
c.cwde(tmp); // w->d
|
||||||
|
return tmp;
|
||||||
|
case 8:
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.cbw(tmp); // b->w
|
||||||
|
c.cwde(tmp); // w->d
|
||||||
|
c.cdqe(tmp); // d->q
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
switch (to_size) {
|
||||||
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
|
case 2: XEASSERTALWAYS(); return value;
|
||||||
|
case 4:
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.cwde(tmp); // w->d
|
||||||
|
return tmp;
|
||||||
|
case 8:
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.cwde(tmp); // w->d
|
||||||
|
c.cdqe(tmp); // d->q
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
switch (to_size) {
|
||||||
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
|
case 2: XEASSERTALWAYS(); return value;
|
||||||
|
case 4: XEASSERTALWAYS(); return value;
|
||||||
|
case 8:
|
||||||
|
c.mov(tmp, value);
|
||||||
|
c.cdqe(tmp); // d->q
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8: break;
|
||||||
|
}
|
||||||
|
XEASSERTALWAYS();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
GpVar X64Emitter::zero_extend(GpVar& value, int size) {
|
GpVar X64Emitter::zero_extend(GpVar& value, int from_size, int to_size) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
|
|
||||||
|
if (!from_size) {
|
||||||
|
from_size = value.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
// No-op if the same size.
|
// No-op if the same size.
|
||||||
if (value.getSize() == size) {
|
if (from_size == to_size) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(benvanik): use movzx if value is in memory.
|
// TODO(benvanik): use movzx if value is in memory.
|
||||||
|
|
||||||
GpVar tmp;
|
GpVar tmp(c.newGpVar());
|
||||||
switch (size) {
|
switch (from_size) {
|
||||||
case 1:
|
case 1:
|
||||||
tmp = c.newGpVar(kX86VarTypeGpd);
|
switch (to_size) {
|
||||||
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
|
case 2:
|
||||||
c.mov(tmp, value.r8());
|
c.mov(tmp, value.r8());
|
||||||
|
return tmp.r16();
|
||||||
|
case 4:
|
||||||
|
c.mov(tmp, value.r8());
|
||||||
|
return tmp.r32();
|
||||||
|
case 8:
|
||||||
|
c.mov(tmp, value.r8());
|
||||||
|
return tmp.r64();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
tmp = c.newGpVar(kX86VarTypeGpd);
|
switch (to_size) {
|
||||||
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
|
case 2: XEASSERTALWAYS(); return value;
|
||||||
|
case 4:
|
||||||
c.mov(tmp, value.r16());
|
c.mov(tmp, value.r16());
|
||||||
|
return tmp.r32();
|
||||||
|
case 8:
|
||||||
|
c.mov(tmp, value.r16());
|
||||||
|
return tmp.r64();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
tmp = c.newGpVar(kX86VarTypeGpd);
|
switch (to_size) {
|
||||||
c.mov(tmp, value.r32());
|
case 1: XEASSERTALWAYS(); return value;
|
||||||
break;
|
case 2: XEASSERTALWAYS(); return value;
|
||||||
default:
|
case 4: XEASSERTALWAYS(); return value;
|
||||||
case 8:
|
case 8:
|
||||||
tmp = c.newGpVar(kX86VarTypeGpq);
|
c.mov(tmp, value.r32());
|
||||||
c.mov(tmp, value.r64());
|
return tmp.r64();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return tmp;
|
break;
|
||||||
|
case 8: break;
|
||||||
|
}
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpVar X64Emitter::trunc(GpVar& value, int size) {
|
GpVar X64Emitter::trunc(GpVar& value, int size) {
|
||||||
|
|
|
@ -84,16 +84,16 @@ public:
|
||||||
AsmJit::GpVar fpr_value(uint32_t n);
|
AsmJit::GpVar fpr_value(uint32_t n);
|
||||||
void update_fpr_value(uint32_t n, AsmJit::GpVar& value);
|
void update_fpr_value(uint32_t n, AsmJit::GpVar& value);
|
||||||
|
|
||||||
AsmJit::GpVar& TouchMemoryAddress(uint32_t cia, AsmJit::GpVar& addr);
|
AsmJit::GpVar TouchMemoryAddress(uint32_t cia, AsmJit::GpVar& addr);
|
||||||
AsmJit::GpVar& ReadMemory(
|
AsmJit::GpVar ReadMemory(
|
||||||
uint32_t cia, AsmJit::GpVar& addr, uint32_t size, bool acquire = false);
|
uint32_t cia, AsmJit::GpVar& addr, uint32_t size, bool acquire = false);
|
||||||
void WriteMemory(
|
void WriteMemory(
|
||||||
uint32_t cia, AsmJit::GpVar& addr, uint32_t size, AsmJit::GpVar& value,
|
uint32_t cia, AsmJit::GpVar& addr, uint32_t size, AsmJit::GpVar& value,
|
||||||
bool release = false);
|
bool release = false);
|
||||||
|
|
||||||
AsmJit::GpVar get_uint64(uint64_t value);
|
AsmJit::GpVar get_uint64(uint64_t value);
|
||||||
AsmJit::GpVar sign_extend(AsmJit::GpVar& value, int size);
|
AsmJit::GpVar sign_extend(AsmJit::GpVar& value, int from_size, int to_size);
|
||||||
AsmJit::GpVar zero_extend(AsmJit::GpVar& value, int size);
|
AsmJit::GpVar zero_extend(AsmJit::GpVar& value, int from_size, int to_size);
|
||||||
AsmJit::GpVar trunc(AsmJit::GpVar& value, int size);
|
AsmJit::GpVar trunc(AsmJit::GpVar& value, int size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue