- avoid calling VMFillParams for simple stack frames

- split Setup into more functions
This commit is contained in:
Magnus Norddahl 2018-11-16 01:13:25 +01:00
parent 6c31d2e965
commit 34b037c9db
4 changed files with 248 additions and 199 deletions

View file

@ -814,6 +814,7 @@ VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo
if (it.Func->SymbolName != NAME_None) if (it.Func->SymbolName != NAME_None)
{ {
it.Function->Proto = it.Func->Variants[0].Proto; it.Function->Proto = it.Func->Variants[0].Proto;
it.Function->ArgFlags = it.Func->Variants[0].ArgFlags;
} }
mItems.Push(it); mItems.Push(it);
@ -885,6 +886,7 @@ void FFunctionBuildList::Build()
if (sfunc->Proto == nullptr) if (sfunc->Proto == nullptr)
{ {
sfunc->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes); sfunc->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes);
sfunc->ArgFlags = item.Func->Variants[0].ArgFlags;
} }
// Emit code // Emit code

View file

@ -471,45 +471,15 @@ void JitCompiler::Setup()
konsts = sfunc->KonstS; konsts = sfunc->KonstS;
konsta = sfunc->KonstA; konsta = sfunc->KonstA;
regD.Resize(sfunc->NumRegD);
regF.Resize(sfunc->NumRegF);
regA.Resize(sfunc->NumRegA);
regS.Resize(sfunc->NumRegS);
for (int i = 0; i < sfunc->NumRegD; i++)
{
regname.Format("regD%d", i);
regD[i] = cc.newInt32(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegF; i++)
{
regname.Format("regF%d", i);
regF[i] = cc.newXmmSd(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegS; i++)
{
regname.Format("regS%d", i);
regS[i] = cc.newIntPtr(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegA; i++)
{
regname.Format("regA%d", i);
regA[i] = cc.newIntPtr(regname.GetChars());
}
labels.Resize(sfunc->CodeSize); labels.Resize(sfunc->CodeSize);
// VMCalls[0]++ CreateRegisters();
auto vmcallsptr = newTempIntPtr(); IncrementVMCalls();
auto vmcalls = newTempInt32(); SetupFrame();
cc.mov(vmcallsptr, imm_ptr(VMCalls)); }
cc.mov(vmcalls, x86::dword_ptr(vmcallsptr));
cc.add(vmcalls, (int)1);
cc.mov(x86::dword_ptr(vmcallsptr), vmcalls);
void JitCompiler::SetupFrame()
{
// the VM version reads this from the stack, but it is constant data // the VM version reads this from the stack, but it is constant data
offsetParams = ((int)sizeof(VMFrame) + 15) & ~15; offsetParams = ((int)sizeof(VMFrame) + 15) & ~15;
offsetF = offsetParams + (int)(sfunc->MaxParam * sizeof(VMValue)); offsetF = offsetParams + (int)(sfunc->MaxParam * sizeof(VMValue));
@ -530,24 +500,33 @@ void JitCompiler::Setup()
auto slowinit = cc.newLabel(); auto slowinit = cc.newLabel();
auto endinit = cc.newLabel(); auto endinit = cc.newLabel();
#if 0 // this crashes sometimes
cc.cmp(numargs, sfunc->NumArgs); cc.cmp(numargs, sfunc->NumArgs);
cc.jne(slowinit); cc.jne(slowinit);
SetupSimpleFrame(vmstack);
cc.jmp(endinit);
cc.bind(slowinit);
SetupSimpleFrameMissingArgs(vmstack); // Does this ever happen?
cc.bind(endinit);
}
else
{
SetupFullVMFrame();
}
}
void JitCompiler::SetupSimpleFrame(asmjit::X86Mem vmstack)
{
using namespace asmjit;
// Is there a better way to know the type than this?
int argsPos = 0; int argsPos = 0;
int regd = 0, regf = 0, rega = 0; int regd = 0, regf = 0, rega = 0;
for (unsigned int i = 0; i < sfunc->Proto->ArgumentTypes.Size(); i++) for (unsigned int i = 0; i < sfunc->Proto->ArgumentTypes.Size(); i++)
{ {
const PType *type = sfunc->Proto->ArgumentTypes[i]; const PType *type = sfunc->Proto->ArgumentTypes[i];
if (type->isPointer()) if (sfunc->ArgFlags[i] & (VARF_Out | VARF_Ref))
{ {
cc.mov(regA[rega++], x86::ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, a))); cc.mov(regA[rega++], x86::ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, a)));
} }
else if (type->isIntCompatible())
{
cc.mov(regD[regd++], x86::dword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, i)));
}
else if (type == TypeVector2) else if (type == TypeVector2)
{ {
cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f)));
@ -559,7 +538,7 @@ void JitCompiler::Setup()
cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f)));
cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f)));
} }
else if (type->isFloat()) else if (type == TypeFloat64)
{ {
cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f)));
} }
@ -567,14 +546,32 @@ void JitCompiler::Setup()
{ {
I_FatalError("JIT: Strings are not supported yet for simple frames"); I_FatalError("JIT: Strings are not supported yet for simple frames");
} }
else if (type->isIntCompatible())
{
cc.mov(regD[regd++], x86::dword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, i)));
}
else
{
cc.mov(regA[rega++], x86::ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, a)));
}
} }
if (sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA) if (sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA)
I_FatalError("JIT: sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA"); I_FatalError("JIT: sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA");
cc.jmp(endinit); for (int i = regd; i < sfunc->NumRegD; i++)
#endif cc.xor_(regD[i], regD[i]);
cc.bind(slowinit);
for (int i = regf; i < sfunc->NumRegF; i++)
cc.xorpd(regF[i], regF[i]);
for (int i = rega; i < sfunc->NumRegA; i++)
cc.xor_(regA[i], regA[i]);
}
void JitCompiler::SetupSimpleFrameMissingArgs(asmjit::X86Mem vmstack)
{
using namespace asmjit;
auto sfuncptr = newTempIntPtr(); auto sfuncptr = newTempIntPtr();
cc.mov(sfuncptr, imm_ptr(sfunc)); cc.mov(sfuncptr, imm_ptr(sfunc));
@ -638,11 +635,12 @@ void JitCompiler::Setup()
for (int i = 0; i < sfunc->NumRegA; i++) for (int i = 0; i < sfunc->NumRegA; i++)
cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*))); cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*)));
cc.bind(endinit);
} }
else
void JitCompiler::SetupFullVMFrame()
{ {
using namespace asmjit;
stack = cc.newIntPtr("stack"); stack = cc.newIntPtr("stack");
auto allocFrame = CreateCall<VMFrameStack *, VMScriptFunction *, VMValue *, int>([](VMScriptFunction *func, VMValue *args, int numargs) -> VMFrameStack* { auto allocFrame = CreateCall<VMFrameStack *, VMScriptFunction *, VMValue *, int>([](VMScriptFunction *func, VMValue *args, int numargs) -> VMFrameStack* {
try try
@ -679,7 +677,6 @@ void JitCompiler::Setup()
for (int i = 0; i < sfunc->NumRegA; i++) for (int i = 0; i < sfunc->NumRegA; i++)
cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*))); cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*)));
} }
}
void JitCompiler::EmitPopFrame() void JitCompiler::EmitPopFrame()
{ {
@ -700,6 +697,49 @@ void JitCompiler::EmitPopFrame()
} }
} }
void JitCompiler::IncrementVMCalls()
{
// VMCalls[0]++
auto vmcallsptr = newTempIntPtr();
auto vmcalls = newTempInt32();
cc.mov(vmcallsptr, asmjit::imm_ptr(VMCalls));
cc.mov(vmcalls, asmjit::x86::dword_ptr(vmcallsptr));
cc.add(vmcalls, (int)1);
cc.mov(asmjit::x86::dword_ptr(vmcallsptr), vmcalls);
}
void JitCompiler::CreateRegisters()
{
regD.Resize(sfunc->NumRegD);
regF.Resize(sfunc->NumRegF);
regA.Resize(sfunc->NumRegA);
regS.Resize(sfunc->NumRegS);
for (int i = 0; i < sfunc->NumRegD; i++)
{
regname.Format("regD%d", i);
regD[i] = cc.newInt32(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegF; i++)
{
regname.Format("regF%d", i);
regF[i] = cc.newXmmSd(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegS; i++)
{
regname.Format("regS%d", i);
regS[i] = cc.newIntPtr(regname.GetChars());
}
for (int i = 0; i < sfunc->NumRegA; i++)
{
regname.Format("regA%d", i);
regA[i] = cc.newIntPtr(regname.GetChars());
}
}
void JitCompiler::EmitNullPointerThrow(int index, EVMAbortException reason) void JitCompiler::EmitNullPointerThrow(int index, EVMAbortException reason)
{ {
auto label = EmitThrowExceptionLabel(reason); auto label = EmitThrowExceptionLabel(reason);

View file

@ -39,6 +39,12 @@ private:
#undef xx #undef xx
void Setup(); void Setup();
void CreateRegisters();
void IncrementVMCalls();
void SetupFrame();
void SetupSimpleFrame(asmjit::X86Mem vmstack);
void SetupSimpleFrameMissingArgs(asmjit::X86Mem vmstack);
void SetupFullVMFrame();
void BindLabels(); void BindLabels();
void EmitOpcode(); void EmitOpcode();
void EmitPopFrame(); void EmitPopFrame();

View file

@ -329,6 +329,7 @@ public:
FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.
class PPrototype *Proto; class PPrototype *Proto;
TArray<uint32_t> ArgFlags; // Should be the same length as Proto->ArgumentTypes
int(*ScriptCall)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) = nullptr; int(*ScriptCall)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) = nullptr;