Optimize cross block single evaluation

This commit is contained in:
drmortalwombat 2022-01-04 11:44:01 +01:00
parent 60ca42e759
commit 78615c0725
4 changed files with 331 additions and 17 deletions

View File

@ -1642,6 +1642,7 @@ InterInstruction::InterInstruction(void)
mInUse = false;
mVolatile = false;
mInvariant = false;
mSingleAssignment = false;
}
void InterInstruction::SetCode(const Location& loc, InterCode code)
@ -2509,6 +2510,8 @@ void InterInstruction::Disassemble(FILE* file)
fprintf(file, "I");
if (mVolatile)
fprintf(file, "V");
if (mSingleAssignment)
fprintf(file, "S");
fprintf(file, "}\n");
}
}
@ -3958,7 +3961,7 @@ void InterCodeBasicBlock::BuildLocalTempSets(int num)
mEntryRequiredTemps = NumberSet(num);
mEntryProvidedTemps = NumberSet(num);
mExitRequiredTemps = NumberSet(num);
exitProvidedTemps = NumberSet(num);
mExitProvidedTemps = NumberSet(num);
for (i = 0; i < mInstructions.Size(); i++)
{
@ -3966,7 +3969,7 @@ void InterCodeBasicBlock::BuildLocalTempSets(int num)
}
mEntryRequiredTemps = mLocalRequiredTemps;
exitProvidedTemps = mLocalProvidedTemps;
mExitProvidedTemps = mLocalProvidedTemps;
if (mTrueJump) mTrueJump->BuildLocalTempSets(num);
if (mFalseJump) mFalseJump->BuildLocalTempSets(num);
@ -3975,18 +3978,221 @@ void InterCodeBasicBlock::BuildLocalTempSets(int num)
void InterCodeBasicBlock::BuildGlobalProvidedTempSet(NumberSet fromProvidedTemps)
{
if (!mVisited || !(fromProvidedTemps <= mEntryProvidedTemps))
bool changed = false;
if (!mVisited)
{
mEntryProvidedTemps |= fromProvidedTemps;
fromProvidedTemps |= exitProvidedTemps;
mEntryProvidedTemps = fromProvidedTemps;
changed = true;
}
else if (!(mEntryProvidedTemps <= fromProvidedTemps))
{
mEntryProvidedTemps &= fromProvidedTemps;
changed = true;
}
if (changed)
{
mExitProvidedTemps = mLocalProvidedTemps;
mExitProvidedTemps |= mEntryProvidedTemps;
mVisited = true;
if (mTrueJump) mTrueJump->BuildGlobalProvidedTempSet(fromProvidedTemps);
if (mFalseJump) mFalseJump->BuildGlobalProvidedTempSet(fromProvidedTemps);
if (mTrueJump) mTrueJump->BuildGlobalProvidedTempSet(mExitProvidedTemps);
if (mFalseJump) mFalseJump->BuildGlobalProvidedTempSet(mExitProvidedTemps);
}
}
static bool SameSingleAssignment(const GrowingInstructionPtrArray& tunified, const InterInstruction* ins, const InterInstruction* cins)
{
if (ins->mCode == cins->mCode && ins->mOperator == cins->mOperator && ins->mNumOperands == cins->mNumOperands)
{
if (ins->mCode == IC_CONSTANT)
return ins->mConst.IsEqual(cins->mConst);
for (int i = 0; i < ins->mNumOperands; i++)
{
if (ins->mSrc[i].mTemp < 0)
{
if (cins->mSrc[i].mTemp < 0)
{
if (!ins->mSrc[i].IsEqual(cins->mSrc[i]))
return false;
}
else
return false;
}
else if (cins->mSrc[i].mTemp < 0)
{
return false;
}
else if (tunified[ins->mSrc[i].mTemp] != tunified[cins->mSrc[i].mTemp])
return false;
}
return true;
}
else
return false;
}
bool InterCodeBasicBlock::SingleAssignmentTempForwarding(const GrowingInstructionPtrArray& tunified, const GrowingInstructionPtrArray& tvalues)
{
#if 0
return false;
#else
bool changed = false;
if (!mVisited)
{
mVisited = true;
GrowingInstructionPtrArray ntunified(tunified), ntvalues(tvalues);
NumberSet providedTemps(mEntryProvidedTemps);
for (int i = 0; i < mInstructions.Size(); i++)
{
InterInstruction* ins = mInstructions[i];
if (ins->mSingleAssignment)
{
int j = 0;
while (j < ntvalues.Size() && !(providedTemps[ntvalues[j]->mDst.mTemp] && SameSingleAssignment(ntunified, ins, ntvalues[j])))
j++;
if (j < ntvalues.Size())
{
if (ins->mCode != IC_CONSTANT && !(ins->mCode == IC_LOAD && ins->mSrc[0].mMemory == IM_FPARAM))
{
ins->mCode = IC_LOAD_TEMPORARY;
ins->mSrc[0].mTemp = ntvalues[j]->mDst.mTemp;
ins->mSrc[0].mType = ntvalues[j]->mDst.mType;
ins->mNumOperands = 1;
}
changed = true;
ntunified[ins->mDst.mTemp] = ntvalues[j];
}
else
{
ntvalues.Push(ins);
ntunified[ins->mDst.mTemp] = ins;
}
}
if (ins->mDst.mTemp >= 0)
providedTemps += ins->mDst.mTemp;
}
if (mTrueJump && mTrueJump->SingleAssignmentTempForwarding(ntunified, ntvalues))
changed = true;
if (mFalseJump && mFalseJump->SingleAssignmentTempForwarding(ntunified, ntvalues))
changed = true;
}
return changed;
#endif
}
bool InterCodeBasicBlock::CalculateSingleAssignmentTemps(FastNumberSet& tassigned, GrowingInstructionPtrArray& tvalue, NumberSet& modifiedParams, InterMemory paramMemory)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mInstructions.Size(); i++)
{
InterInstruction* ins = mInstructions[i];
int t = ins->mDst.mTemp;
if (t >= 0)
{
if (!tassigned[t] || tvalue[t] == ins)
{
if (!tassigned[t])
{
changed = true;
tassigned += t;
}
int j = 0;
while (j < ins->mNumOperands && (ins->mSrc[j].mTemp < 0 || tvalue[ins->mSrc[j].mTemp] != nullptr))
j++;
bool valid = j == ins->mNumOperands;
if (valid)
{
if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER)
valid = false;
else if (ins->mCode == IC_LOAD)
{
if (ins->mSrc[0].mMemory == paramMemory)
{
if (modifiedParams[ins->mSrc[0].mVarIndex])
valid = false;
}
else if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
if (!(ins->mSrc[0].mLinkerObject->mFlags & LOBJF_CONST))
valid = false;
}
else
valid = false;
}
else if (ins->mCode == IC_LEA)
{
if (ins->mSrc[1].mMemory == paramMemory)
{
if (!modifiedParams[ins->mSrc[1].mVarIndex])
{
modifiedParams += ins->mSrc[1].mVarIndex;
changed = true;
}
}
}
}
if (valid)
{
if (!tvalue[t])
{
tvalue[t] = ins;
changed = true;
}
}
else if (tvalue[t])
{
tvalue[t] = nullptr;
changed = true;
}
}
else if (tvalue[t])
{
tvalue[t] = nullptr;
changed = true;
}
}
else if (ins->mCode == IC_STORE)
{
if (ins->mSrc[1].mMemory == paramMemory)
{
if (!modifiedParams[ins->mSrc[1].mVarIndex])
{
modifiedParams += ins->mSrc[1].mVarIndex;
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->CalculateSingleAssignmentTemps(tassigned, tvalue, modifiedParams, paramMemory))
changed = true;
if (mFalseJump && mFalseJump->CalculateSingleAssignmentTemps(tassigned, tvalue, modifiedParams, paramMemory))
changed = true;
}
return changed;
}
void InterCodeBasicBlock::PerformTempForwarding(TempForwardingTable& forwardingTable)
{
int i;
@ -6693,6 +6899,38 @@ void InterCodeProcedure::RenameTemporaries(void)
DisassembleDebug("global renamed temps");
}
void InterCodeProcedure::SingleAssignmentForwarding(void)
{
int numTemps = mTemporaries.Size();
InterMemory paramMemory = mFastCallProcedure ? IM_FPARAM : IM_PARAM;
FastNumberSet tassigned(numTemps);
GrowingInstructionPtrArray tunified(nullptr), tvalues(nullptr);
NumberSet modifiedParams(mParamAliasedSet.Size());
tunified.SetSize(numTemps);
bool changed;
do
{
ResetVisited();
changed = mEntryBlock->CalculateSingleAssignmentTemps(tassigned, tunified, modifiedParams, paramMemory);
} while (changed);
for (int i = 0; i < numTemps; i++)
{
if (tunified[i])
tunified[i]->mSingleAssignment = true;
}
tunified.Clear();
ResetVisited();
mEntryBlock->SingleAssignmentTempForwarding(tunified, tvalues);
DisassembleDebug("single assignment forwarding");
}
void InterCodeProcedure::TempForwarding(void)
{
int numTemps = mTemporaries.Size();
@ -7028,6 +7266,8 @@ void InterCodeProcedure::Close(void)
BuildDataFlowSets();
#endif
SingleAssignmentForwarding();
ResetVisited();
mEntryBlock->PeepholeOptimization();
@ -7036,7 +7276,7 @@ void InterCodeProcedure::Close(void)
DisassembleDebug("Peephole optimized");
bool changed = false;
bool changed = false;
do
{
BuildDataFlowSets();

View File

@ -347,7 +347,7 @@ public:
int mNumOperands;
Location mLocation;
bool mInUse, mInvariant, mVolatile, mExpensive;
bool mInUse, mInvariant, mVolatile, mExpensive, mSingleAssignment;
InterInstruction(void);
@ -446,7 +446,7 @@ public:
NumberSet mLocalRequiredTemps, mLocalProvidedTemps;
NumberSet mEntryRequiredTemps, mEntryProvidedTemps;
NumberSet mExitRequiredTemps, exitProvidedTemps;
NumberSet mExitRequiredTemps, mExitProvidedTemps;
NumberSet mLocalRequiredVars, mLocalProvidedVars;
NumberSet mEntryRequiredVars, mEntryProvidedVars;
@ -520,6 +520,9 @@ public:
void PerformMachineSpecificValueUsageCheck(const GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid);
bool EliminateDeadBranches(void);
bool CalculateSingleAssignmentTemps(FastNumberSet& tassigned, GrowingInstructionPtrArray& tvalue, NumberSet& modifiedParams, InterMemory paramMemory);
bool SingleAssignmentTempForwarding(const GrowingInstructionPtrArray& tunified, const GrowingInstructionPtrArray& tvalues);
void BuildCollisionTable(NumberSet* collisionSets);
void ReduceTemporaries(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
@ -625,6 +628,7 @@ protected:
void RemoveUnusedInstructions(void);
bool GlobalConstantPropagation(void);
void BuildDominators(void);
void SingleAssignmentForwarding(void);
void MergeBasicBlocks(void);

View File

@ -770,6 +770,47 @@ bool NativeCodeInstruction::IsSame(const NativeCodeInstruction& ins) const
return false;
}
bool NativeCodeInstruction::MayBeChangedOnAddress(const NativeCodeInstruction& ins) const
{
if (!ins.ChangesAddress())
return false;
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (mMode == ASMIM_ZERO_PAGE)
return mAddress == ins.mAddress;
else if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y)
return mAddress == ins.mAddress || mAddress + 1 == ins.mAddress;
else
return mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y;
}
else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y)
{
return mMode == ASMIM_ZERO_PAGE || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y;
}
else if (ins.mMode == ASMIM_ABSOLUTE)
{
if (mMode == ASMIM_ABSOLUTE)
return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress;
else if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
return mLinkerObject == ins.mLinkerObject;
else
return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X;
}
else if (ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
{
if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
return mLinkerObject == ins.mLinkerObject;
else
return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X;
}
else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
return mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X;
else
return false;
}
bool NativeCodeInstruction::SameEffectiveAddress(const NativeCodeInstruction& ins) const
{
if (mMode != ins.mMode)
@ -4796,7 +4837,14 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc
mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, BC_REG_ACCU, lshift);
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
return BC_REG_ACCU;
case 5:
if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 51)
@ -4825,7 +4873,14 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc
mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, BC_REG_ACCU, lshift);
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
return BC_REG_ACCU;
case 7:
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
@ -4845,7 +4900,14 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 5));
mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, BC_REG_ACCU, lshift);
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
return BC_REG_ACCU;
case 9:
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
@ -4865,7 +4927,14 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 5));
mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, BC_REG_ACCU, lshift);
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
ShiftRegisterLeft(proc, BC_REG_ACCU, lshift);
return BC_REG_ACCU;
#if 1
case 25:
@ -11390,13 +11459,13 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
//
// move ldx/y down
for (int i = 0; i + 1 < mIns.Size(); i++)
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY)
{
if (!mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || !mIns[i + 1].ChangesAddress())
if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
{
NativeCodeInstruction ins = mIns[i];
mIns[i] = mIns[i + 1];
@ -11409,7 +11478,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
{
if (!mIns[i + 1].RequiresXReg() && !mIns[i + 1].ChangesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || !mIns[i + 1].ChangesAddress())
if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
{
NativeCodeInstruction ins = mIns[i];
mIns[i] = mIns[i + 1];

View File

@ -93,6 +93,7 @@ public:
bool UsesZeroPage(int address) const;
bool ChangesGlobalMemory(void) const;
bool SameEffectiveAddress(const NativeCodeInstruction& ins) const;
bool MayBeChangedOnAddress(const NativeCodeInstruction& ins) const;
bool IsSame(const NativeCodeInstruction& ins) const;
bool IsCommutative(void) const;
bool IsShift(void) const;