Finally I have tracked down this nasty bug and fixed it.
Problem was in function EInstruction::translate. If instruction had 2 operands that are spilled (on stack), than there was a bug in how they are allocated back to registers.
First AsmJit assigned workOffset=cc._currentOffset to both variables. Then it tried to allocate register for the first operand. For that it needed to emit one instruction. This resulted in incrementing of cc._currentOffset. Then it tried to allocate register for the second operand. But because the _currentOffset was incremented, there was nothing to prevent it from allocating the same register also to this second operand. During that it spilled the first operand, which ended with vdata->registerIndex==INVALID_VALUE.
My fix to this is to update workOffset of all operands also during allocation loop. See code below.
p.
Emittable* EInstruction::translate(CompilerContext& cc) ASMJIT_NOTHROW
{
uint32_t i;
uint32_t variablesCount = _variablesCount;
if (variablesCount > 0)
{
// These variables are used by the instruction and we set current offset
// to their work offsets -> getSpillCandidate never return the variable
// used this instruction.
for (i = 0; i < variablesCount; i++)
{
_variables->vdata->workOffset = cc._currentOffset;
}
// Alloc variables used by the instruction (special first).
for (i = 0; i < variablesCount; i++)
{
for(int j=0; j<variablesCount; j++) {
VarAllocRecord& r2 = _variables[j];
r2.vdata->workOffset=cc._currentOffset;
}
VarAllocRecord& r = _variables[i];
// Alloc variables with specific register first.
if ((r.vflags & VARIABLE_ALLOC_SPECIAL) != 0)
cc.allocVar(r.vdata, r.regMask, r.vflags);
}
for (i = 0; i < variablesCount; i++)
{
for(int j=0; j<variablesCount; j++) {
VarAllocRecord& r2 = _variables[j];
r2.vdata->workOffset=cc._currentOffset;
}
VarAllocRecord& r = _variables[i];
// Alloc variables without specific register last.
if ((r.vflags & VARIABLE_ALLOC_SPECIAL) == 0) {
cc.allocVar(r.vdata, r.regMask, r.vflags);
}
ASMJIT_ASSERT(r.vdata->registerIndex!=INVALID_VALUE);
for(int j=0; j<=i; j++) {
VarAllocRecord& r2 = _variables[j];
ASMJIT_ASSERT(r2.vdata->registerIndex!=INVALID_VALUE);
}
}