Optimize sprite multiplexer
This commit is contained in:
parent
1d337f1244
commit
1e0450cd8a
|
@ -8,12 +8,18 @@
|
|||
volatile char npos = 1, tpos = 0;
|
||||
volatile byte rirq_count;
|
||||
|
||||
byte rasterIRQRows[NUM_IRQS];
|
||||
byte rasterIRQIndex[NUM_IRQS];
|
||||
byte rasterIRQRows[NUM_IRQS + 1];
|
||||
byte rasterIRQIndex[NUM_IRQS + 1];
|
||||
#ifdef ZPAGE_IRQS
|
||||
__zeropage
|
||||
#endif
|
||||
byte rasterIRQNext[NUM_IRQS + 1];
|
||||
byte rasterIRQLow[NUM_IRQS];
|
||||
byte rasterIRQHigh[NUM_IRQS];
|
||||
|
||||
#ifdef ZPAGE_IRQS
|
||||
__zeropage
|
||||
#endif
|
||||
byte nextIRQ;
|
||||
|
||||
__asm irq0
|
||||
|
@ -32,7 +38,7 @@ l1:
|
|||
cmp #$ff
|
||||
beq e1
|
||||
|
||||
ldy rasterIRQIndex, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
tax
|
||||
lda rasterIRQLow, y
|
||||
sta ji + 1
|
||||
|
@ -59,7 +65,6 @@ ji:
|
|||
sty $d012
|
||||
|
||||
ex:
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
|
@ -111,7 +116,7 @@ l1:
|
|||
cmp #$ff
|
||||
beq e1
|
||||
|
||||
ldy rasterIRQIndex, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
tax
|
||||
lda rasterIRQLow, y
|
||||
sta ji + 1
|
||||
|
@ -182,7 +187,7 @@ l1:
|
|||
cmp #$ff
|
||||
beq e1
|
||||
|
||||
ldy rasterIRQIndex, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
tax
|
||||
lda rasterIRQLow, y
|
||||
sta ji + 1
|
||||
|
@ -376,14 +381,21 @@ void rirq_clear(byte n)
|
|||
rasterIRQRows[n] = 255;
|
||||
}
|
||||
|
||||
void rirq_init_kernal(void)
|
||||
void rirq_init_tables(void)
|
||||
{
|
||||
for(byte i=0; i<NUM_IRQS; i++)
|
||||
{
|
||||
rasterIRQRows[i] = 255;
|
||||
rasterIRQIndex[i] = i;
|
||||
rasterIRQIndex[i + 1] = i;
|
||||
}
|
||||
rasterIRQIndex[0] = NUM_IRQS;
|
||||
rasterIRQRows[NUM_IRQS] = 0;
|
||||
rasterIRQNext[NUM_IRQS] = 255;
|
||||
}
|
||||
|
||||
void rirq_init_kernal(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
|
@ -400,12 +412,7 @@ void rirq_init_kernal(void)
|
|||
|
||||
void rirq_init_io(void)
|
||||
{
|
||||
for(byte i=0; i<NUM_IRQS; i++)
|
||||
{
|
||||
rasterIRQRows[i] = 255;
|
||||
rasterIRQIndex[i] = i;
|
||||
}
|
||||
rasterIRQNext[NUM_IRQS] = 255;
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
|
@ -422,12 +429,7 @@ void rirq_init_io(void)
|
|||
|
||||
void rirq_init_memmap(void)
|
||||
{
|
||||
for(byte i=0; i<NUM_IRQS; i++)
|
||||
{
|
||||
rasterIRQRows[i] = 255;
|
||||
rasterIRQIndex[i] = i;
|
||||
}
|
||||
rasterIRQNext[NUM_IRQS] = 255;
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
|
@ -458,6 +460,27 @@ void rirq_wait(void)
|
|||
|
||||
void rirq_sort(void)
|
||||
{
|
||||
#if 1
|
||||
byte maxr = rasterIRQRows[rasterIRQIndex[1]];
|
||||
for(byte i = 2; i<NUM_IRQS + 1; i++)
|
||||
{
|
||||
byte ri = rasterIRQIndex[i];
|
||||
byte rr = rasterIRQRows[ri];
|
||||
if (rr < maxr)
|
||||
{
|
||||
rasterIRQIndex[i] = rasterIRQIndex[i - 1];
|
||||
byte j = i, rj;
|
||||
while (rr < rasterIRQRows[(rj = rasterIRQIndex[j - 2])])
|
||||
{
|
||||
rasterIRQIndex[j - 1] = rj;
|
||||
j--;
|
||||
}
|
||||
rasterIRQIndex[j - 1] = ri;
|
||||
}
|
||||
else
|
||||
maxr = rr;
|
||||
}
|
||||
#else
|
||||
for(byte i = 1; i<NUM_IRQS; i++)
|
||||
{
|
||||
byte ri = rasterIRQIndex[i];
|
||||
|
@ -470,9 +493,9 @@ void rirq_sort(void)
|
|||
}
|
||||
rasterIRQIndex[j] = ri;
|
||||
}
|
||||
|
||||
#endif
|
||||
for(sbyte i=NUM_IRQS-1; i>=0; i--)
|
||||
rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i]];
|
||||
rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i + 1]];
|
||||
|
||||
npos++;
|
||||
byte yp = rasterIRQNext[nextIRQ];
|
||||
|
|
|
@ -243,6 +243,7 @@ void vspr_update(void)
|
|||
{
|
||||
char xymask = 0;
|
||||
volatile char * vsprs = vspriteScreen;
|
||||
char sypos[VSPRITES_MAX];
|
||||
|
||||
#pragma unroll(full)
|
||||
for(char ui=0; ui<8; ui++)
|
||||
|
@ -254,33 +255,39 @@ void vspr_update(void)
|
|||
xymask = ((unsigned)xymask | (vspriteXHigh[ri] << 8)) >> 1;
|
||||
vic.spr_pos[ui].x = vspriteXLow[ri];
|
||||
vic.spr_pos[ui].y = vspriteYLow[ri];
|
||||
sypos[ui] = vspriteYLow[ri];
|
||||
}
|
||||
|
||||
vic.spr_msbx = xymask;
|
||||
|
||||
#pragma unroll(full)
|
||||
bool done = false;
|
||||
|
||||
for(char ti=0; ti<VSPRITES_MAX - 8; ti++)
|
||||
{
|
||||
if (spriteYPos[ti + 8] < 250)
|
||||
byte ri = spriteOrder[ti + 8];
|
||||
if (!done && vspriteYLow[ri] < 250)
|
||||
{
|
||||
char m = 1 << (ti & 7);
|
||||
|
||||
byte ri = spriteOrder[ti + 8];
|
||||
|
||||
xymask |= m;
|
||||
if (!vspriteXHigh[ri])
|
||||
if (!(vspriteXHigh[ri] & 1))
|
||||
xymask ^= m;
|
||||
|
||||
rirq_data(spirq + ti, 2, vspriteYLow[ri]);
|
||||
rirq_data(spirq + ti, 0, vspriteColor[ri]);
|
||||
rirq_data(spirq + ti, 1, vspriteXLow[ri]);
|
||||
rirq_data(spirq + ti, 2, vspriteYLow[ri]);
|
||||
rirq_data(spirq + ti, 3, vspriteImage[ri]);
|
||||
|
||||
rirq_data(spirq + ti, 4, xymask);
|
||||
rirq_move(ti, spriteYPos[ti + 1] + 23);
|
||||
rirq_move(ti, sypos[ti] + 23);
|
||||
sypos[ti + 8] = vspriteYLow[ri];
|
||||
}
|
||||
else
|
||||
{
|
||||
rirq_clear(ti);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15797,6 +15797,230 @@ bool NativeCodeBasicBlock::OptimizeXYPairUsage(void)
|
|||
return changed;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::MoveImmediateStoreUp(int at)
|
||||
{
|
||||
bool usex = mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
|
||||
bool usey = mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;
|
||||
|
||||
int val = mIns[at].mAddress;
|
||||
int i = at;
|
||||
while (i > 0)
|
||||
{
|
||||
i--;
|
||||
if (mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == val)
|
||||
{
|
||||
if (mIns[i].mType == ASMIT_LDA)
|
||||
{
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
|
||||
mIns.Remove(at + 1, 2);
|
||||
return true;
|
||||
}
|
||||
else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_STX, mIns[at + 1].mMode))
|
||||
{
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STX, mIns[at + 1]));
|
||||
mIns.Remove(at + 1, 2);
|
||||
return true;
|
||||
}
|
||||
else if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_STY, mIns[at + 1].mMode))
|
||||
{
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STY, mIns[at + 1]));
|
||||
mIns.Remove(at + 1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIns[i].MayReference(mIns[at + 1]))
|
||||
return false;
|
||||
else if (usex && mIns[i].ChangesXReg())
|
||||
return false;
|
||||
else if (usey && mIns[i].ChangesYReg())
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::MoveImmediateStoreDown(int at)
|
||||
{
|
||||
bool usex = mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
|
||||
bool usey = mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;
|
||||
|
||||
int val = mIns[at].mAddress;
|
||||
int i = at + 2;
|
||||
while (i < mIns.Size())
|
||||
{
|
||||
if (mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == val)
|
||||
{
|
||||
if (mIns[i].mType == ASMIT_LDA)
|
||||
{
|
||||
if (usex)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_X;
|
||||
}
|
||||
else if (usey)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Y;
|
||||
}
|
||||
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
|
||||
mIns.Remove(at, 2);
|
||||
return true;
|
||||
}
|
||||
else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_STX, mIns[at + 1].mMode))
|
||||
{
|
||||
if (usey)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Y;
|
||||
}
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STX, mIns[at + 1]));
|
||||
mIns.Remove(at, 2);
|
||||
return true;
|
||||
}
|
||||
else if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_STY, mIns[at + 1].mMode))
|
||||
{
|
||||
if (usex)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_X;
|
||||
}
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STY, mIns[at + 1]));
|
||||
mIns.Remove(at, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIns[i].MayReference(mIns[at + 1]))
|
||||
return false;
|
||||
else if (usex && mIns[i].ChangesXReg())
|
||||
return false;
|
||||
else if (usey && mIns[i].ChangesYReg())
|
||||
return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::RecycleImmediates(void)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
CheckLive();
|
||||
|
||||
for (int i = 0; i + 1 < mIns.Size(); i++)
|
||||
{
|
||||
NativeCodeInstruction& ins(mIns[i]);
|
||||
if (mIns[i].mMode == ASMIM_IMMEDIATE)
|
||||
{
|
||||
if ((mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
|
||||
(mIns[i].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) ||
|
||||
(mIns[i].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z))))
|
||||
{
|
||||
if (MoveImmediateStoreDown(i) || MoveImmediateStoreUp(i))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckLive();
|
||||
|
||||
if (mTrueJump && mTrueJump->RecycleImmediates())
|
||||
changed = true;
|
||||
|
||||
if (mFalseJump && mFalseJump->RecycleImmediates())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::MoveLoadStoreDown(int at)
|
||||
{
|
||||
bool usex =
|
||||
mIns[at + 0].mMode == ASMIM_ABSOLUTE_X || mIns[at + 0].mMode == ASMIM_INDIRECT_X || mIns[at + 0].mMode == ASMIM_ZERO_PAGE_X ||
|
||||
mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
|
||||
bool usey =
|
||||
mIns[at + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 0].mMode == ASMIM_INDIRECT_Y || mIns[at + 0].mMode == ASMIM_ZERO_PAGE_Y ||
|
||||
mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;
|
||||
|
||||
int i = at + 2;
|
||||
while (i < mIns.Size())
|
||||
{
|
||||
if ((mIns[i].SameEffectiveAddress(mIns[at + 0]) || mIns[i].SameEffectiveAddress(mIns[at + 1])) && mIns[i].mType == ASMIT_LDA)
|
||||
{
|
||||
if (usex)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_X;
|
||||
}
|
||||
else if (usey)
|
||||
{
|
||||
for (int j = at; j <= i; j++)
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Y;
|
||||
}
|
||||
|
||||
mIns.Remove(i);
|
||||
if (i != at + 2)
|
||||
{
|
||||
mIns.Insert(i + 0, NativeCodeInstruction(mIns[at + 0].mIns, ASMIT_LDA, mIns[at + 0]));
|
||||
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
|
||||
mIns.Remove(at, 2);
|
||||
}
|
||||
else
|
||||
mIns[at + 1].mLive |= LIVE_CPU_REG_A;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIns[i].MayReference(mIns[at + 1]) || mIns[at].MayBeChangedOnAddress(mIns[i]))
|
||||
return false;
|
||||
else if (usex && mIns[i].ChangesXReg())
|
||||
return false;
|
||||
else if (usey && mIns[i].ChangesYReg())
|
||||
return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::RecycleLoadStore(void)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
CheckLive();
|
||||
|
||||
for (int i = 0; i + 1 < mIns.Size(); i++)
|
||||
{
|
||||
NativeCodeInstruction& ins(mIns[i]);
|
||||
if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
|
||||
!mIns[i].MayBeChangedOnAddress(mIns[i + 1]) && !(mIns[i].mFlags & NCIF_VOLATILE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
|
||||
{
|
||||
if (MoveLoadStoreDown(i))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
CheckLive();
|
||||
|
||||
if (mTrueJump && mTrueJump->RecycleLoadStore())
|
||||
changed = true;
|
||||
|
||||
if (mFalseJump && mFalseJump->RecycleLoadStore())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
void NativeCodeBasicBlock::BuildUseChangeSets(int start, int end, unsigned & used, unsigned & changed, uint32 & flags)
|
||||
|
@ -15825,6 +16049,45 @@ void NativeCodeBasicBlock::BuildUseChangeSets(int start, int end, unsigned & use
|
|||
}
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::CanSwapInstructions(int at)
|
||||
{
|
||||
if (mIns[at].RequiresAccu() && mIns[at + 1].ChangesAccu())
|
||||
return false;
|
||||
if (mIns[at].RequiresXReg() && mIns[at + 1].ChangesXReg())
|
||||
return false;
|
||||
if (mIns[at].RequiresYReg() && mIns[at + 1].ChangesYReg())
|
||||
return false;
|
||||
if (mIns[at].RequiresCarry() && mIns[at + 1].ChangesCarry())
|
||||
return false;
|
||||
|
||||
if (mIns[at + 1].RequiresAccu() && mIns[at].ChangesAccu())
|
||||
return false;
|
||||
if (mIns[at + 1].RequiresXReg() && mIns[at].ChangesXReg())
|
||||
return false;
|
||||
if (mIns[at + 1].RequiresYReg() && mIns[at].ChangesYReg())
|
||||
return false;
|
||||
if (mIns[at + 1].RequiresCarry() && mIns[at].ChangesCarry())
|
||||
return false;
|
||||
|
||||
if ((mIns[at + 1].mLive & LIVE_CPU_REG_A) && mIns[at].ChangesAccu())
|
||||
return false;
|
||||
if ((mIns[at + 1].mLive & LIVE_CPU_REG_X) && mIns[at].ChangesXReg())
|
||||
return false;
|
||||
if ((mIns[at + 1].mLive & LIVE_CPU_REG_Y) && mIns[at].ChangesYReg())
|
||||
return false;
|
||||
if ((mIns[at + 1].mLive & LIVE_CPU_REG_C) && mIns[at].ChangesCarry())
|
||||
return false;
|
||||
if ((mIns[at + 1].mLive & LIVE_CPU_REG_Z) && mIns[at].ChangesZFlag())
|
||||
return false;
|
||||
|
||||
if (mIns[at].MayBeChangedOnAddress(mIns[at + 1]) ||
|
||||
mIns[at + 1].MayBeChangedOnAddress(mIns[at]) ||
|
||||
mIns[at + 1].MayReference(mIns[at]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::CanExchangeSegments(int start, int mid, int end)
|
||||
{
|
||||
unsigned usedFront, changedFront, usedBack, changedBack;
|
||||
|
@ -16613,6 +16876,92 @@ bool NativeCodeBasicBlock::Split16BitLoopCount(NativeCodeProcedure* proc)
|
|||
return changed;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::CrossBlockFlagsForwarding(void)
|
||||
{
|
||||
bool changed = false;
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
int i = mIns.Size() - 1;
|
||||
while (i >= 0)
|
||||
{
|
||||
if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
|
||||
{
|
||||
int j = i - 1;
|
||||
while (j >= 0 && !mIns[j].ChangesZFlag())
|
||||
j--;
|
||||
if (j >= 0)
|
||||
{
|
||||
if (mIns[j].ChangesAccuAndFlag())
|
||||
{
|
||||
while (j < i)
|
||||
{
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Z;
|
||||
j++;
|
||||
}
|
||||
mIns[i].mType = ASMIT_NOP;
|
||||
mIns[i].mMode = ASMIM_IMPLIED;
|
||||
changed = true;
|
||||
}
|
||||
else if (j > 0 && mIns[j - 1].ChangesAccuAndFlag() && CanSwapInstructions(j - 1))
|
||||
{
|
||||
int live = mIns[j].mLive | mIns[j - 1].mLive;
|
||||
mIns[j].mLive |= live;
|
||||
mIns[j - 1].mLive |= live;
|
||||
|
||||
NativeCodeInstruction ins(mIns[j]);
|
||||
mIns[j] = mIns[j - 1];
|
||||
mIns[j - 1] = ins;
|
||||
|
||||
while (j < i)
|
||||
{
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Z;
|
||||
j++;
|
||||
}
|
||||
|
||||
mIns[i].mType = ASMIT_NOP;
|
||||
mIns[i].mMode = ASMIM_IMPLIED;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j = 0;
|
||||
while (j < mEntryBlocks.Size() && mEntryBlocks[j]->mIns.Size() > 0 && mEntryBlocks[j]->mIns.Last().ChangesAccuAndFlag())
|
||||
j++;
|
||||
if (j == mEntryBlocks.Size())
|
||||
{
|
||||
for (int j = 0; j < mEntryBlocks.Size(); j++)
|
||||
mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Z;
|
||||
mEntryRequiredRegs += CPU_REG_Z;
|
||||
|
||||
j = 0;
|
||||
while (j < i)
|
||||
{
|
||||
mIns[j].mLive |= LIVE_CPU_REG_Z;
|
||||
j++;
|
||||
}
|
||||
mIns[i].mType = ASMIT_NOP;
|
||||
mIns[i].mMode = ASMIM_IMPLIED;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
if (mTrueJump && mTrueJump->CrossBlockFlagsForwarding())
|
||||
changed = true;
|
||||
if (mFalseJump && mFalseJump->CrossBlockFlagsForwarding())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
bool NativeCodeBasicBlock::LoopRegisterWrapAround(void)
|
||||
{
|
||||
bool changed = false;
|
||||
|
@ -16778,6 +17127,117 @@ bool NativeCodeBasicBlock::EliminateDeadLoops(void)
|
|||
return changed;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::SinglePathRegisterForwardY(NativeCodeBasicBlock* path, int yreg)
|
||||
{
|
||||
if (path && path->mNumEntries == 1 && path->mTrueJump && !path->mFalseJump && !path->ChangesYReg() && !path->ChangesZeroPage(yreg))
|
||||
{
|
||||
NativeCodeBasicBlock* mblock = path->mTrueJump;
|
||||
|
||||
if (mblock && mblock->mIns.Size() && mblock->mIns[0].mType == ASMIT_LDY && mblock->mIns[0].mMode == ASMIM_ZERO_PAGE && mblock->mIns[0].mAddress == yreg)
|
||||
{
|
||||
bool fail = false;
|
||||
for (int i = 0; i < mblock->mEntryBlocks.Size(); i++)
|
||||
{
|
||||
NativeCodeBasicBlock* eblock = mblock->mEntryBlocks[i];
|
||||
if (eblock != path && eblock->mFalseJump)
|
||||
{
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail)
|
||||
{
|
||||
for (int i = 0; i < mblock->mEntryBlocks.Size(); i++)
|
||||
{
|
||||
NativeCodeBasicBlock* eblock = mblock->mEntryBlocks[i];
|
||||
if (eblock != path)
|
||||
{
|
||||
eblock->mIns.Push(mblock->mIns[0]);
|
||||
eblock->mExitRequiredRegs += CPU_REG_Y;
|
||||
}
|
||||
}
|
||||
|
||||
mblock->mEntryRequiredRegs += CPU_REG_Y;
|
||||
mExitRequiredRegs += CPU_REG_Y;
|
||||
for (int i = 0; i < path->mIns.Size(); i++)
|
||||
path->mIns[i].mLive |= LIVE_CPU_REG_Y;
|
||||
path->mEntryRequiredRegs += CPU_REG_Y;
|
||||
path->mExitRequiredRegs += CPU_REG_Y;
|
||||
int i = mIns.Size() - 1;
|
||||
while (i >= 0 && !(mIns[i].mLive & LIVE_CPU_REG_Y))
|
||||
{
|
||||
mIns[i].mLive |= LIVE_CPU_REG_Y;
|
||||
i--;
|
||||
}
|
||||
mblock->mIns.Remove(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::SinglePathRegisterForward(void)
|
||||
{
|
||||
bool changed = false;
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
if (mFalseJump)
|
||||
{
|
||||
int areg = -1, xreg = -1, yreg = -1;
|
||||
|
||||
for (int i = 0; i < mIns.Size(); i++)
|
||||
{
|
||||
NativeCodeInstruction& ins(mIns[i]);
|
||||
|
||||
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
|
||||
{
|
||||
if (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA)
|
||||
areg = mIns[i].mAddress;
|
||||
else if (mIns[i].mType == ASMIT_LDX || mIns[i].mType == ASMIT_STX)
|
||||
xreg = mIns[i].mAddress;
|
||||
else if (mIns[i].mType == ASMIT_LDY || mIns[i].mType == ASMIT_STY)
|
||||
yreg = mIns[i].mAddress;
|
||||
else if (mIns[i].ChangesAddress())
|
||||
{
|
||||
if (mIns[i].mAddress == areg)
|
||||
areg = -1;
|
||||
if (mIns[i].mAddress == xreg)
|
||||
xreg = -1;
|
||||
if (mIns[i].mAddress == yreg)
|
||||
yreg = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (areg >= 0 && (mIns[i].ChangesAccu() || mIns[i].ChangesZeroPage(areg)))
|
||||
areg = -1;
|
||||
if (xreg >= 0 && (mIns[i].ChangesXReg() || mIns[i].ChangesZeroPage(xreg)))
|
||||
xreg = -1;
|
||||
if (yreg >= 0 && (mIns[i].ChangesYReg() || mIns[i].ChangesZeroPage(yreg)))
|
||||
yreg = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (yreg >= 0)
|
||||
{
|
||||
if (SinglePathRegisterForwardY(mTrueJump, yreg) || SinglePathRegisterForwardY(mFalseJump, yreg))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mTrueJump && mTrueJump->SinglePathRegisterForward())
|
||||
changed = true;
|
||||
if (mFalseJump && mFalseJump->SinglePathRegisterForward())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::CrossBlockStoreLoadBypass(NativeCodeProcedure* proc)
|
||||
{
|
||||
|
@ -18485,6 +18945,40 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc)
|
|||
|
||||
}
|
||||
#endif
|
||||
if (mFalseJump && mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump && mTrueJump->mNumEntries == 1)
|
||||
{
|
||||
int sz = mIns.Size();
|
||||
if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_INX)
|
||||
{
|
||||
NativeCodeBasicBlock* eblock = mTrueJump->mTrueJump;
|
||||
int esz = eblock->mIns.Size();
|
||||
int i = 0;
|
||||
while (i < esz && !eblock->mIns[i].ReferencesXReg())
|
||||
i++;
|
||||
if (i < esz && eblock->mIns[i].mType == ASMIT_TXA && !(eblock->mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
|
||||
{
|
||||
if (i + 2 < esz && eblock->mIns[i + 1].mType == ASMIT_CLC && eblock->mIns[i + 2].mType == ASMIT_ADC && !(eblock->mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
|
||||
{
|
||||
if (eblock->mIns[i + 2].mMode == ASMIM_IMMEDIATE)
|
||||
{
|
||||
mIns[sz - 1].mAddress += eblock->mIns[i + 2].mAddress;
|
||||
eblock->mIns[i + 2].mType = ASMIT_NOP; eblock->mIns[i + 2].mMode = ASMIM_IMPLIED;
|
||||
changed = true;
|
||||
}
|
||||
else if (eblock->mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS)
|
||||
{
|
||||
mIns[sz - 1].mMode = ASMIM_IMMEDIATE_ADDRESS;
|
||||
mIns[sz - 1].mAddress += eblock->mIns[i + 2].mAddress;
|
||||
mIns[sz - 1].mFlags = eblock->mIns[i + 2].mFlags;
|
||||
mIns[sz - 1].mLinkerObject = eblock->mIns[i + 2].mLinkerObject;
|
||||
eblock->mIns[i + 2].mType = ASMIT_NOP; eblock->mIns[i + 2].mMode = ASMIM_IMPLIED;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mTrueJump && mTrueJump->ExpandADCToBranch(proc))
|
||||
changed = true;
|
||||
|
@ -23172,6 +23666,31 @@ bool NativeCodeBasicBlock::BypassRegisterConditionBlock(void)
|
|||
|
||||
if (cblock && cblock->mNumEntries == 1 && eblock->mNumEntries == 2)
|
||||
{
|
||||
if (cblock->mIns.Size() > 0 && !cblock->mEntryRequiredRegs[CPU_REG_Y] &&
|
||||
mIns.Last().mType == ASMIT_TAY && cblock->mIns.Last().mType == ASMIT_TAY && !(mIns.Last().mLive & LIVE_CPU_REG_Z))
|
||||
{
|
||||
eblock->mIns.Insert(0, NativeCodeInstruction(mIns.Last().mIns, ASMIT_TAY));
|
||||
mIns[mIns.Size() - 1].mType = ASMIT_NOP;
|
||||
cblock->mIns[cblock->mIns.Size() - 1].mType = ASMIT_NOP;
|
||||
|
||||
mExitRequiredRegs += CPU_REG_A;
|
||||
cblock->mExitRequiredRegs += CPU_REG_A;
|
||||
eblock->mEntryRequiredRegs += CPU_REG_A;
|
||||
changed = true;
|
||||
}
|
||||
if (cblock->mIns.Size() > 0 && !cblock->mEntryRequiredRegs[CPU_REG_X] &&
|
||||
mIns.Last().mType == ASMIT_TAX && cblock->mIns.Last().mType == ASMIT_TAX && !(mIns.Last().mLive & LIVE_CPU_REG_Z))
|
||||
{
|
||||
eblock->mIns.Insert(0, NativeCodeInstruction(mIns.Last().mIns, ASMIT_TAX));
|
||||
mIns[mIns.Size() - 1].mType = ASMIT_NOP;
|
||||
cblock->mIns[cblock->mIns.Size() - 1].mType = ASMIT_NOP;
|
||||
|
||||
mExitRequiredRegs += CPU_REG_A;
|
||||
cblock->mExitRequiredRegs += CPU_REG_A;
|
||||
eblock->mEntryRequiredRegs += CPU_REG_A;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (cblock->mIns.Size() >= 1 && eblock->mIns.Size() >= 1)
|
||||
{
|
||||
|
@ -31037,6 +31556,7 @@ bool NativeCodeBasicBlock::ValueForwarding(NativeCodeProcedure* proc, const Nati
|
|||
|
||||
if (target != mTrueJump)
|
||||
{
|
||||
mIns.Push(mTrueJump->mIns[0]);
|
||||
mTrueJump->mEntryBlocks.RemoveAll(this);
|
||||
mTrueJump->mNumEntries--;
|
||||
target->mEntryBlocks.Push(this);
|
||||
|
@ -39691,6 +40211,38 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
|
|||
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
|
||||
progress = true;
|
||||
}
|
||||
else if (
|
||||
(mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) &&
|
||||
(mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
|
||||
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 1].mLive & LIVE_MEM) &&
|
||||
mIns[i + 2].mType == ASMIT_STA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
|
||||
(mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
|
||||
(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) != (LIVE_CPU_REG_X | LIVE_CPU_REG_Y))
|
||||
{
|
||||
if (mIns[i + 2].mLive & LIVE_CPU_REG_X)
|
||||
{
|
||||
if (mIns[i + 0].mType == ASMIT_INC)
|
||||
mIns[i + 1].mType = ASMIT_INY;
|
||||
else
|
||||
mIns[i + 1].mType = ASMIT_DEY;
|
||||
|
||||
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
|
||||
mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
|
||||
mIns[i + 2].mType = ASMIT_STY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mIns[i + 0].mType == ASMIT_INC)
|
||||
mIns[i + 1].mType = ASMIT_INX;
|
||||
else
|
||||
mIns[i + 1].mType = ASMIT_DEX;
|
||||
|
||||
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
|
||||
mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
|
||||
mIns[i + 2].mType = ASMIT_STX;
|
||||
}
|
||||
progress = true;
|
||||
}
|
||||
else if (
|
||||
mIns[i + 0].mType == ASMIT_LDX &&
|
||||
mIns[i + 1].mType == ASMIT_TXA &&
|
||||
|
@ -43437,8 +43989,30 @@ void NativeCodeBasicBlock::BuildPlacement(ExpandingArray<NativeCodeBasicBlock*>&
|
|||
mTrueJump->BuildPlacement(placement);
|
||||
}
|
||||
}
|
||||
else if (mTrueJump)
|
||||
else if (mTrueJump && !mTrueJump->mPlaced)
|
||||
{
|
||||
if (mTrueJump->mLoopHead && mTrueJump->mFalseJump)
|
||||
{
|
||||
if (!mTrueJump->mFalseJump->mFalseJump && mTrueJump->mFalseJump->mTrueJump == mTrueJump)
|
||||
{
|
||||
if (!mTrueJump->mFalseJump->mPlaced && mTrueJump->mFalseJump->mCode.Size() + mTrueJump->mCode.Size() < 100)
|
||||
{
|
||||
mTrueJump->mFalseJump->mPlaced = true;
|
||||
mTrueJump->mFalseJump->mPlace = placement.Size();
|
||||
placement.Push(mTrueJump->mFalseJump);
|
||||
}
|
||||
}
|
||||
if (!mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == mTrueJump)
|
||||
{
|
||||
if (!mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mCode.Size() + mTrueJump->mCode.Size() < 100)
|
||||
{
|
||||
mTrueJump->mTrueJump->mPlaced = true;
|
||||
mTrueJump->mTrueJump->mPlace = placement.Size();
|
||||
placement.Push(mTrueJump->mTrueJump);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTrueJump->BuildPlacement(placement);
|
||||
}
|
||||
}
|
||||
|
@ -43889,7 +44463,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
|||
{
|
||||
mInterProc = proc;
|
||||
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "vspr_update");
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "main");
|
||||
|
||||
int nblocks = proc->mBlocks.Size();
|
||||
tblocks = new NativeCodeBasicBlock * [nblocks];
|
||||
|
@ -44683,6 +45257,7 @@ void NativeCodeProcedure::Optimize(void)
|
|||
#endif
|
||||
|
||||
#if 1
|
||||
|
||||
ResetVisited();
|
||||
if (mEntryBlock->PeepHoleOptimizer(this, step))
|
||||
changed = true;
|
||||
|
@ -45056,9 +45631,24 @@ void NativeCodeProcedure::Optimize(void)
|
|||
ResetVisited();
|
||||
if (mEntryBlock->CombineSameXY())
|
||||
changed = true;
|
||||
|
||||
ResetVisited();
|
||||
if (mEntryBlock->RecycleImmediates())
|
||||
changed = true;
|
||||
|
||||
ResetVisited();
|
||||
if (mEntryBlock->RecycleLoadStore())
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (step == 7)
|
||||
{
|
||||
ResetVisited();
|
||||
if (mEntryBlock->SinglePathRegisterForward())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (step == 7)
|
||||
{
|
||||
ResetVisited();
|
||||
|
@ -45411,6 +46001,9 @@ void NativeCodeProcedure::Optimize(void)
|
|||
NativeRegisterDataSet data;
|
||||
mEntryBlock->ValueForwarding(this, data, true, true);
|
||||
|
||||
ResetVisited();
|
||||
mEntryBlock->CrossBlockFlagsForwarding();
|
||||
|
||||
ResetVisited();
|
||||
mEntryBlock->PropagateZPAbsolute();
|
||||
|
||||
|
|
|
@ -611,6 +611,10 @@ public:
|
|||
bool CrossBlockStoreLoadBypass(NativeCodeProcedure* proc);
|
||||
bool EliminateDeadLoops(void);
|
||||
bool LoopRegisterWrapAround(void);
|
||||
bool CrossBlockFlagsForwarding(void);
|
||||
|
||||
bool SinglePathRegisterForwardY(NativeCodeBasicBlock* path, int yreg);
|
||||
bool SinglePathRegisterForward(void);
|
||||
|
||||
bool CanBytepassLoad(const NativeCodeInstruction& ains, int from = 0) const;
|
||||
bool CanHoistStore(const NativeCodeInstruction& ains) const;
|
||||
|
@ -620,8 +624,15 @@ public:
|
|||
bool MoveAccuTrainsDown(void);
|
||||
bool MoveAccuTrainDown(int end, int start);
|
||||
|
||||
bool MoveImmediateStoreUp(int at);
|
||||
bool MoveImmediateStoreDown(int at);
|
||||
bool RecycleImmediates(void);
|
||||
bool MoveLoadStoreDown(int at);
|
||||
bool RecycleLoadStore(void);
|
||||
|
||||
void BuildUseChangeSets(int start, int end, unsigned & used, unsigned & changed, uint32 & flags);
|
||||
bool CanExchangeSegments(int start, int mid, int end);
|
||||
bool CanSwapInstructions(int at);
|
||||
|
||||
bool CrossBlockXYPreservation(void);
|
||||
|
||||
|
|
Loading…
Reference in New Issue