From 0f5e9330021070a865b7f1ed4ec97a590cc5e9b7 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:57:59 +0200 Subject: [PATCH] Optimize cross block constant propagation --- oscar64/InterCode.cpp | 164 +++++++++++++++++++++++++++++++- oscar64/InterCode.h | 4 + oscar64/Linker.cpp | 25 +++++ oscar64/NativeCodeGenerator.cpp | 69 +++++++++++++- oscar64/NativeCodeGenerator.h | 1 + 5 files changed, 256 insertions(+), 7 deletions(-) diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 086b690..97caaf6 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -16219,6 +16219,153 @@ static int TempUseDelta(const InterInstruction* ins) return d; } +bool InterCodeBasicBlock::IsConstExitTemp(int temp) const +{ + int n = mInstructions.Size() - 1; + while (n >= 0 && mInstructions[n]->mDst.mTemp != temp) + n--; + return n >= 0 && mInstructions[n]->mCode == IC_CONSTANT; +} + +bool InterCodeBasicBlock::SplitSingleBranchUseConst(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead && mFalseJump) + { + for (int i = 0; i + 1 < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_CONSTANT) + { + if (CanMoveInstructionBehindBlock(i)) + { + InterCodeBasicBlock* tblock = nullptr; + + if (mTrueJump->mEntryRequiredTemps[ins->mDst.mTemp] && !mFalseJump->mEntryRequiredTemps[ins->mDst.mTemp]) + tblock = mTrueJump; + else if (!mTrueJump->mEntryRequiredTemps[ins->mDst.mTemp] && mFalseJump->mEntryRequiredTemps[ins->mDst.mTemp]) + tblock = mFalseJump; + + if (tblock) + { + if (tblock->mNumEntries > 1) + { + InterCodeBasicBlock* nblock = new InterCodeBasicBlock(mProc); + + nblock->mEntryRequiredTemps = tblock->mEntryRequiredTemps; + nblock->mExitRequiredTemps = tblock->mEntryRequiredTemps; + + mExitRequiredTemps -= ins->mDst.mTemp; + nblock->mEntryRequiredTemps -= ins->mDst.mTemp; + + tblock->mEntryBlocks.RemoveAll(this); + tblock->mEntryBlocks.Push(nblock); + + if (tblock == mTrueJump) + mTrueJump = nblock; + else + mFalseJump = nblock; + + InterInstruction* jins = new InterInstruction(mInstructions.Last()->mLocation, IC_JUMP); + nblock->mInstructions.Push(jins); + nblock->Close(tblock, nullptr); + + nblock->mEntryBlocks.Push(this); + nblock->mNumEntries = 1; + + tblock = nblock; + } + + tblock->mInstructions.Insert(0, ins); + mInstructions.Remove(i); + i--; + changed = true; + } + } + } + } + } + + + if (mTrueJump && mTrueJump->SplitSingleBranchUseConst()) + changed = true; + if (mFalseJump && mFalseJump->SplitSingleBranchUseConst()) + changed = true; + } + + return changed; +} + + +bool InterCodeBasicBlock::CommonTailCodeMerge(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead) + { + for (int i = 0; i + 1 < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (CanMoveInstructionBeforeBlock(i)) + { + bool aconst = true, aany = false; + for (int j = 0; j < ins->mNumOperands; j++) + { + if (ins->mSrc[j].mTemp >= 0) + { + aany = true; + int k = 0; + while (k < mEntryBlocks.Size() && mEntryBlocks[k]->IsConstExitTemp(ins->mSrc[j].mTemp) && !mEntryBlocks[k]->mFalseJump) + k++; + if (k < mEntryBlocks.Size()) + { + aconst = false; + break; + } + } + } + + if (aconst && aany) + { + for (int j = 0; j < mEntryBlocks.Size(); j++) + { + InterCodeBasicBlock* eblock = mEntryBlocks[j]; + eblock->mInstructions.Insert(eblock->mInstructions.Size() - 1, ins->Clone()); + if (ins->mDst.mTemp >= 0) + eblock->mExitRequiredTemps += ins->mDst.mTemp; + } + if (ins->mDst.mTemp >= 0) + mEntryRequiredTemps += ins->mDst.mTemp; + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + ins->mDst.mTemp = -1; + changed = true; + } + + } + } + } + + if (mTrueJump && mTrueJump->CommonTailCodeMerge()) + changed = true; + if (mFalseJump && mFalseJump->CommonTailCodeMerge()) + changed = true; + } + + return changed; +} + void InterCodeBasicBlock::PeepholeOptimization(const GrowingVariableArray& staticVars) { int i; @@ -18021,6 +18168,17 @@ void InterCodeProcedure::PropagateConstOperationsUp(void) do { changed = false; + ResetVisited(); + if (mEntryBlock->SplitSingleBranchUseConst()) + changed = true; + + ResetVisited(); + if (mEntryBlock->CommonTailCodeMerge()) + { + changed = true; + BuildDataFlowSets(); + } + ResetVisited(); mEntryBlock->BuildConstTempSets(); @@ -18069,7 +18227,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "setspr"); + CheckFunc = !strcmp(mIdent->mString, "dungeon_rand_path"); CheckCase = false; mEntryBlock = mBlocks[0]; @@ -18775,15 +18933,11 @@ void InterCodeProcedure::Close(void) #if 1 do { DisassembleDebug("InConstP"); - CheckFinal(); TempForwarding(); - CheckFinal(); } while (GlobalConstantPropagation()); - CheckFinal(); BuildTraces(false); DisassembleDebug("Rebuilt traces"); - CheckFinal(); PeepholeOptimization(); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 737417f..7835b2e 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -555,6 +555,10 @@ public: void CheckFinal(void); void CheckBlocks(void); + bool IsConstExitTemp(int temp) const; + bool CommonTailCodeMerge(void); + bool SplitSingleBranchUseConst(void); + void PeepholeOptimization(const GrowingVariableArray& staticVars); bool PeepholeReplaceOptimization(const GrowingVariableArray& staticVars); diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 092dedf..030b9c1 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -1283,6 +1283,31 @@ bool Linker::WriteMapFile(const char* filename) } } + fprintf(file, "\nobjects by size\n"); + ExpandingArray so; + for (int i = 0; i < mObjects.Size(); i++) + { + LinkerObject* obj = mObjects[i]; + + if ((obj->mFlags & LOBJF_REFERENCED) && obj->mIdent) + { + int k = so.Size(); + so.Push(obj); + while (k > 0 && so[k - 1]->mSize < obj->mSize) + { + so[k] = so[k - 1]; + k--; + } + so[k] = obj; + } + } + + for (int i = 0; i < so.Size(); i++) + { + const LinkerObject* obj = so[i]; + fprintf(file, "%04x (%04x) : %s, %s:%s\n", obj->mAddress, obj->mSize, obj->mIdent->mString, LinkerObjectTypeNames[obj->mType], obj->mSection->mIdent->mString); + } + fclose(file); return true; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 37f60cc..7da5edd 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -18844,6 +18844,63 @@ void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins) mIns[0].mLive |= LIVE_CPU_REG_C; } +bool NativeCodeBasicBlock::ShortcutBlockExit(void) +{ + bool changed = false; + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead && mTrueJump && mFalseJump && !mTrueJump->mLoopHead && !mFalseJump->mLoopHead) + { + for (int i = 0; i < mTrueJump->mEntryBlocks.Size(); i++) + { + NativeCodeBasicBlock* eblock = mTrueJump->mEntryBlocks[i]; + if (eblock != this) + { + if (eblock->mTrueJump == mTrueJump && eblock->mFalseJump == mFalseJump && eblock->mBranch == mBranch) + { + int n = mIns.Size(), m = eblock->mIns.Size(); + if (m > 0 && n >= m) + { + while (m > 0 && mIns[n - 1].IsSame(eblock->mIns[m - 1])) + { + n--; + m--; + } + + if (m == 0) + { + mTrueJump->mNumEntries--; + mTrueJump->mEntryBlocks.RemoveAll(this); + mFalseJump->mNumEntries--; + mFalseJump->mEntryBlocks.RemoveAll(this); + mFalseJump = nullptr; + mTrueJump = eblock; + eblock->mNumEntries++; + eblock->mEntryBlocks.Push(this); + + mIns.SetSize(n); + mBranch = ASMIT_JMP; + changed = true; + break; + } + } + } + } + } + } + + if (mTrueJump && mTrueJump->ShortcutBlockExit()) + changed = true; + if (mFalseJump && mFalseJump->ShortcutBlockExit()) + changed = true; + + } + + return changed; +} + bool NativeCodeBasicBlock::PropagateSinglePath(void) { bool changed = false; @@ -41965,7 +42022,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "mat4_mmul"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "cursor_joy_exit"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; @@ -42634,7 +42691,7 @@ void NativeCodeProcedure::Optimize(void) ResetPatched(); mEntryBlock->CheckVisited(); } - + } while (bchanged); } @@ -42892,6 +42949,14 @@ void NativeCodeProcedure::Optimize(void) if (mEntryBlock->PropagateSinglePath()) changed = true; } + + if (step > 4) + { + ResetVisited(); + if (mEntryBlock->ShortcutBlockExit()) + changed = true; + } + #endif #if _DEBUG diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 2319579..e32638d 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -515,6 +515,7 @@ public: bool IsExitXRegZP(int addr, int& index) const; bool IsExitARegZP(int addr, int& index) const; + bool ShortcutBlockExit(void); bool PropagateSinglePath(void); bool CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock * nblock, const NativeCodeBasicBlock* fblock = nullptr) const;