diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 02510524e2..afd823dd6f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -11349,8 +11349,51 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { if (RegNum == -1) { - if (!(VarFlags & VARF_Out)) RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); - else RegNum = build->Registers[REGT_POINTER].Get(1); + if (!(VarFlags & VARF_Out)) + { + const int regType = ValueType->GetRegType(); + assert(regType <= REGT_TYPE); + + auto& registers = build->Registers[regType]; + RegNum = registers.Get(RegCount); + + for (int reg = RegNum, end = RegNum + RegCount; reg < end; ++reg) + { + if (!registers.IsDirty(reg)) + { + continue; + } + + ScriptPosition.Message(MSG_DEBUGMSG, "Implicit initialization of variable %s\n", Name.GetChars()); + + switch (regType) + { + case REGT_INT: + build->Emit(OP_LI, reg, 0, 0); + break; + + case REGT_FLOAT: + build->Emit(OP_LKF, reg, build->GetConstantFloat(0.0)); + break; + + case REGT_STRING: + build->Emit(OP_LKS, reg, build->GetConstantString(nullptr)); + break; + + case REGT_POINTER: + build->Emit(OP_LKP, reg, build->GetConstantAddress(nullptr)); + break; + + default: + assert(false); + break; + } + } + } + else + { + RegNum = build->Registers[REGT_POINTER].Get(1); + } } } else diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 2b3b547c59..1c27a597e6 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -367,6 +367,7 @@ void VMFunctionBuilder::ParamChange(int delta) VMFunctionBuilder::RegAvailability::RegAvailability() { memset(Used, 0, sizeof(Used)); + memset(Dirty, 0, sizeof(Dirty)); MostUsed = 0; } @@ -493,16 +494,19 @@ void VMFunctionBuilder::RegAvailability::Return(int reg, int count) // because for that case it pushes the self pointer a second time without reallocating, so it gets freed twice. //assert((Used[firstword] & mask) == mask); Used[firstword] &= ~mask; + Dirty[firstword] |= mask; } else { // Range is in two words. partialmask = mask << firstbit; assert((Used[firstword] & partialmask) == partialmask); Used[firstword] &= ~partialmask; + Dirty[firstword] |= partialmask; partialmask = mask >> (32 - firstbit); assert((Used[firstword + 1] & partialmask) == partialmask); Used[firstword + 1] &= ~partialmask; + Dirty[firstword + 1] |= partialmask; } } diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index 28b6798d51..856e2afca3 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -37,8 +37,16 @@ public: void Return(int reg, int count); bool Reuse(int regnum); + bool IsDirty(int reg) const + { + const int firstword = reg / 32; + const int firstbit = reg & 31; + return Dirty[firstword] & (1 << firstbit); + } + private: VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) + VM_UWORD Dirty[256/32]; int MostUsed; friend class VMFunctionBuilder;