More integer value range optimizations

This commit is contained in:
drmortalwombat 2021-12-22 12:58:17 +01:00
parent 05a6c71698
commit 183864208f
6 changed files with 298 additions and 21 deletions

View File

@ -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;
}

View File

@ -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

94
autotest/loopboundtest.c Normal file
View File

@ -0,0 +1,94 @@
#include <assert.h>
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;
}

View File

@ -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");

View File

@ -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;

View File

@ -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 &&