coprocessor: Implement fast-path for Coproc{Send,Get}{OneWord,TwoWords}
Allow coprocessor interface to provide pointers instead of a callback. This allows for a fastpath when all that is required is to read or write a value and no other action needs to be taken.
This commit is contained in:
parent
e3bc7d039f
commit
9ecdd32b84
2 changed files with 103 additions and 21 deletions
|
@ -36,6 +36,20 @@ public:
|
||||||
boost::optional<void*> user_arg;
|
boost::optional<void*> user_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* boost::blank: coprocessor exception will be compiled
|
||||||
|
* Callback: a call to the Callback will be compiled
|
||||||
|
* std::uint32_t*: a write/read to that memory address will be compiled
|
||||||
|
*/
|
||||||
|
using CallbackOrAccessOneWord = boost::variant<boost::blank, Callback, std::uint32_t*>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* boost::blank: coprocessor exception will be compiled
|
||||||
|
* Callback: a call to the Callback will be compiled
|
||||||
|
* std::array<std::uint32_t*, 2>: a write/read to those memory addresses will be compiled
|
||||||
|
*/
|
||||||
|
using CallbackOrAccessTwoWords = boost::variant<boost::blank, Callback, std::array<std::uint32_t*, 2>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling CDP or CDP2 for this coprocessor.
|
* Called when compiling CDP or CDP2 for this coprocessor.
|
||||||
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
||||||
|
@ -45,38 +59,38 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling MCR or MCR2 for this coprocessor.
|
* Called when compiling MCR or MCR2 for this coprocessor.
|
||||||
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
* A return value of boost::blank will cause a coprocessor exception to be compiled.
|
||||||
* arg0 of the callback will contain the word sent to the coprocessor.
|
* arg0 of the callback will contain the word sent to the coprocessor.
|
||||||
* arg1 and return value of the callback are ignored.
|
* arg1 and return value of the callback are ignored.
|
||||||
*/
|
*/
|
||||||
virtual boost::optional<Callback> CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) = 0;
|
virtual CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling MCRR or MCRR2 for this coprocessor.
|
* Called when compiling MCRR or MCRR2 for this coprocessor.
|
||||||
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
* A return value of boost::blank will cause a coprocessor exception to be compiled.
|
||||||
* arg0 and arg1 of the callback will contain the words sent to the coprocessor.
|
* arg0 and arg1 of the callback will contain the words sent to the coprocessor.
|
||||||
* The return value of the callback is ignored.
|
* The return value of the callback is ignored.
|
||||||
*/
|
*/
|
||||||
virtual boost::optional<Callback> CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) = 0;
|
virtual CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling MRC or MRC2 for this coprocessor.
|
* Called when compiling MRC or MRC2 for this coprocessor.
|
||||||
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
* A return value of boost::blank will cause a coprocessor exception to be compiled.
|
||||||
* The return value of the callback should contain word from coprocessor.
|
* The return value of the callback should contain word from coprocessor.
|
||||||
* The low word of the return value will be stored in Rt.
|
* The low word of the return value will be stored in Rt.
|
||||||
* arg0 and arg1 of the callback are ignored.
|
* arg0 and arg1 of the callback are ignored.
|
||||||
*/
|
*/
|
||||||
virtual boost::optional<Callback> CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) = 0;
|
virtual CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling MRRC or MRRC2 for this coprocessor.
|
* Called when compiling MRRC or MRRC2 for this coprocessor.
|
||||||
* A return value of boost::none will cause a coprocessor exception to be compiled.
|
* A return value of boost::blank will cause a coprocessor exception to be compiled.
|
||||||
* The return value of the callback should contain words from coprocessor.
|
* The return value of the callback should contain words from coprocessor.
|
||||||
* The low word of the return value will be stored in Rt.
|
* The low word of the return value will be stored in Rt.
|
||||||
* The high word of the return value will be stored in Rt2.
|
* The high word of the return value will be stored in Rt2.
|
||||||
* arg0 and arg1 of the callback are ignored.
|
* arg0 and arg1 of the callback are ignored.
|
||||||
*/
|
*/
|
||||||
virtual boost::optional<Callback> CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) = 0;
|
virtual CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when compiling LDC or LDC2 for this coprocessor.
|
* Called when compiling LDC or LDC2 for this coprocessor.
|
||||||
|
|
|
@ -3017,12 +3017,27 @@ void EmitX64::EmitCoprocSendOneWord(IR::Block&, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto action = coproc->CompileSendOneWord(two, opc1, CRn, CRm, opc2);
|
auto action = coproc->CompileSendOneWord(two, opc1, CRn, CRm, opc2);
|
||||||
if (!action) {
|
switch (action.which()) {
|
||||||
|
case 0:
|
||||||
EmitCoprocessorException();
|
EmitCoprocessorException();
|
||||||
return;
|
return;
|
||||||
}
|
case 1:
|
||||||
|
|
||||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word);
|
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word);
|
||||||
|
return;
|
||||||
|
case 2: {
|
||||||
|
u32* destination_ptr = boost::get<u32*>(action);
|
||||||
|
|
||||||
|
Xbyak::Reg32 reg_word = reg_alloc.UseGpr(word).cvt32();
|
||||||
|
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
|
||||||
|
|
||||||
|
code->mov(reg_destination_addr, reinterpret_cast<u64>(destination_ptr));
|
||||||
|
code->mov(code->dword[reg_destination_addr], reg_word);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unreachable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCoprocSendTwoWords(IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitCoprocSendTwoWords(IR::Block&, IR::Inst* inst) {
|
||||||
|
@ -3043,13 +3058,31 @@ void EmitX64::EmitCoprocSendTwoWords(IR::Block&, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto action = coproc->CompileSendTwoWords(two, opc, CRm);
|
auto action = coproc->CompileSendTwoWords(two, opc, CRm);
|
||||||
if (!action) {
|
switch (action.which()) {
|
||||||
|
case 0:
|
||||||
EmitCoprocessorException();
|
EmitCoprocessorException();
|
||||||
return;
|
return;
|
||||||
}
|
case 1:
|
||||||
|
|
||||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word1, word2);
|
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word1, word2);
|
||||||
|
return;
|
||||||
|
case 2: {
|
||||||
|
auto destination_ptrs = boost::get<std::array<u32*, 2>>(action);
|
||||||
|
|
||||||
|
Xbyak::Reg32 reg_word1 = reg_alloc.UseGpr(word1).cvt32();
|
||||||
|
Xbyak::Reg32 reg_word2 = reg_alloc.UseGpr(word2).cvt32();
|
||||||
|
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
|
||||||
|
|
||||||
|
code->mov(reg_destination_addr, reinterpret_cast<u64>(destination_ptrs[0]));
|
||||||
|
code->mov(code->dword[reg_destination_addr], reg_word1);
|
||||||
|
code->mov(reg_destination_addr, reinterpret_cast<u64>(destination_ptrs[1]));
|
||||||
|
code->mov(code->dword[reg_destination_addr], reg_word2);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCoprocGetOneWord(IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitCoprocGetOneWord(IR::Block&, IR::Inst* inst) {
|
||||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||||
|
@ -3068,12 +3101,27 @@ void EmitX64::EmitCoprocGetOneWord(IR::Block&, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto action = coproc->CompileGetOneWord(two, opc1, CRn, CRm, opc2);
|
auto action = coproc->CompileGetOneWord(two, opc1, CRn, CRm, opc2);
|
||||||
if (!action) {
|
switch (action.which()) {
|
||||||
|
case 0:
|
||||||
EmitCoprocessorException();
|
EmitCoprocessorException();
|
||||||
return;
|
return;
|
||||||
}
|
case 1:
|
||||||
|
|
||||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
||||||
|
return;
|
||||||
|
case 2: {
|
||||||
|
u32* source_ptr = boost::get<u32*>(action);
|
||||||
|
|
||||||
|
Xbyak::Reg32 reg_word = reg_alloc.DefGpr(inst).cvt32();
|
||||||
|
Xbyak::Reg64 reg_source_addr = reg_alloc.ScratchGpr();
|
||||||
|
|
||||||
|
code->mov(reg_source_addr, reinterpret_cast<u64>(source_ptr));
|
||||||
|
code->mov(reg_word, code->dword[reg_source_addr]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unreachable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCoprocGetTwoWords(IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitCoprocGetTwoWords(IR::Block&, IR::Inst* inst) {
|
||||||
|
@ -3091,12 +3139,32 @@ void EmitX64::EmitCoprocGetTwoWords(IR::Block&, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto action = coproc->CompileGetTwoWords(two, opc, CRm);
|
auto action = coproc->CompileGetTwoWords(two, opc, CRm);
|
||||||
if (!action) {
|
switch (action.which()) {
|
||||||
|
case 0:
|
||||||
EmitCoprocessorException();
|
EmitCoprocessorException();
|
||||||
return;
|
return;
|
||||||
}
|
case 1:
|
||||||
|
|
||||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
||||||
|
return;
|
||||||
|
case 2: {
|
||||||
|
auto source_ptrs = boost::get<std::array<u32*, 2>>(action);
|
||||||
|
|
||||||
|
Xbyak::Reg64 reg_result = reg_alloc.DefGpr(inst);
|
||||||
|
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
|
||||||
|
Xbyak::Reg64 reg_tmp = reg_alloc.ScratchGpr();
|
||||||
|
|
||||||
|
code->mov(reg_destination_addr, reinterpret_cast<u64>(source_ptrs[1]));
|
||||||
|
code->mov(reg_result.cvt32(), code->dword[reg_destination_addr]);
|
||||||
|
code->shl(reg_result, 32);
|
||||||
|
code->mov(reg_destination_addr, reinterpret_cast<u64>(source_ptrs[0]));
|
||||||
|
code->mov(reg_tmp.cvt32(), code->dword[reg_destination_addr]);
|
||||||
|
code->or_(reg_result, reg_tmp);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unreachable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCoprocLoadWords(IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitCoprocLoadWords(IR::Block&, IR::Inst* inst) {
|
||||||
|
|
Loading…
Reference in a new issue