mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 15:22:16 +00:00
- pass additional return values as the last args to a direct native call
This commit is contained in:
parent
3202c86ea7
commit
8860517bbd
1 changed files with 85 additions and 14 deletions
|
@ -403,36 +403,78 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.setCursor(cursorAfter);
|
|
||||||
|
|
||||||
if (numparams != B)
|
if (numparams != B)
|
||||||
I_FatalError("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions\n");
|
I_FatalError("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions\n");
|
||||||
|
|
||||||
int numret = C;
|
// Note: the usage of newResultXX is intentional. Asmjit has a register allocation bug
|
||||||
if (numret > 1)
|
// if the return virtual register is already allocated in an argument slot.
|
||||||
I_FatalError("Only one return parameter is supported for direct native calls\n");
|
|
||||||
|
|
||||||
if (numret == 1)
|
const VMOP *retval = pc + 1;
|
||||||
|
int numret = C;
|
||||||
|
|
||||||
|
// Check if first return value was placed in the function's real return value slot
|
||||||
|
int startret = 1;
|
||||||
|
if (numret > 0)
|
||||||
{
|
{
|
||||||
const auto &retval = pc[1];
|
int type = retval[0].b;
|
||||||
if (retval.op != OP_RESULT)
|
switch (type)
|
||||||
{
|
{
|
||||||
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
case REGT_INT:
|
||||||
|
case REGT_FLOAT:
|
||||||
|
case REGT_POINTER:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
startret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = retval.b;
|
// Pass return pointers as arguments
|
||||||
int regnum = retval.c;
|
for (int i = startret; i < numret; ++i)
|
||||||
|
{
|
||||||
|
int type = retval[i].b;
|
||||||
|
int regnum = retval[i].c;
|
||||||
|
|
||||||
if (type & REGT_KONST)
|
if (type & REGT_KONST)
|
||||||
{
|
{
|
||||||
I_FatalError("OP_RESULT with REGT_KONST is not allowed\n");
|
I_FatalError("OP_RESULT with REGT_KONST is not allowed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: the usage of newResultXX is intentional. Asmjit has a register allocation bug
|
CheckVMFrame();
|
||||||
// if the return virtual register is already allocated in an argument slot.
|
|
||||||
|
auto regPtr = newTempIntPtr();
|
||||||
|
|
||||||
switch (type & REGT_TYPE)
|
switch (type & REGT_TYPE)
|
||||||
{
|
{
|
||||||
|
case REGT_INT:
|
||||||
|
cc.lea(regPtr, x86::ptr(vmframe, offsetD + (int)(regnum * sizeof(int32_t))));
|
||||||
|
break;
|
||||||
|
case REGT_FLOAT:
|
||||||
|
cc.lea(regPtr, x86::ptr(vmframe, offsetF + (int)(regnum * sizeof(double))));
|
||||||
|
break;
|
||||||
|
case REGT_STRING:
|
||||||
|
cc.lea(regPtr, x86::ptr(vmframe, offsetS + (int)(regnum * sizeof(FString))));
|
||||||
|
break;
|
||||||
|
case REGT_POINTER:
|
||||||
|
cc.lea(regPtr, x86::ptr(vmframe, offsetA + (int)(regnum * sizeof(void*))));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
I_FatalError("Unknown OP_RESULT type encountered\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.setArg(numparams + i - startret, regPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.setCursor(cursorAfter);
|
||||||
|
|
||||||
|
if (startret == 1 && numret > 0)
|
||||||
|
{
|
||||||
|
int type = retval[0].b;
|
||||||
|
int regnum = retval[0].c;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
case REGT_INT:
|
case REGT_INT:
|
||||||
tmp = newResultInt32();
|
tmp = newResultInt32();
|
||||||
call->setRet(0, tmp);
|
call->setRet(0, tmp);
|
||||||
|
@ -448,11 +490,40 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
call->setRet(0, tmp);
|
call->setRet(0, tmp);
|
||||||
cc.mov(regA[regnum], tmp);
|
cc.mov(regA[regnum], tmp);
|
||||||
break;
|
break;
|
||||||
case REGT_STRING:
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the result into virtual registers
|
||||||
|
for (int i = startret; i < numret; ++i)
|
||||||
|
{
|
||||||
|
int type = retval[i].b;
|
||||||
|
int regnum = retval[i].c;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case REGT_INT:
|
||||||
|
cc.mov(regD[regnum], asmjit::x86::dword_ptr(vmframe, offsetD + regnum * sizeof(int32_t)));
|
||||||
|
break;
|
||||||
|
case REGT_FLOAT:
|
||||||
|
cc.movsd(regF[regnum], asmjit::x86::qword_ptr(vmframe, offsetF + regnum * sizeof(double)));
|
||||||
|
break;
|
||||||
case REGT_FLOAT | REGT_MULTIREG2:
|
case REGT_FLOAT | REGT_MULTIREG2:
|
||||||
|
cc.movsd(regF[regnum], asmjit::x86::qword_ptr(vmframe, offsetF + regnum * sizeof(double)));
|
||||||
|
cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double)));
|
||||||
|
break;
|
||||||
case REGT_FLOAT | REGT_MULTIREG3:
|
case REGT_FLOAT | REGT_MULTIREG3:
|
||||||
|
cc.movsd(regF[regnum], asmjit::x86::qword_ptr(vmframe, offsetF + regnum * sizeof(double)));
|
||||||
|
cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double)));
|
||||||
|
cc.movsd(regF[regnum + 2], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 2) * sizeof(double)));
|
||||||
|
break;
|
||||||
|
case REGT_STRING:
|
||||||
|
// We don't have to do anything in this case. String values are never moved to virtual registers.
|
||||||
|
break;
|
||||||
|
case REGT_POINTER:
|
||||||
|
cc.mov(regA[regnum], asmjit::x86::ptr(vmframe, offsetA + regnum * sizeof(void*)));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unsupported OP_RESULT type encountered in EmitNativeCall\n");
|
I_FatalError("Unknown OP_RESULT type encountered\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue