From 183864208fbe8923e3d40207bcba510712f2dd01 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Wed, 22 Dec 2021 12:58:17 +0100 Subject: [PATCH] More integer value range optimizations --- autotest/arraytest.c | 7 +- autotest/autotest.bat | 3 + autotest/loopboundtest.c | 94 +++++++++++++++++++++ oscar64/InterCode.cpp | 143 +++++++++++++++++++++++++++++++- oscar64/InterCode.h | 2 + oscar64/NativeCodeGenerator.cpp | 70 ++++++++++++---- 6 files changed, 298 insertions(+), 21 deletions(-) create mode 100644 autotest/loopboundtest.c diff --git a/autotest/arraytest.c b/autotest/arraytest.c index 4ac510a..d1ef752 100644 --- a/autotest/arraytest.c +++ b/autotest/arraytest.c @@ -77,17 +77,16 @@ int main(void) a[i] = i % 10; al[i] = i % 10; } -#if 0 + assert(sum(a, 100) == 450); copy(b, a, 100); assert(sum(b, 100) == 450); reverse(c, a, 100); assert(sum(c, 100) == 450); assert(sumb(a, 100) == 450); -#endif copyb(b, a, 100); assert(sumb(b, 100) == 450); -#if 0 + reverseb(c, a, 100); assert(sumb(c, 100) == 450); @@ -98,6 +97,6 @@ int main(void) reversel(cl, al, 100); assert(suml(cl, 100) == 450); -#endif + return 0; } diff --git a/autotest/autotest.bat b/autotest/autotest.bat index 512bab6..0215a3d 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -69,6 +69,9 @@ if %errorlevel% neq 0 goto :error call :test loopdomtest.c if %errorlevel% neq 0 goto :error +call :test loopboundtest.c +if %errorlevel% neq 0 goto :error + call :test byteindextest.c if %errorlevel% neq 0 goto :error diff --git a/autotest/loopboundtest.c b/autotest/loopboundtest.c new file mode 100644 index 0000000..5322877 --- /dev/null +++ b/autotest/loopboundtest.c @@ -0,0 +1,94 @@ +#include + +struct S +{ + int a[100]; +}; + +int lts(S * s) +{ + int x = 0; + for(int i=0; i<100; i++) + x += s->a[i]; + return x; +} + +int les(S * s) +{ + int x = 0; + for(int i=0; i<=99; i++) + x += s->a[i]; + return x; +} + +int gts(S * s) +{ + int x = 0; + for(int i=100; i>0; i--) + x += s->a[i-1]; + return x; +} + +int ges(S * s) +{ + int x = 0; + for(int i=99; i>=0; i--) + x += s->a[i]; + return x; +} + +int ltu(S * s) +{ + unsigned x = 0; + for(int i=0; i<100; i++) + x += s->a[i]; + return x; +} + +int leu(S * s) +{ + unsigned x = 0; + for(int i=0; i<=99; i++) + x += s->a[i]; + return x; +} + +int gtu(S * s) +{ + unsigned x = 0; + for(int i=100; i>0; i--) + x += s->a[i-1]; + return x; +} + +int geu(S * s) +{ + unsigned x = 0; + for(int i=100; i>=1; i--) + x += s->a[i-1]; + return x; +} + +int main(void) +{ + S s; + + int k = 0; + for(int i=0; i<100; i++) + { + int t = (i & 15) + 3; + s.a[i] = t; + k += t; + } + + assert(lts(&s) == k); + assert(les(&s) == k); + assert(gts(&s) == k); + assert(ges(&s) == k); + assert(ltu(&s) == k); + assert(leu(&s) == k); + assert(gtu(&s) == k); + assert(geu(&s) == k); + + return 0; +} diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 2a89375..f1d5362 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -1576,6 +1576,25 @@ bool InterOperand::IsUByte(void) const mRange.mMaxState == IntegerValueRange::S_BOUND && mRange.mMaxValue < 256; } +bool InterOperand::IsUnsigned(void) const +{ + if (mRange.mMinState == IntegerValueRange::S_BOUND && mRange.mMinValue >= 0 && mRange.mMaxState == IntegerValueRange::S_BOUND) + { + switch (mType) + { + case IT_INT8: + return mRange.mMaxValue < 128; + case IT_INT16: + return mRange.mMaxValue < 32768; + case IT_INT32: + return true; + } + } + + return false; +} + + bool InterOperand::IsEqual(const InterOperand& op) const { if (mType != op.mType || mTemp != op.mTemp) @@ -3290,6 +3309,33 @@ bool InterCodeBasicBlock::PropagateConstTemps(const GrowingInstructionPtrArray& return changed; } +void InterCodeBasicBlock::SimplifyIntegerRangeRelops(void) +{ + if (!mVisited) + { + mVisited = true; + +#if 1 + int sz = mInstructions.Size(); + if (sz >= 2 && mInstructions[sz - 1]->mCode == IC_BRANCH && mInstructions[sz - 2]->mCode == IC_RELATIONAL_OPERATOR && mInstructions[sz - 2]->mDst.mTemp == mInstructions[sz - 1]->mSrc[0].mTemp) + { + if (mInstructions[sz - 2]->mOperator == IA_CMPLS) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + if (mInstructions[sz - 2]->mSrc[1].IsUnsigned()) + mInstructions[sz - 2]->mOperator = IA_CMPLU; + } + } + } +#endif + if (mTrueJump) + mTrueJump->SimplifyIntegerRangeRelops(); + if (mFalseJump) + mFalseJump->SimplifyIntegerRangeRelops(); + } +} + bool InterCodeBasicBlock::BuildGlobalIntegerRangeSets(void) { bool changed = false; @@ -3638,6 +3684,42 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(void) mFalseValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; } } + else if (mInstructions[sz - 2]->mOperator == IA_CMPLES) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + mTrueValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + + mFalseValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst + 1; + } + } + else if (mInstructions[sz - 2]->mOperator == IA_CMPGS) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst + 1; + + mFalseValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + } + } + else if (mInstructions[sz - 2]->mOperator == IA_CMPGES) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + + mFalseValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst - 1; + } + } else if (mInstructions[sz - 2]->mOperator == IA_CMPLU) { if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) @@ -3648,8 +3730,62 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(void) mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; mTrueValueRange[t].mMinValue = 0; + if (mFalseValueRange[t].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[t].mMinValue >= 0) + { + mFalseValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + } + } + } + else if (mInstructions[sz - 2]->mOperator == IA_CMPLEU) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + mTrueValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMinValue = 0; + + if (mFalseValueRange[t].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[t].mMinValue >= 0) + { + mFalseValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst + 1; + } + } + } + else if (mInstructions[sz - 2]->mOperator == IA_CMPGU) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + if (mTrueValueRange[t].mMinState == IntegerValueRange::S_BOUND && mTrueValueRange[t].mMinValue >= 0) + { + mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst + 1; + } + + mFalseValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; mFalseValueRange[t].mMinState = IntegerValueRange::S_BOUND; - mFalseValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + mFalseValueRange[t].mMinValue = 0; + } + } + else if (mInstructions[sz - 2]->mOperator == IA_CMPGEU) + { + if (mInstructions[sz - 2]->mSrc[0].mTemp < 0) + { + int t = mInstructions[sz - 2]->mSrc[1].mTemp; + if (mTrueValueRange[t].mMinState == IntegerValueRange::S_BOUND && mTrueValueRange[t].mMinValue >= 0) + { + mTrueValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mTrueValueRange[t].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; + } + + mFalseValueRange[t].mMaxState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst - 1; + mFalseValueRange[t].mMinState = IntegerValueRange::S_BOUND; + mFalseValueRange[t].mMinValue = 0; } } } @@ -6493,6 +6629,11 @@ void InterCodeProcedure::Close(void) DisassembleDebug("Estimated value range"); + ResetVisited(); + mEntryBlock->SimplifyIntegerRangeRelops(); + + DisassembleDebug("Simplified range limited relational ops"); + MapVariables(); DisassembleDebug("mapped variabled"); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index e8df5fe..dc3e843 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -331,6 +331,7 @@ public: bool IsEqual(const InterOperand & op) const; bool IsUByte(void) const; + bool IsUnsigned(void) const; void Disassemble(FILE* file); }; @@ -504,6 +505,7 @@ public: void BuildLocalIntegerRangeSets(int num); void UpdateLocalIntegerRangeSets(void); bool BuildGlobalIntegerRangeSets(void); + void SimplifyIntegerRangeRelops(void); GrowingIntArray mEntryRenameTable; GrowingIntArray mExitRenameTable; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index debbcb8..e641546 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -5571,15 +5571,26 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { - NativeCodeBasicBlock* iblock = nproc->AllocateBlock(); - NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); + if (ins->mDst.IsUByte()) + { + if (ins->mSrc[0].mTemp >= 0 && !ins->mSrc[0].IsUByte() || ins->mSrc[1].mTemp >= 0 && !ins->mSrc[1].IsUByte()) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } + } + else + { + NativeCodeBasicBlock* iblock = nproc->AllocateBlock(); + NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); - this->Close(eblock, iblock, ASMIT_BNE); + this->Close(eblock, iblock, ASMIT_BNE); - iblock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, treg + 1)); + iblock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, treg + 1)); - iblock->Close(eblock, nullptr, ASMIT_JMP); - return eblock; + iblock->Close(eblock, nullptr, ASMIT_JMP); + return eblock; + } } } else if (ins->mOperator == IA_ADD && InterTypeSize[ins->mDst.mType] == 1 && ( @@ -5614,7 +5625,12 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p insl = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff); insh = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff); if (sins0) + { + if (ins->mDst.IsUByte()) + insh = NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0); + LoadValueToReg(proc, sins0, treg, &insl, &insh); + } else { if (ins->mOperator == IA_ADD) @@ -5643,7 +5659,12 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p insl = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff); insh = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff); if (sins1) + { + if (ins->mDst.IsUByte()) + insh = NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0); + LoadValueToReg(proc, sins1, treg, &insl, &insh); + } else { if (ins->mOperator == IA_ADD) @@ -9060,10 +9081,20 @@ bool NativeCodeBasicBlock::MoveStoreXUp(int at) { if (mIns[at - 1].ChangesXReg() || mIns[at - 1].mType == ASMIT_STX) return done; - if ((mIns[at - 1].mMode == ASMIM_ZERO_PAGE || mIns[at - 1].mMode == ASMIM_INDIRECT_Y) && mIns[at - 1].mAddress == mIns[at].mAddress) - return done; - if (mIns[at - 1].mMode == ASMIM_INDIRECT_Y && mIns[at - 1].mAddress == mIns[at].mAddress + 1) - return done; + if (mIns[at].mMode == ASMIM_ZERO_PAGE) + { + if ((mIns[at - 1].mMode == ASMIM_ZERO_PAGE || mIns[at - 1].mMode == ASMIM_INDIRECT_Y) && mIns[at - 1].mAddress == mIns[at].mAddress) + return done; + if (mIns[at - 1].mMode == ASMIM_INDIRECT_Y && mIns[at - 1].mAddress == mIns[at].mAddress + 1) + return done; + } + else + { + if (mIns[at - 1].mMode == ASMIM_ABSOLUTE && mIns[at - 1].mLinkerObject == mIns[at].mLinkerObject && mIns[at - 1].mAddress == mIns[at].mAddress) + return done; + else if ((mIns[at - 1].mMode == ASMIM_ABSOLUTE_X || mIns[at - 1].mMode == ASMIM_ABSOLUTE_Y) && mIns[at - 1].mLinkerObject == mIns[at].mLinkerObject) + return done; + } mIns[at].mLive |= mIns[at - 1].mLive; @@ -10670,7 +10701,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) for (int i = 1; i + 1 < mIns.Size(); i++) { - if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE) + if (mIns[i].mType == ASMIT_STX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE)) { if (MoveStoreXUp(i)) changed = true; @@ -10849,15 +10880,11 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;; progress = true; } -#endif -#if 1 else if (mIns[i].mType == ASMIT_ROR && mIns[i].mMode == ASMIM_IMPLIED && (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0) { mIns[i].mType = ASMIT_LSR; progress = true; } -#endif -#if 1 else if (mIns[i].mType == ASMIT_ROL && mIns[i].mMode == ASMIM_IMPLIED && (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0) { mIns[i].mType = ASMIT_ASL; @@ -11595,7 +11622,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) else if ( mIns[i + 0].mMode != ASMIM_RELATIVE && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) && - mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 1].mAddress && + mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 2].mAddress && (mIns[i + 1].mType == ASMIT_DEC || mIns[i + 1].mType == ASMIT_INC)) { mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; @@ -11676,6 +11703,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 && + mIns[i + 1].mType == ASMIT_SEC && + mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x80 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + { + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } + #if 1 else if ( mIns[i + 0].mType == ASMIT_CLC &&