diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 0b574a4..ead4dac 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -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(); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 8002aa7..e58e0e1 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -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); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 7ba21e3..d87b84c 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -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]; diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 1c3a8c0..bdba3fe 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -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;