oscar64/oscar64/NativeCodeGenerator.cpp

53776 lines
1.7 MiB

#include "NativeCodeGenerator.h"
#include "CompilerTypes.h"
#define JUMP_TO_BRANCH 1
static bool CheckFunc;
static bool CheckCase;
static const int CPU_REG_A = 256;
static const int CPU_REG_X = 257;
static const int CPU_REG_Y = 258;
static const int CPU_REG_C = 259;
static const int CPU_REG_Z = 260;
static const int NUM_REGS = 261;
static const uint32 LIVE_CPU_REG_A = 0x00000001;
static const uint32 LIVE_CPU_REG_X = 0x00000002;
static const uint32 LIVE_CPU_REG_Y = 0x00000004;
static const uint32 LIVE_CPU_REG_C = 0x00000008;
static const uint32 LIVE_CPU_REG_Z = 0x00000010;
static const uint32 LIVE_CPU_REG = 0x0000001f;
static const uint32 LIVE_MEM = 0x00000020;
static const uint32 LIVE_ALL = 0x000000ff;
static int GlobalValueNumber = 0;
NativeRegisterData::NativeRegisterData(void)
: mMode(NRDM_UNKNOWN), mValue(GlobalValueNumber++), mMask(0)
{
}
void NativeRegisterData::Reset(void)
{
mMode = NRDM_UNKNOWN;
mValue = GlobalValueNumber++;
}
void NativeRegisterData::ResetMask(void)
{
mMask = 0;
}
bool NativeRegisterData::SameData(const NativeCodeInstruction& ins) const
{
if (ins.mMode == ASMIM_ZERO_PAGE)
return mMode == NRDM_ZERO_PAGE && mValue == ins.mAddress;
else if (ins.mMode == ASMIM_ABSOLUTE)
return mMode == NRDM_ABSOLUTE && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
else if (ins.mMode == ASMIM_ABSOLUTE_X)
return mMode == NRDM_ABSOLUTE_X && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
else if (ins.mMode == ASMIM_ABSOLUTE_Y)
return mMode == NRDM_ABSOLUTE_Y && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
else if (ins.mMode == ASMIM_INDIRECT_Y)
return mMode == NRDM_INDIRECT_Y && mValue == ins.mAddress;
else
return false;
}
bool NativeRegisterData::SameData(const NativeRegisterData& d) const
{
if (mMode != d.mMode)
return false;
switch (mMode)
{
case NRDM_UNKNOWN:
case NRDM_IMMEDIATE:
case NRDM_ZERO_PAGE:
return mValue == d.mValue;
case NRDM_IMMEDIATE_ADDRESS:
case NRDM_ABSOLUTE:
return mValue == d.mValue && mLinkerObject == d.mLinkerObject && mFlags == d.mFlags;
default:
return false;
}
}
void NativeRegisterDataSet::Reset(void)
{
for (int i = 0; i < NUM_REGS; i++)
mRegs[i].Reset();
}
void NativeRegisterDataSet::ResetMask(void)
{
for (int i = 0; i < NUM_REGS; i++)
mRegs[i].ResetMask();
}
void NativeRegisterDataSet::ResetCall(const NativeCodeInstruction& ins, int fastCallBase)
{
mRegs[CPU_REG_C].Reset();
mRegs[CPU_REG_Z].Reset();
mRegs[CPU_REG_A].Reset();
mRegs[CPU_REG_X].Reset();
mRegs[CPU_REG_Y].Reset();
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE ||
mRegs[i].mMode == NRDM_ABSOLUTE_X ||
mRegs[i].mMode == NRDM_ABSOLUTE_Y)
{
if (mRegs[i].mLinkerObject && mRegs[i].mLinkerObject->mVariable)
{
InterVariable* var = mRegs[i].mLinkerObject->mVariable;
if (ins.mLinkerObject && ins.mLinkerObject->mProc)
{
if (!(var->mLinkerObject->mFlags & LOBJF_LOCAL_VAR))
{
if (var->mIndex && var->mIndex < ins.mLinkerObject->mProc->mModule->mGlobalVars.Size() && var == ins.mLinkerObject->mProc->mModule->mGlobalVars[var->mIndex])
{
if (ins.mLinkerObject->mProc->ModifiesGlobal(var->mIndex))
mRegs[i].Reset();
}
else
mRegs[i].Reset();
}
}
else if (var->mAliased)
mRegs[i].Reset();
}
else
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
{
mRegs[i].Reset();
}
}
ResetWorkRegs();
if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
{
if (ins.mLinkerObject && ins.mLinkerObject->mProc)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
ResetZeroPage(i);
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
ResetZeroPage(i);
}
if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS + fastCallBase; i++)
if (ins.mLinkerObject->mZeroPageSet[i])
ResetZeroPage(i);
}
else
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS + fastCallBase; i++)
ResetZeroPage(i);
}
}
}
void NativeRegisterDataSet::ResetWorkRegs(void)
{
ResetZeroPage(BC_REG_WORK_Y);
ResetZeroPageRange(BC_REG_ADDR, 2);
ResetZeroPageRange(BC_REG_ACCU, 4);
ResetZeroPageRange(BC_REG_WORK, 8);
}
void NativeRegisterDataSet::ResetWorkMasks(void)
{
mRegs[BC_REG_WORK_Y].ResetMask();
mRegs[BC_REG_ADDR + 0].ResetMask();
mRegs[BC_REG_ADDR + 1].ResetMask();
for (int i = 0; i < 4; i++)
mRegs[BC_REG_ACCU + i].ResetMask();
for (int i = 0; i < 8; i++)
mRegs[BC_REG_WORK + i].ResetMask();
}
void NativeRegisterDataSet::ResetZeroPage(int addr)
{
mRegs[addr].Reset();
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ZERO_PAGE && mRegs[i].mValue == addr)
mRegs[i].Reset();
else if (mRegs[i].mMode == NRDM_INDIRECT_Y && (mRegs[i].mValue == addr || mRegs[i].mValue + 1 == addr))
mRegs[i].Reset();
}
}
void NativeRegisterDataSet::ResetZeroPageRange(int addr, int num)
{
for(int i=0; i<num; i++)
mRegs[addr + i].Reset();
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ZERO_PAGE && mRegs[i].mValue >= addr && mRegs[i].mValue < addr + num)
mRegs[i].Reset();
else if (mRegs[i].mMode == NRDM_INDIRECT_Y && mRegs[i].mValue + 1 >= addr && mRegs[i].mValue < addr + num)
mRegs[i].Reset();
}
}
int NativeRegisterDataSet::FindAbsolute(LinkerObject* linkerObject, int addr)
{
for (int i = 0; i < 256; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE && mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue == addr)
return i;
}
return -1;
}
void NativeRegisterDataSet::ResetAbsolute(LinkerObject* linkerObject, int addr)
{
for (int i = 0; i < NUM_REGS; i++)
{
if ((mRegs[i].mMode == NRDM_ABSOLUTE || mRegs[i].mMode == NRDM_ABSOLUTE_X || mRegs[i].mMode == NRDM_ABSOLUTE_Y)
&& mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue == addr)
mRegs[i].Reset();
else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
mRegs[i].Reset();
}
}
void NativeRegisterDataSet::ResetAbsoluteXY(LinkerObject* linkerObject, int addr)
{
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE)
{
if (mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue < addr + 256 && mRegs[i].mValue >= addr)
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_ABSOLUTE_X || mRegs[i].mMode == NRDM_ABSOLUTE_Y)
{
if (mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue < addr + 256 && mRegs[i].mValue + 256 > addr)
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
mRegs[i].Reset();
}
}
void NativeRegisterDataSet::ResetX(void)
{
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE_X)
mRegs[i].Reset();
}
}
void NativeRegisterDataSet::ResetY(void)
{
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE_Y || mRegs[i].mMode == NRDM_INDIRECT_Y )
mRegs[i].Reset();
}
}
void NativeRegisterDataSet::ResetIndirect(int reg)
{
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ABSOLUTE ||
mRegs[i].mMode == NRDM_ABSOLUTE_X ||
mRegs[i].mMode == NRDM_ABSOLUTE_Y)
{
if (reg != BC_REG_STACK || !mRegs[i].mLinkerObject)
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_INDIRECT_Y )
{
mRegs[i].Reset();
}
}
}
void NativeRegisterDataSet::IntersectMask(const NativeRegisterDataSet& set)
{
for (int i = 0; i < NUM_REGS; i++)
{
mRegs[i].mMask &= set.mRegs[i].mMask & ~(mRegs[i].mValue ^ set.mRegs[i].mValue);
}
}
void NativeRegisterDataSet::Intersect(const NativeRegisterDataSet& set)
{
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_UNKNOWN)
{
if (set.mRegs[i].mMode != NRDM_UNKNOWN || mRegs[i].mValue != set.mRegs[i].mValue)
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_IMMEDIATE)
{
if (set.mRegs[i].mMode != NRDM_IMMEDIATE || mRegs[i].mValue != set.mRegs[i].mValue)
mRegs[i].Reset();
}
else if (mRegs[i].mMode == NRDM_IMMEDIATE_ADDRESS)
{
if (set.mRegs[i].mMode != NRDM_IMMEDIATE_ADDRESS || mRegs[i].mValue != set.mRegs[i].mValue || mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject || mRegs[i].mFlags != set.mRegs[i].mFlags)
mRegs[i].Reset();
}
}
bool changed;
do
{
changed = false;
for (int i = 0; i < NUM_REGS; i++)
{
if (mRegs[i].mMode == NRDM_ZERO_PAGE)
{
if (set.mRegs[i].mMode != NRDM_ZERO_PAGE || mRegs[i].mValue != set.mRegs[i].mValue)
{
mRegs[i].Reset();
changed = true;
}
#if 0
else if (mRegs[mRegs[i].mValue].mValue != set.mRegs[set.mRegs[i].mValue].mValue)
{
mRegs[i].Reset();
changed = true;
}
#endif
}
else if (mRegs[i].mMode == NRDM_ABSOLUTE)
{
if (set.mRegs[i].mMode != NRDM_ABSOLUTE || mRegs[i].mValue != set.mRegs[i].mValue || mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject)
{
mRegs[i].Reset();
changed = true;
}
}
else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
{
if (set.mRegs[i].mMode != NRDM_INDIRECT_Y || mRegs[i].mValue != set.mRegs[i].mValue || !mRegs[CPU_REG_Y].SameData(set.mRegs[CPU_REG_Y]))
{
mRegs[i].Reset();
changed = true;
}
else
{
int reg = mRegs[i].mValue;
if (!mRegs[reg].SameData(set.mRegs[reg]) || !mRegs[reg + 1].SameData(set.mRegs[reg + 1]))
{
mRegs[i].Reset();
changed = true;
}
}
}
else if (mRegs[i].mMode == NRDM_ABSOLUTE_X)
{
if (set.mRegs[i].mMode != NRDM_ABSOLUTE_X ||
mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject ||
mRegs[i].mValue != set.mRegs[i].mValue ||
!mRegs[CPU_REG_X].SameData(set.mRegs[CPU_REG_X]))
{
mRegs[i].Reset();
changed = true;
}
}
else if (mRegs[i].mMode == NRDM_ABSOLUTE_Y)
{
if (set.mRegs[i].mMode != NRDM_ABSOLUTE_Y ||
mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject ||
mRegs[i].mValue != set.mRegs[i].mValue ||
!mRegs[CPU_REG_Y].SameData(set.mRegs[CPU_REG_Y]))
{
mRegs[i].Reset();
changed = true;
}
}
}
} while (changed);
}
ValueNumberingData::ValueNumberingData(void)
{
mIndex = GlobalValueNumber++;
mOffset = 0;
}
void ValueNumberingData::Reset(void)
{
mIndex = GlobalValueNumber++;
mOffset = 0;
}
bool ValueNumberingData::SameBase(const ValueNumberingData& d) const
{
return mIndex == d.mIndex;
}
void ValueNumberingDataSet::Reset(void)
{
for (int i = 0; i < 261; i++)
mRegs[i].Reset();
}
void ValueNumberingDataSet::ResetWorkRegs(void)
{
mRegs[BC_REG_WORK_Y].Reset();
mRegs[BC_REG_ADDR].Reset();
mRegs[BC_REG_ADDR + 1].Reset();
for (int i = 0; i < 4; i++)
mRegs[BC_REG_ACCU + i].Reset();
for (int i = 0; i < 8; i++)
mRegs[BC_REG_WORK + i].Reset();
}
void ValueNumberingDataSet::ResetCall(const NativeCodeInstruction& ins)
{
mRegs[CPU_REG_C].Reset();
mRegs[CPU_REG_Z].Reset();
mRegs[CPU_REG_A].Reset();
mRegs[CPU_REG_X].Reset();
mRegs[CPU_REG_Y].Reset();
ResetWorkRegs();
if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
{
if (ins.mLinkerObject && ins.mLinkerObject->mProc)
{
if (!(ins.mFlags & NCIF_FEXEC) && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
{
for (int i = 0; i < 256; i++)
if (ins.mLinkerObject->mZeroPageSet[i])
mRegs[i].Reset();
return;
}
for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
mRegs[i].Reset();
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
mRegs[i].Reset();
}
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
mRegs[i].Reset();
}
}
void ValueNumberingDataSet::Intersect(const ValueNumberingDataSet& set)
{
for (int i = 0; i < 261; i++)
{
if (mRegs[i].mIndex != set.mRegs[i].mIndex || mRegs[i].mOffset != set.mRegs[i].mOffset)
mRegs[i].Reset();
}
}
NativeCodeInstruction::NativeCodeInstruction(void)
: mIns(nullptr), mType(ASMIT_INV), mMode(ASMIM_IMPLIED), mAddress(0), mLinkerObject(nullptr), mFlags(NCIF_LOWER | NCIF_UPPER), mParam(0), mLive(LIVE_ALL)
{}
NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmInsType type, AsmInsMode mode, int64 address, LinkerObject* linkerObject, uint32 flags, int param)
: mIns(ins), mType(type), mMode(mode), mAddress(int(address)), mLinkerObject(linkerObject), mFlags(flags), mParam(param), mLive(LIVE_ALL)
{
if (mIns)
{
assert(mIns->mLocation.mFileName);
}
if (mode == ASMIM_IMMEDIATE_ADDRESS)
{
#if _DEBUG
assert(address >= 0);
#endif
assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
assert(HasAsmInstructionMode(mType, ASMIM_IMMEDIATE));
}
if (mode == ASMIM_IMMEDIATE)
{
assert(address >= 0 && address < 256);
}
if (mode == ASMIM_ZERO_PAGE)
{
assert(address >= 1 && address < 256);
}
}
NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmInsType type, const NativeCodeInstruction& addr)
: mIns(ins), mType(type), mMode(addr.mMode), mAddress(addr.mAddress), mLinkerObject(addr.mLinkerObject), mFlags(addr.mFlags), mParam(addr.mParam), mLive(LIVE_ALL)
{
if (mIns)
{
assert(mIns->mLocation.mFileName);
}
}
bool NativeCodeInstruction::IsUsedResultInstructions(NumberSet& requiredTemps)
{
bool used = false;
mLive = 0;
if (requiredTemps[CPU_REG_A])
mLive |= LIVE_CPU_REG_A;
if (requiredTemps[CPU_REG_X])
mLive |= LIVE_CPU_REG_X;
if (requiredTemps[CPU_REG_Y])
mLive |= LIVE_CPU_REG_Y;
if (requiredTemps[CPU_REG_Z])
mLive |= LIVE_CPU_REG_Z;
if (requiredTemps[CPU_REG_C])
mLive |= LIVE_CPU_REG_C;
if (mMode == ASMIM_ZERO_PAGE && requiredTemps[mAddress])
mLive |= LIVE_MEM;
if (mMode == ASMIM_INDIRECT_Y && (requiredTemps[mAddress] || requiredTemps[mAddress + 1]))
mLive |= LIVE_MEM;
if (mType == ASMIT_JSR)
{
requiredTemps -= CPU_REG_C;
requiredTemps -= CPU_REG_Z;
requiredTemps -= CPU_REG_A;
requiredTemps -= CPU_REG_X;
requiredTemps -= CPU_REG_Y;
if (mFlags & NCIF_USE_CPU_REG_A)
requiredTemps += CPU_REG_A;
if (mFlags & NCIF_USE_CPU_REG_X)
requiredTemps += CPU_REG_X;
if (mFlags & NCIF_USE_CPU_REG_Y)
requiredTemps += CPU_REG_Y;
if (mFlags & NCIF_RUNTIME)
{
for (int i = 0; i < 4; i++)
{
requiredTemps += BC_REG_ACCU + i;
requiredTemps += BC_REG_WORK + i;
}
if (mFlags & NCIF_USE_ZP_32_X)
{
for (int i = 0; i < 4; i++)
requiredTemps += mParam + i;
}
if (mFlags & NCIF_FEXEC)
{
requiredTemps += BC_REG_LOCALS;
requiredTemps += BC_REG_LOCALS + 1;
for(int i= BC_REG_FPARAMS; i< BC_REG_FPARAMS_END; i++)
requiredTemps += i;
}
}
else
{
for (int i = 0; i < 4; i++)
{
requiredTemps -= BC_REG_ACCU + i;
requiredTemps -= BC_REG_WORK + i;
}
if (mFlags & NICF_USE_WORKREGS)
{
for (int i = 0; i < 10; i++)
requiredTemps += BC_REG_WORK + i;
}
requiredTemps += BC_REG_LOCALS;
requiredTemps += BC_REG_LOCALS + 1;
if (mLinkerObject)
{
for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
{
for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++)
requiredTemps += mLinkerObject->mTemporaries[i] + j;
}
}
}
return true;
}
if (mType == ASMIT_RTS)
{
#if 1
if (mFlags & NCIF_USE_CPU_REG_A)
requiredTemps += CPU_REG_A;
if (mFlags & NCIF_LOWER)
{
requiredTemps += BC_REG_ACCU;
if (mFlags & NCIF_UPPER)
{
requiredTemps += BC_REG_ACCU + 1;
if (mFlags & NCIF_LONG)
{
requiredTemps += BC_REG_ACCU + 2;
requiredTemps += BC_REG_ACCU + 3;
}
}
}
#endif
#if 0
for (int i = 0; i < 4; i++)
{
requiredTemps += BC_REG_ACCU + i;
}
#endif
requiredTemps += BC_REG_STACK;
requiredTemps += BC_REG_STACK + 1;
requiredTemps += BC_REG_LOCALS;
requiredTemps += BC_REG_LOCALS + 1;
return true;
}
if (mType == ASMIT_BYTE)
return true;
// check side effects
switch (mType)
{
case ASMIT_STA:
case ASMIT_STX:
case ASMIT_STY:
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ROL:
case ASMIT_ROR:
if (mMode != ASMIM_IMPLIED && mMode != ASMIM_ZERO_PAGE)
used = true;
break;
case ASMIT_JSR:
case ASMIT_JMP:
case ASMIT_BEQ:
case ASMIT_BNE:
case ASMIT_BPL:
case ASMIT_BMI:
case ASMIT_BCC:
case ASMIT_BCS:
used = true;
break;
}
if (requiredTemps[CPU_REG_C])
{
switch (mType)
{
case ASMIT_CLC:
case ASMIT_SEC:
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_CMP:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_CPX:
case ASMIT_CPY:
used = true;
break;
}
}
if (requiredTemps[CPU_REG_Z])
{
switch (mType)
{
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
case ASMIT_LDA:
case ASMIT_LDX:
case ASMIT_LDY:
case ASMIT_BIT:
case ASMIT_INX:
case ASMIT_DEX:
case ASMIT_INY:
case ASMIT_DEY:
case ASMIT_TYA:
case ASMIT_TXA:
case ASMIT_TAY:
case ASMIT_TAX:
used = true;
break;
}
}
if (requiredTemps[CPU_REG_A])
{
switch (mType)
{
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_ASL:
case ASMIT_LSR:
if (mMode == ASMIM_IMPLIED)
used = true;
break;
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
case ASMIT_LDA:
case ASMIT_TXA:
case ASMIT_TYA:
used = true;
break;
}
}
if (requiredTemps[CPU_REG_X])
{
switch (mType)
{
case ASMIT_LDX:
case ASMIT_INX:
case ASMIT_DEX:
case ASMIT_TAX:
used = true;
break;
}
}
if (requiredTemps[CPU_REG_Y])
{
switch (mType)
{
case ASMIT_LDY:
case ASMIT_INY:
case ASMIT_DEY:
case ASMIT_TAY:
used = true;
break;
}
}
if (mMode == ASMIM_ZERO_PAGE)
{
switch (mType)
{
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_STA:
case ASMIT_STX:
case ASMIT_STY:
if (requiredTemps[mAddress])
used = true;
break;
}
}
if (used)
{
switch (mMode)
{
case ASMIM_ZERO_PAGE_X:
case ASMIM_INDIRECT_X:
case ASMIM_ABSOLUTE_X:
requiredTemps += CPU_REG_X;
break;
case ASMIM_ZERO_PAGE_Y:
case ASMIM_ABSOLUTE_Y:
requiredTemps += CPU_REG_Y;
break;
case ASMIM_INDIRECT_Y:
requiredTemps += CPU_REG_Y;
requiredTemps += mAddress;
requiredTemps += mAddress + 1;
break;
case ASMIM_IMMEDIATE:
if (mFlags & NICF_TMPREF)
{
if (mFlags & NCIF_LOWER)
requiredTemps += mAddress;
if (mFlags & NCIF_UPPER)
requiredTemps += mAddress + 1;
}
break;
}
// check carry flags
switch (mType)
{
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
requiredTemps += CPU_REG_C;
break;
case ASMIT_CMP:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_CLC:
case ASMIT_SEC:
requiredTemps -= CPU_REG_C;
break;
case ASMIT_BCC:
case ASMIT_BCS:
requiredTemps += CPU_REG_C;
break;
case ASMIT_BEQ:
case ASMIT_BNE:
case ASMIT_BPL:
case ASMIT_BMI:
requiredTemps += CPU_REG_Z;
break;
}
// check zero flags
switch (mType)
{
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
case ASMIT_LDA:
case ASMIT_LDX:
case ASMIT_LDY:
case ASMIT_BIT:
case ASMIT_TAY:
case ASMIT_TYA:
case ASMIT_TAX:
case ASMIT_TXA:
case ASMIT_INX:
case ASMIT_DEX:
case ASMIT_INY:
case ASMIT_DEY:
requiredTemps -= CPU_REG_Z;
break;
}
// check CPU register
switch (mType)
{
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_ASL:
case ASMIT_LSR:
if (mMode == ASMIM_IMPLIED)
requiredTemps += CPU_REG_A;
break;
case ASMIT_LDA:
requiredTemps -= CPU_REG_A;
break;
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
requiredTemps += CPU_REG_A;
break;
case ASMIT_LDX:
requiredTemps -= CPU_REG_X;
break;
case ASMIT_INX:
case ASMIT_DEX:
requiredTemps += CPU_REG_X;
break;
case ASMIT_LDY:
requiredTemps -= CPU_REG_Y;
break;
case ASMIT_INY:
case ASMIT_DEY:
requiredTemps += CPU_REG_Y;
break;
case ASMIT_CMP:
case ASMIT_STA:
requiredTemps += CPU_REG_A;
break;
case ASMIT_CPX:
case ASMIT_STX:
requiredTemps += CPU_REG_X;
break;
case ASMIT_CPY:
case ASMIT_STY:
requiredTemps += CPU_REG_Y;
break;
case ASMIT_TXA:
requiredTemps += CPU_REG_X;
requiredTemps -= CPU_REG_A;
break;
case ASMIT_TYA:
requiredTemps += CPU_REG_Y;
requiredTemps -= CPU_REG_A;
break;
case ASMIT_TAX:
requiredTemps += CPU_REG_A;
requiredTemps -= CPU_REG_X;
break;
case ASMIT_TAY:
requiredTemps += CPU_REG_A;
requiredTemps -= CPU_REG_Y;
break;
}
if (mMode == ASMIM_ZERO_PAGE)
{
switch (mType)
{
case ASMIT_STA:
case ASMIT_STX:
case ASMIT_STY:
requiredTemps -= mAddress;
break;
default:
requiredTemps += mAddress;
}
}
return true;
}
return false;
}
bool NativeCodeInstruction::LoadsAccu(void) const
{
return mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_JSR;
}
bool NativeCodeInstruction::ChangesAccuAndFlag(void) const
{
if (mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA ||
mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
mType == ASMIT_SBC || mType == ASMIT_ADC)
return true;
else if (mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROR || mType == ASMIT_ROL)
return mMode == ASMIM_IMPLIED;
else
return false;
}
uint32 NativeCodeInstruction::NeedsLive(void) const
{
uint32 live = mLive;
if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y)
live |= LIVE_CPU_REG_Y;
if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X)
live |= LIVE_CPU_REG_X;
if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY)
live |= LIVE_CPU_REG_Y;
if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX)
live |= LIVE_CPU_REG_X;
if (mMode == ASMIM_IMPLIED && (mType == ASMIT_TAX || mType == ASMIT_TAY ||
mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR))
live |= LIVE_CPU_REG_A;
if (mType == ASMIT_STA ||
mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP)
live |= LIVE_CPU_REG_A;
if (mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_ROL || mType == ASMIT_ROR)
live |= LIVE_CPU_REG_C;
return live;
}
bool NativeCodeInstruction::RequiresYReg(void) const
{
if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y)
return true;
if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY)
return true;
return false;
}
bool NativeCodeInstruction::RequiresXReg(void) const
{
if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X)
return true;
if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX)
return true;
return false;
}
bool NativeCodeInstruction::ReplaceYRegWithXReg(void)
{
bool changed = false;
switch (mType)
{
case ASMIT_LDY:
mType = ASMIT_LDX;
changed = true;
break;
case ASMIT_STY:
mType = ASMIT_STX;
changed = true;
break;
case ASMIT_CPY:
mType = ASMIT_CPX;
changed = true;
break;
case ASMIT_TYA:
mType = ASMIT_TXA;
changed = true;
break;
case ASMIT_TAY:
mType = ASMIT_TAX;
changed = true;
break;
case ASMIT_INY:
mType = ASMIT_INX;
changed = true;
break;
case ASMIT_DEY:
mType = ASMIT_DEX;
changed = true;
break;
}
if (mMode == ASMIM_ABSOLUTE_Y)
{
assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X));
mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
if (mLive & LIVE_CPU_REG_Y)
mLive |= LIVE_CPU_REG_X;
return changed;
}
bool NativeCodeInstruction::CanSwapXYReg(void)
{
if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y)
return false;
else if (mMode == ASMIM_ABSOLUTE_X)
return HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y);
else if (mMode == ASMIM_ABSOLUTE_Y)
return HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X);
else if (mType == ASMIT_JSR && (mFlags & (NCIF_USE_CPU_REG_X | NCIF_USE_CPU_REG_Y)))
return false;
else
return true;
}
bool NativeCodeInstruction::SwapXYReg(void)
{
bool changed = false;
switch (mType)
{
case ASMIT_LDX:
mType = ASMIT_LDY;
changed = true;
break;
case ASMIT_STX:
mType = ASMIT_STY;
changed = true;
break;
case ASMIT_CPX:
mType = ASMIT_CPY;
changed = true;
break;
case ASMIT_TXA:
mType = ASMIT_TYA;
changed = true;
break;
case ASMIT_TAX:
mType = ASMIT_TAY;
changed = true;
break;
case ASMIT_INX:
mType = ASMIT_INY;
changed = true;
break;
case ASMIT_DEX:
mType = ASMIT_DEY;
changed = true;
break;
case ASMIT_LDY:
mType = ASMIT_LDX;
changed = true;
break;
case ASMIT_STY:
mType = ASMIT_STX;
changed = true;
break;
case ASMIT_CPY:
mType = ASMIT_CPX;
changed = true;
break;
case ASMIT_TYA:
mType = ASMIT_TXA;
changed = true;
break;
case ASMIT_TAY:
mType = ASMIT_TAX;
changed = true;
break;
case ASMIT_INY:
mType = ASMIT_INX;
changed = true;
break;
case ASMIT_DEY:
mType = ASMIT_DEX;
changed = true;
break;
}
if (mMode == ASMIM_ABSOLUTE_X)
{
assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y));
mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
else if (mMode == ASMIM_ABSOLUTE_Y)
{
assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X));
mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
uint32 live = mLive;
mLive &= ~(LIVE_CPU_REG_X | LIVE_CPU_REG_Y);
if (live & LIVE_CPU_REG_X)
mLive |= LIVE_CPU_REG_Y;
if (live & LIVE_CPU_REG_Y)
mLive |= LIVE_CPU_REG_X;
return changed;
}
static void UpdateCollisionSet(NumberSet& liveTemps, NumberSet* collisionSets, int temp)
{
int i;
if (temp >= 0 && !liveTemps[temp])
{
for (i = 0; i < liveTemps.Size(); i++)
{
if (liveTemps[i])
{
collisionSets[i] += temp;
collisionSets[temp] += i;
}
}
liveTemps += temp;
}
}
void NativeCodeInstruction::BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets)
{
if (mMode == ASMIM_ZERO_PAGE)
{
if (ChangesAddress())
liveTemps -= mAddress;
if (UsesAddress())
UpdateCollisionSet(liveTemps, collisionSets, mAddress);
}
if (mMode == ASMIM_INDIRECT_Y)
{
UpdateCollisionSet(liveTemps, collisionSets, mAddress);
UpdateCollisionSet(liveTemps, collisionSets, mAddress + 1);
}
if (mType == ASMIT_JSR)
{
for(int i= BC_REG_ACCU; i< BC_REG_ACCU + 4; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
for (int i = BC_REG_WORK; i < BC_REG_WORK + 4; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
if (mFlags & NCIF_RUNTIME)
{
if (mFlags & NCIF_USE_ZP_32_X)
{
for (int i = mParam; i < mParam + 4; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
}
if (mFlags & NCIF_FEXEC)
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
}
}
else
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
if (mLinkerObject && mLinkerObject->mProc)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
UpdateCollisionSet(liveTemps, collisionSets, i);
}
}
}
else if (mType == ASMIT_RTS)
{
if (mFlags & NCIF_LOWER)
{
UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 0);
if (mFlags & NCIF_UPPER)
{
UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 1);
if (mFlags & NCIF_LONG)
{
UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 2);
UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 3);
}
}
}
}
}
bool NativeCodeInstruction::ReplaceXRegWithYReg(void)
{
bool changed = false;
switch (mType)
{
case ASMIT_LDX:
mType = ASMIT_LDY;
changed = true;
break;
case ASMIT_STX:
mType = ASMIT_STY;
changed = true;
break;
case ASMIT_CPX:
mType = ASMIT_CPY;
changed = true;
break;
case ASMIT_TXA:
mType = ASMIT_TYA;
changed = true;
break;
case ASMIT_TAX:
mType = ASMIT_TAY;
changed = true;
break;
case ASMIT_INX:
mType = ASMIT_INY;
changed = true;
break;
case ASMIT_DEX:
mType = ASMIT_DEY;
changed = true;
break;
}
if (mMode == ASMIM_ABSOLUTE_X)
{
assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y));
mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
if (mLive & LIVE_CPU_REG_X)
mLive |= LIVE_CPU_REG_Y;
return changed;
}
bool NativeCodeInstruction::ChangesYReg(void) const
{
return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY || mType == ASMIT_JSR;
}
bool NativeCodeInstruction::ChangesXReg(void) const
{
return mType == ASMIT_TAX || mType == ASMIT_LDX || mType == ASMIT_INX || mType == ASMIT_DEX || mType == ASMIT_JSR;
}
bool NativeCodeInstruction::ReferencesCarry(void) const
{
return ChangesCarry() || RequiresCarry();
}
bool NativeCodeInstruction::ReferencesAccu(void) const
{
return ChangesAccu() || RequiresAccu();
}
bool NativeCodeInstruction::ReferencesYReg(void) const
{
return ChangesYReg() || RequiresYReg();
}
bool NativeCodeInstruction::ReferencesXReg(void) const
{
return ChangesXReg() || RequiresXReg();
}
bool NativeCodeInstruction::ReferencesZeroPage(int address) const
{
return UsesZeroPage(address) || ChangesZeroPage(address);
}
bool NativeCodeInstruction::ChangesZeroPage(int address) const
{
if (mMode == ASMIM_ZERO_PAGE && mAddress == address)
return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY;
else if (mType == ASMIT_JSR)
{
if (address >= BC_REG_ACCU && address < BC_REG_ACCU + 4)
return true;
if (address >= BC_REG_WORK && address < BC_REG_WORK + 8)
return true;
if (address >= BC_REG_ADDR && address < BC_REG_ADDR + 4)
return true;
if (!(mFlags & NCIF_RUNTIME) || (mFlags & NCIF_FEXEC))
{
if (mLinkerObject && mLinkerObject->mProc)
{
if (!(mFlags & NCIF_FEXEC) && (mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
return mLinkerObject->mZeroPageSet[address];
if (address >= BC_REG_TMP && address < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps)
return true;
}
else
{
if (address >= BC_REG_TMP && address < BC_REG_TMP_SAVED)
return true;
}
if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
return true;
}
return false;
}
else
return false;
}
bool NativeCodeInstruction::UsesZeroPage(int address) const
{
if (mMode == ASMIM_ZERO_PAGE && mAddress == address)
return true;
else if (mMode == ASMIM_INDIRECT_Y && (mAddress == address || mAddress + 1 == address))
return true;
else if (mType == ASMIT_JSR)
{
if (mFlags & NCIF_RUNTIME)
{
if (address >= BC_REG_ACCU && address < BC_REG_ACCU + 4)
return true;
if (address >= BC_REG_WORK && address < BC_REG_WORK + 8)
return true;
if (mFlags & NCIF_USE_ZP_32_X)
{
if (address >= mParam && address < mParam + 4)
return true;
}
if (mFlags & NCIF_FEXEC)
{
if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
return true;
}
}
else
{
if (mFlags & NICF_USE_WORKREGS)
{
if (address >= BC_REG_WORK && address < BC_REG_WORK + 10)
return true;
}
if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
return true;
if (mLinkerObject)
{
for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
{
if (address >= mLinkerObject->mTemporaries[i] && address < mLinkerObject->mTemporaries[i] + mLinkerObject->mTempSizes[i])
return true;
}
}
}
return false;
}
else if (mType == ASMIT_RTS)
{
if (mFlags & NCIF_LOWER)
{
if (address == BC_REG_ACCU + 0)
return true;
if (mFlags & NCIF_UPPER)
{
if (address == BC_REG_ACCU + 1)
return true;
if (mFlags & NCIF_LONG)
{
if (address == BC_REG_ACCU + 2 || address == BC_REG_ACCU + 3)
return true;
}
}
}
return false;
}
else
return false;
}
bool NativeCodeInstruction::ChangesGlobalMemory(void) const
{
if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY || mType == ASMIT_JSR;
else
return false;
}
bool NativeCodeInstruction::RequiresCarry(void) const
{
return
mType == ASMIT_ADC || mType == ASMIT_SBC ||
mType == ASMIT_ROL || mType == ASMIT_ROR;
}
bool NativeCodeInstruction::ChangesZFlag(void) const
{
return
mType == ASMIT_ADC || mType == ASMIT_SBC ||
mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROL || mType == ASMIT_ROR ||
mType == ASMIT_INC || mType == ASMIT_DEC ||
mType == ASMIT_INY || mType == ASMIT_DEY ||
mType == ASMIT_INX || mType == ASMIT_DEX ||
mType == ASMIT_TAX || mType == ASMIT_TAY || mType == ASMIT_TXA || mType == ASMIT_TYA ||
mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY ||
mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR ||
mType == ASMIT_BIT ||
mType == ASMIT_JSR;
}
bool NativeCodeInstruction::ChangesCarry(void) const
{
return
mType == ASMIT_CLC || mType == ASMIT_SEC ||
mType == ASMIT_ADC || mType == ASMIT_SBC ||
mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROL || mType == ASMIT_ROR ||
mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
mType == ASMIT_JSR;
}
bool NativeCodeInstruction::RequiresAccu(void) const
{
if (mMode == ASMIM_IMPLIED)
{
return
mType == ASMIT_TAX || mType == ASMIT_TAY ||
mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
}
else
{
return
mType == ASMIT_STA ||
mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP;
}
}
bool NativeCodeInstruction::UsesAccu(void) const
{
if (ChangesAccu())
return true;
return mType == ASMIT_STA || mType == ASMIT_CMP || mType == ASMIT_TAX || mType == ASMIT_TAY;
}
bool NativeCodeInstruction::ChangesAccu(void) const
{
if (mMode == ASMIM_IMPLIED)
{
return
mType == ASMIT_TXA || mType == ASMIT_TYA ||
mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
}
else
{
return
mType == ASMIT_JSR ||
mType == ASMIT_LDA ||
mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
mType == ASMIT_SBC || mType == ASMIT_ADC;
}
}
bool NativeCodeInstruction::UsesAddress(void) const
{
if (mMode != ASMIM_IMPLIED)
{
return
mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR ||
mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY ||
mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR || mType == ASMIT_BIT;
}
else
return false;
}
bool NativeCodeInstruction::ChangesAddress(void) const
{
if (mMode != ASMIM_IMPLIED)
return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY;
else
return false;
}
bool NativeCodeInstruction::IsSimpleJSR(void) const
{
return mType == ASMIT_JSR && mMode == ASMIM_ABSOLUTE && !(mLinkerObject && (mLinkerObject->mFlags & LOBJF_INLINE)) && !(mFlags & NCIF_BREAKPOINT);
}
bool NativeCodeInstruction::IsShift(void) const
{
return mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
}
bool NativeCodeInstruction::IsShiftOrInc(void) const
{
return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR;// || mType == ASMIT_ROL || mType == ASMIT_ROR;
}
bool NativeCodeInstruction::IsCommutative(void) const
{
return mType == ASMIT_ADC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR;
}
bool NativeCodeInstruction::IsSame(const NativeCodeInstruction& ins) const
{
if (mType == ins.mType && mMode == ins.mMode && mParam == ins.mParam)
{
switch (mMode)
{
case ASMIM_IMPLIED:
return true;
case ASMIM_IMMEDIATE:
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_ZERO_PAGE_Y:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
return ins.mAddress == mAddress;
case ASMIM_IMMEDIATE_ADDRESS:
return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags);
case ASMIM_ABSOLUTE:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress);
default:
return false;
}
}
else
return false;
}
bool NativeCodeInstruction::IsSameLS(const NativeCodeInstruction& ins) const
{
if ((mType == ins.mType || mType == ASMIT_STA && ins.mType == ASMIT_LDA) && mMode == ins.mMode && mParam == ins.mParam)
{
switch (mMode)
{
case ASMIM_IMPLIED:
return true;
case ASMIM_IMMEDIATE:
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_ZERO_PAGE_Y:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
return ins.mAddress == mAddress;
case ASMIM_IMMEDIATE_ADDRESS:
return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags);
case ASMIM_ABSOLUTE:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress);
default:
return false;
}
}
else
return false;
}
bool NativeCodeInstruction::MayBeMovedBefore(const NativeCodeInstruction& ins)
{
if ((ChangesAddress() || ins.ChangesAddress()) && MayBeSameAddress(ins))
return false;
if (RequiresXReg() && ins.ChangesXReg() || ins.RequiresXReg() && ChangesXReg())
return false;
if (RequiresYReg() && ins.ChangesYReg() || ins.RequiresYReg() && ChangesYReg())
return false;
if (RequiresAccu() && ins.ChangesAccu() || ins.RequiresAccu() && ChangesAccu())
return false;
if (RequiresCarry() && ins.ChangesCarry() || ins.RequiresCarry() && ChangesCarry())
return false;
if ((mLive & LIVE_CPU_REG_A) && ins.ChangesAccu())
return false;
if ((mLive & LIVE_CPU_REG_X) && ins.ChangesXReg())
return false;
if ((mLive & LIVE_CPU_REG_Y) && ins.ChangesYReg())
return false;
if ((mLive & LIVE_CPU_REG_C) && ins.ChangesCarry())
return false;
if ((mLive & LIVE_CPU_REG_Z) && ins.ChangesZFlag())
return false;
return true;
}
bool NativeCodeInstruction::MayBeSameAddress(const NativeCodeInstruction& ins, bool sameXY) const
{
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (mMode == ASMIM_ZERO_PAGE)
return mAddress == ins.mAddress;
else
return false;
}
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 && mAddress <= ins.mAddress && mAddress + 256 > ins.mAddress;
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)
{
if (mLinkerObject != ins.mLinkerObject)
return false;
else if (mAddress >= ins.mAddress + 256 || ins.mAddress >= mAddress + 256)
return false;
else if (mMode == ASMIM_ABSOLUTE && ins.mAddress > mAddress)
return false;
else
return mMode != ins.mMode || !sameXY || mAddress == ins.mAddress;
}
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::MayReference(const NativeCodeInstruction& ins, bool sameXY) const
{
if (!ins.ChangesAddress())
return false;
if (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS || mMode == ASMIM_IMPLIED)
return false;
if (mType == ASMIT_JSR)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
return ReferencesZeroPage(ins.mAddress);
else
return true;
}
if (ins.mMode == ASMIM_ZERO_PAGE)
return ReferencesZeroPage(ins.mAddress);
else if (mMode == ASMIM_ZERO_PAGE)
return false;
else if (mMode == ASMIM_ABSOLUTE)
{
if (ins.mMode == ASMIM_ABSOLUTE)
return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress;
else if (ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
return mLinkerObject == ins.mLinkerObject;
else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
return ins.mAddress != BC_REG_STACK;
else
return false;
}
else if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
{
if (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
{
if (mLinkerObject != ins.mLinkerObject)
return false;
else
return mMode != ins.mMode || !sameXY || mAddress == ins.mAddress;
}
else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
return ins.mAddress != BC_REG_STACK;
else
return false;
}
else if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
{
if (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
return mAddress != BC_REG_STACK;
else
return ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X;
}
else
return false;
}
bool NativeCodeInstruction::MayBeChangedOnAddress(const NativeCodeInstruction& ins, bool sameXY) const
{
if (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS)
return false;
if (ins.mType == ASMIT_JSR)
{
if (mMode == ASMIM_ZERO_PAGE)
return ins.ChangesZeroPage(mAddress);
else if (mMode == ASMIM_IMPLIED || mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS)
return false;
else
return true;
}
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 if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
return mAddress != BC_REG_STACK;
else
return false;
}
else if (ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
{
if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
{
if (mLinkerObject != ins.mLinkerObject)
return false;
else
return mMode != ins.mMode || !sameXY || mAddress == ins.mAddress;
}
else if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
return mAddress != BC_REG_STACK;
else
return false;
}
else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
{
if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
return ins.mAddress != BC_REG_STACK;
else
return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X;
}
else
return false;
}
bool NativeCodeInstruction::UsesMemoryOf(const NativeCodeInstruction& ins) const
{
if (ins.mMode == ASMIM_ZERO_PAGE)
return UsesZeroPage(ins.mAddress);
else if (UsesAddress())
{
if (ins.mMode == ASMIM_ABSOLUTE && mMode == ASMIM_ABSOLUTE)
return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress;
else if (
(ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) &&
(mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y))
return mLinkerObject == ins.mLinkerObject;
else if (ins.mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_Y)
return true;
else
return false;
}
else
return false;
}
bool NativeCodeInstruction::SameEffectiveAddress(const NativeCodeInstruction& ins) const
{
if (mMode != ins.mMode)
return false;
switch (mMode)
{
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_ZERO_PAGE_Y:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
case ASMIM_IMMEDIATE:
return ins.mAddress == mAddress;
case ASMIM_ABSOLUTE:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress);
default:
return false;
}
}
bool NativeCodeInstruction::ApplySimulation(const NativeRegisterDataSet& data)
{
switch (mType)
{
case ASMIT_LDA:
case ASMIT_LDX:
case ASMIT_LDY:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_AND:
case ASMIT_ORA:
case ASMIT_EOR:
if (mMode == ASMIM_ZERO_PAGE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[mAddress].mValue;
return true;
}
else if (mMode == ASMIM_ZERO_PAGE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS)
{
mMode = ASMIM_IMMEDIATE_ADDRESS;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mFlags = data.mRegs[mAddress].mFlags;
mAddress = data.mRegs[mAddress].mValue;
assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
return true;
}
break;
}
if (mMode == ASMIM_INDIRECT_Y && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE)
{
mMode = ASMIM_ABSOLUTE_Y;
mAddress = data.mRegs[mAddress].mValue + 256 * data.mRegs[mAddress + 1].mValue;
mLinkerObject = nullptr;
}
else if (mMode == ASMIM_INDIRECT_Y && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject)
{
mMode = ASMIM_ABSOLUTE_Y;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress].mValue;
}
return false;
}
void NativeCodeInstruction::Simulate(NativeRegisterDataSet& data)
{
int reg = -1;
if (mMode == ASMIM_ZERO_PAGE)
reg = mAddress;
else if (mMode == ASMIM_IMPLIED)
reg = CPU_REG_A;
switch (mType)
{
case ASMIT_JSR:
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Y].Reset();
data.ResetWorkRegs();
if (mFlags & NCIF_FEXEC)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
data.mRegs[i].Reset();
}
else if (!(mFlags & NCIF_RUNTIME))
{
if (mLinkerObject && mLinkerObject->mProc)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++)
data.mRegs[i].Reset();
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
data.mRegs[i].Reset();
}
}
break;
case ASMIT_ROL:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue << 1) | data.mRegs[CPU_REG_C].mValue;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[reg].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].Reset();
data.mRegs[CPU_REG_C].mValue = data.mRegs[reg].mValue >= 128;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[reg].Reset();
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_ROR:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue >> 1) | (data.mRegs[CPU_REG_C].mValue << 7);
data.mRegs[CPU_REG_C].mValue = data.mRegs[reg].mValue & 1;
data.mRegs[reg].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].Reset();
data.mRegs[CPU_REG_C].mValue = data.mRegs[reg].mValue & 1;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[reg].Reset();
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_ASL:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue << 1);
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[reg].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_LSR:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue >> 1);
data.mRegs[CPU_REG_C].mValue = data.mRegs[reg].mValue & 1;
data.mRegs[reg].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_INC:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
data.mRegs[reg].mValue = (data.mRegs[reg].mValue + 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[reg].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_DEC:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
data.mRegs[reg].mValue = (data.mRegs[reg].mValue + 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[reg].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_ADC:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[CPU_REG_A].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_SBC:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue ^ 0xff) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[CPU_REG_A].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_AND:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue & data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_A].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if ((data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[reg].mValue == 0) || (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0))
{
data.mRegs[CPU_REG_A].mValue = 0;
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = 0;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_ORA:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue | data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_A].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if ((data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[reg].mValue == 0xff) || (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0xff))
{
data.mRegs[CPU_REG_A].mValue = 0xff;
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = 0xff;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_EOR:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue | data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_A].mValue = t & 255;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_INX:
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mValue = (data.mRegs[CPU_REG_X].mValue + 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_X].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_DEX:
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mValue = (data.mRegs[CPU_REG_X].mValue - 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_X].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_INY:
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mValue = (data.mRegs[CPU_REG_Y].mValue + 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_Y].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_DEY:
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mValue = (data.mRegs[CPU_REG_Y].mValue - 1) & 255;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_Y].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TXA:
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_A].mValue = data.mRegs[CPU_REG_X].mValue;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_X].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TYA:
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_A].mValue = data.mRegs[CPU_REG_Y].mValue;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_Y].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TAX:
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mValue = data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TAY:
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mValue = data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_Y].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_CMP:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue ^ 0xff) + data.mRegs[CPU_REG_A].mValue + 1;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
{
data.mRegs[CPU_REG_C].mValue = 1;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_CPX:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue ^ 0xff) + data.mRegs[CPU_REG_X].mValue + 1;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
{
data.mRegs[CPU_REG_C].mValue = 1;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_CPY:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
int t = (data.mRegs[reg].mValue ^ 0xff) + data.mRegs[CPU_REG_Y].mValue + 1;
data.mRegs[CPU_REG_C].mValue = t >= 256;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t & 255;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
{
data.mRegs[CPU_REG_C].mValue = 1;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_BIT:
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_LDA:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue;
data.mRegs[CPU_REG_A].mValue = t;
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mFlags = mFlags;
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_LDX:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue;
data.mRegs[CPU_REG_X].mValue = t;
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_X].mFlags = mFlags;
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_LDY:
if (reg >= 0)
{
if (data.mRegs[reg].mMode == NRDM_IMMEDIATE)
{
int t = data.mRegs[reg].mValue;
data.mRegs[CPU_REG_Y].mValue = t;
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = t;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[CPU_REG_Y].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_Y].mFlags = mFlags;
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_Y].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_STA:
if (reg >= 0)
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE || data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS)
{
data.mRegs[reg] = data.mRegs[CPU_REG_A];
}
else
{
data.mRegs[reg].Reset();
}
}
break;
case ASMIT_STX:
if (reg >= 0)
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[reg].mValue = data.mRegs[CPU_REG_X].mValue;
data.mRegs[reg].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
}
}
break;
case ASMIT_STY:
if (reg >= 0)
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[reg].mValue = data.mRegs[CPU_REG_Y].mValue;
data.mRegs[reg].mMode = NRDM_IMMEDIATE;
}
else
{
data.mRegs[reg].Reset();
}
}
break;
case ASMIT_CLC:
data.mRegs[CPU_REG_C].mValue = 0;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
break;
case ASMIT_SEC:
data.mRegs[CPU_REG_C].mValue = 1;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
break;
}
}
bool NativeCodeInstruction::BitFieldForwarding(NativeRegisterDataSet& data, AsmInsType& carryop)
{
bool changed = false;
int iaddr = -1;
if (mMode == ASMIM_IMPLIED)
iaddr = CPU_REG_A;
else if (mMode == ASMIM_ZERO_PAGE)
iaddr = mAddress;
int opmask = 0, opvalue = 0;
if (mMode == ASMIM_IMMEDIATE)
{
opmask = 0xff;
opvalue = mAddress;
}
else if (mMode == ASMIM_ZERO_PAGE)
{
opmask = data.mRegs[mAddress].mMask;
opvalue = data.mRegs[mAddress].mValue;
}
#if 1
else if ((mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) && mLinkerObject && (mLinkerObject->mFlags & LOBJF_CONST) && mLinkerObject->mSize <= 256 && mLinkerObject->mReferences.Size() == 0 && mType != ASMIT_JSR)
{
int mor = 0;
int mand = 0xff;
for (int i = 0; i < mLinkerObject->mSize; i++)
{
mor |= mLinkerObject->mData[i];
mand &= mLinkerObject->mData[i];
}
opmask = (mand | ~mor) & 0xff;
opvalue = mand;
#if 0
if (opmask)
printf("Check %s, %02x %02x\n", mLinkerObject->mIdent->mString, opmask, opvalue);
#endif
}
#endif
switch (mType)
{
case ASMIT_JSR:
data.mRegs[CPU_REG_C].ResetMask();
data.mRegs[CPU_REG_Z].ResetMask();
data.mRegs[CPU_REG_A].ResetMask();
data.mRegs[CPU_REG_X].ResetMask();
data.mRegs[CPU_REG_Y].ResetMask();
data.ResetWorkMasks();
if (!(mFlags & NCIF_RUNTIME) || (mFlags & NCIF_FEXEC))
{
if (mLinkerObject && mLinkerObject->mProc)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++)
data.mRegs[i].ResetMask();
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
data.mRegs[i].ResetMask();
}
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
data.mRegs[i].ResetMask();
}
break;
case ASMIT_CLC:
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = 0;
break;
case ASMIT_SEC:
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = 1;
break;
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
data.mRegs[CPU_REG_C].mMask = 0;
break;
case ASMIT_ADC:
if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_C].mMask == 1 && data.mRegs[CPU_REG_C].mValue == 0)
{
if ((mAddress & ~data.mRegs[CPU_REG_A].mMask) == 0 && (mAddress & data.mRegs[CPU_REG_A].mValue) == 0)
{
mType = ASMIT_ORA;
data.mRegs[CPU_REG_A].mValue |= mAddress;
changed = true;
}
else if (mAddress == 1 && (data.mRegs[CPU_REG_A].mMask & 3) == 3 && (data.mRegs[CPU_REG_A].mValue & 3) == 1)
{
mType = ASMIT_EOR;
mAddress = 3;
data.mRegs[CPU_REG_A].mValue ^= 3;
changed = true;
}
else
{
data.mRegs[CPU_REG_C].mMask = 0;
data.mRegs[CPU_REG_A].mMask = 0;
}
}
else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
{
int zeros = data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue;
int fzero = 0x01;
while (fzero < 0x100 && (fzero & zeros) == 0)
fzero <<= 1;
fzero |= (fzero - 1);
data.mRegs[CPU_REG_A].mMask &= ~fzero;
if (fzero >= 0x100)
data.mRegs[CPU_REG_C].mMask = 0;
else
{
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = 0;
}
}
else if (data.mRegs[CPU_REG_C].mMask == 1 && data.mRegs[CPU_REG_C].mValue == 0)
{
if ((((~opmask | opvalue) & (~data.mRegs[CPU_REG_A].mMask | data.mRegs[CPU_REG_A].mValue)) & 0xff) == 0)
{
mType = ASMIT_ORA;
data.mRegs[CPU_REG_A].mValue |= opvalue;
data.mRegs[CPU_REG_A].mMask &= opmask;
changed = true;
}
else
{
data.mRegs[CPU_REG_C].mMask = 0;
data.mRegs[CPU_REG_A].mMask = 0;
}
}
else
{
data.mRegs[CPU_REG_C].mMask = 0;
data.mRegs[CPU_REG_A].mMask = 0;
}
break;
case ASMIT_SBC:
data.mRegs[CPU_REG_C].mMask = 0;
data.mRegs[CPU_REG_A].mMask = 0;
break;
case ASMIT_LDA:
if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_A].mMask = 0xff;
data.mRegs[CPU_REG_A].mValue = mAddress & 0xff;
}
else
{
data.mRegs[CPU_REG_A].mMask = opmask;
data.mRegs[CPU_REG_A].mValue = opvalue;
if (opmask == 0xff)
{
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = opvalue;
changed = true;
}
}
break;
case ASMIT_STA:
if (mMode == ASMIM_ZERO_PAGE)
{
data.mRegs[mAddress].mMask = data.mRegs[CPU_REG_A].mMask;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue;
}
break;
case ASMIT_LDX:
if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mMask = 0xff;
data.mRegs[CPU_REG_X].mValue = mAddress & 0xff;
}
else
{
data.mRegs[CPU_REG_X].mMask = opmask;
data.mRegs[CPU_REG_X].mValue = opvalue;
if (opmask == 0xff)
{
mType = ASMIT_LDX;
mMode = ASMIM_IMMEDIATE;
mAddress = opvalue;
changed = true;
}
}
break;
case ASMIT_STX:
if (mMode == ASMIM_ZERO_PAGE)
{
data.mRegs[mAddress].mMask = data.mRegs[CPU_REG_X].mMask;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_X].mValue;
}
break;
case ASMIT_LDY:
if (mMode == ASMIM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mMask = 0xff;
data.mRegs[CPU_REG_Y].mValue = mAddress & 0xff;
}
else
{
data.mRegs[CPU_REG_Y].mMask = opmask;
data.mRegs[CPU_REG_Y].mValue = opvalue;
if (opmask == 0xff)
{
mType = ASMIT_LDY;
mMode = ASMIM_IMMEDIATE;
mAddress = opvalue;
changed = true;
}
}
break;
case ASMIT_STY:
if (mMode == ASMIM_ZERO_PAGE)
{
data.mRegs[mAddress].mMask = data.mRegs[CPU_REG_Y].mMask;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_Y].mValue;
}
break;
case ASMIT_AND:
{
int zeros =
(opmask & ~opvalue) |
(data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue);
int ones =
(opmask & opvalue) &
(data.mRegs[CPU_REG_A].mMask & data.mRegs[CPU_REG_A].mValue);
data.mRegs[CPU_REG_A].mMask = (ones | zeros) & 0xff;
data.mRegs[CPU_REG_A].mValue = ones & 0xff;
if (data.mRegs[CPU_REG_A].mMask == 0xff)
{
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
} break;
case ASMIT_ORA:
{
int ones =
(opmask & opvalue) |
(data.mRegs[CPU_REG_A].mMask & data.mRegs[CPU_REG_A].mValue);
int zeros =
(opmask & ~opvalue) &
(data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue);
data.mRegs[CPU_REG_A].mMask = (ones | zeros) & 0xff;
data.mRegs[CPU_REG_A].mValue = ones & 0xff;
if (data.mRegs[CPU_REG_A].mMask == 0xff)
{
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
} break;
case ASMIT_EOR:
data.mRegs[CPU_REG_A].mMask = 0;
break;
case ASMIT_TAX:
data.mRegs[CPU_REG_X].mMask = data.mRegs[CPU_REG_A].mMask;
data.mRegs[CPU_REG_X].mValue = data.mRegs[CPU_REG_A].mValue;
break;
case ASMIT_TAY:
data.mRegs[CPU_REG_Y].mMask = data.mRegs[CPU_REG_A].mMask;
data.mRegs[CPU_REG_Y].mValue = data.mRegs[CPU_REG_A].mValue;
break;
case ASMIT_TXA:
data.mRegs[CPU_REG_A].mMask = data.mRegs[CPU_REG_X].mMask;
data.mRegs[CPU_REG_A].mValue = data.mRegs[CPU_REG_X].mValue;
break;
case ASMIT_TYA:
data.mRegs[CPU_REG_A].mMask = data.mRegs[CPU_REG_Y].mMask;
data.mRegs[CPU_REG_A].mValue = data.mRegs[CPU_REG_Y].mValue;
break;
case ASMIT_INX:
case ASMIT_DEX:
data.mRegs[CPU_REG_X].mMask = 0;
break;
case ASMIT_INY:
case ASMIT_DEY:
data.mRegs[CPU_REG_Y].mMask = 0;
break;
case ASMIT_INC:
case ASMIT_DEC:
if (mMode == ASMIM_ZERO_PAGE)
data.mRegs[mAddress].mMask = 0;
break;
case ASMIT_ASL:
if (iaddr >= 0)
{
int mask = data.mRegs[iaddr].mMask, value = data.mRegs[iaddr].mValue;
data.mRegs[iaddr].mMask = ((mask << 1) & 0xff) | 0x01;
data.mRegs[iaddr].mValue = ((value << 1) & 0xff);
if (mask & 0x80)
{
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = value >> 7;
}
else
data.mRegs[CPU_REG_C].mMask = 0;
if (mMode == ASMIM_IMPLIED && data.mRegs[CPU_REG_A].mMask == 0xff && data.mRegs[CPU_REG_C].mMask)
{
carryop = data.mRegs[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
}
else
data.mRegs[CPU_REG_C].mMask = 0;
break;
case ASMIT_LSR:
if (iaddr >= 0)
{
int mask = data.mRegs[iaddr].mMask, value = data.mRegs[iaddr].mValue;
if (mask == 0xff && value == 0x00)
{
mType = ASMIT_CLC;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = 0;
changed = true;
}
else
{
data.mRegs[iaddr].mMask = ((mask >> 1) & 0xff) | 0x80;
data.mRegs[iaddr].mValue = ((value >> 1) & 0x7f);
if (mask & 0x01)
{
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = value & 1;
}
else
data.mRegs[CPU_REG_C].mMask = 0;
if (mMode == ASMIM_IMPLIED && data.mRegs[CPU_REG_A].mMask == 0xff && data.mRegs[CPU_REG_C].mMask)
{
carryop = data.mRegs[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
}
}
else
data.mRegs[CPU_REG_C].mMask = 0;
break;
case ASMIT_ROL:
if (iaddr >= 0)
{
int mask = data.mRegs[iaddr].mMask, value = data.mRegs[iaddr].mValue;
data.mRegs[iaddr].mMask = (mask << 1) & 0xff;
data.mRegs[iaddr].mValue = (value << 1) & 0xff;
if (data.mRegs[CPU_REG_C].mMask & 1)
{
data.mRegs[iaddr].mMask |= 1;
data.mRegs[iaddr].mValue |= data.mRegs[CPU_REG_C].mValue & 1;
}
if (mask & 0x80)
{
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = value >> 7;
}
else
data.mRegs[CPU_REG_C].mMask = 0;
if (mMode == ASMIM_IMPLIED && data.mRegs[CPU_REG_A].mMask == 0xff && data.mRegs[CPU_REG_C].mMask)
{
carryop = data.mRegs[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
}
else
data.mRegs[CPU_REG_C].mMask = 0;
break;
case ASMIT_ROR:
if (iaddr >= 0)
{
int mask = data.mRegs[iaddr].mMask, value = data.mRegs[iaddr].mValue;
data.mRegs[iaddr].mMask = (mask >> 1) & 0x7f;
data.mRegs[iaddr].mValue = (value >> 1) & 0x7f;
if (data.mRegs[CPU_REG_C].mMask & 1)
{
data.mRegs[iaddr].mMask |= 0x80;
data.mRegs[iaddr].mValue |= (data.mRegs[CPU_REG_C].mValue << 7) & 0x80;
}
if (mask & 0x01)
{
data.mRegs[CPU_REG_C].mMask = 1;
data.mRegs[CPU_REG_C].mValue = value & 1;
}
else
data.mRegs[CPU_REG_C].mMask = 0;
if (mMode == ASMIM_IMPLIED && data.mRegs[CPU_REG_A].mMask == 0xff && data.mRegs[CPU_REG_C].mMask)
{
carryop = data.mRegs[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
}
else
data.mRegs[CPU_REG_C].mMask = 0;
break;
}
#if _DEBUG
for (int i = 0; i < NUM_REGS; i++)
{
assert(!(data.mRegs[i].mMask & 0xff00));
}
#endif
return changed;
}
bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsType& carryop, bool initial, bool final, int fastCallBase)
{
bool changed = false;
carryop = ASMIT_NOP;
mFlags &= ~NCIF_YZERO;
if ((data.mRegs[CPU_REG_Y].mMode & NRDM_IMMEDIATE) && (data.mRegs[CPU_REG_Y].mValue == 0))
mFlags |= NCIF_YZERO;
if (mType == ASMIT_JSR)
{
data.ResetCall(*this, fastCallBase);
return false;
}
if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mValue == 0)
{
switch (mType)
{
case ASMIT_ROL:
mType = ASMIT_ASL;
changed = true;
break;
case ASMIT_ROR:
mType = ASMIT_LSR;
changed = true;
break;
}
}
switch (mType)
{
case ASMIT_CLC:
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = 0;
break;
case ASMIT_SEC:
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = 1;
break;
case ASMIT_ROL:
case ASMIT_ROR:
if (mMode == ASMIM_IMPLIED)
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_ASL:
case ASMIT_LSR:
if (mMode == ASMIM_IMPLIED)
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0 && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_CLC;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = 0;
changed = true;
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_INC:
case ASMIT_DEC:
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_LDA:
if (mMode == ASMIM_IMMEDIATE)
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_A].mValue = mAddress;
}
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS &&
data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject &&
data.mRegs[CPU_REG_A].mFlags == mFlags &&
data.mRegs[CPU_REG_A].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mFlags = mFlags;
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_INDIRECT_Y && mMode != ASMIM_ABSOLUTE_X && mMode != ASMIM_ABSOLUTE_Y)
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_STA:
if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_A].mValue)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
case ASMIT_STX:
if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_X].mValue)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
case ASMIT_STY:
if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_Y].mValue)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
case ASMIT_ADC:
if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data.mRegs[CPU_REG_C].mValue == 0)
{
mType = ASMIT_ORA;
changed = true;
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0 && data.mRegs[CPU_REG_C].mValue == 0)
{
mType = ASMIT_LDA;
changed = true;
}
else if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = mAddress + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
mType = ASMIT_LDA;
mAddress = t & 0xff;
int c = t >= 256;
if (c && !data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_SEC;
else if (!c && data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_CLC;
changed = true;
}
}
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_SBC:
if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data.mRegs[CPU_REG_C].mValue == 1)
{
mType = ASMIT_ORA;
changed = true;
}
else if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
int t = (mAddress ^ 0xff) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
mType = ASMIT_LDA;
mAddress = t & 0xff;
int c = t >= 256;
if (c && !data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_SEC;
else if (!c && data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_CLC;
changed = true;
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS && mLinkerObject == data.mRegs[CPU_REG_A].mLinkerObject)
{
int t;
if (mFlags & NCIF_LOWER)
t = (mAddress ^ 0xffff) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
else
t = ((mAddress ^ 0xffff) >> 8) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue;
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = t & 0xff;
int c = t >= 256;
if (c && !data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_SEC;
else if (!c && data.mRegs[CPU_REG_C].mValue)
carryop = ASMIT_CLC;
changed = true;
}
}
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_CMP:
if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue - mAddress;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_A].mValue >= mAddress;
}
else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
{
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = 1;
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_CPX:
if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_X].mValue - mAddress;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_X].mValue >= mAddress;
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_CPY:
if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_Y].mValue - mAddress;
data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_Y].mValue >= mAddress;
}
else
{
data.mRegs[CPU_REG_C].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
if (mType == ASMIT_ORA)
mAddress |= data.mRegs[CPU_REG_A].mValue;
else if (mType == ASMIT_AND)
mAddress &= data.mRegs[CPU_REG_A].mValue;
else if (mType == ASMIT_EOR)
mAddress ^= data.mRegs[CPU_REG_A].mValue;
mType = ASMIT_LDA;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
changed = true;
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0)
{
if (mType == ASMIT_ORA || mType == ASMIT_EOR)
{
mType = ASMIT_LDA;
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
else
{
mType = ASMIT_LDA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = 0;
}
changed = true;
}
else if (mMode == ASMIM_IMMEDIATE && mType == ASMIT_ORA && mAddress != 0x00)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
data.mRegs[CPU_REG_A].Reset();
}
else if (mMode == ASMIM_IMMEDIATE && ((mAddress == 0 && (mType == ASMIT_ORA || mType == ASMIT_EOR)) || (mAddress == 0xff && mType == ASMIT_AND)))
{
data.mRegs[CPU_REG_Z].Reset();
}
else
{
data.mRegs[CPU_REG_A].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_LDX:
data.ResetX();
if (mMode == ASMIM_IMMEDIATE)
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
}
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE_ADDRESS &&
data.mRegs[CPU_REG_X].mLinkerObject == mLinkerObject &&
data.mRegs[CPU_REG_X].mFlags == mFlags &&
data.mRegs[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_X].mFlags = mFlags;
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_ABSOLUTE_Y)
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_BIT:
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_INX:
case ASMIT_DEX:
data.ResetX();
data.mRegs[CPU_REG_X].Reset();
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_LDY:
data.ResetY();
if (mMode == ASMIM_IMMEDIATE)
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = mAddress;
}
}
else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE_ADDRESS &&
data.mRegs[CPU_REG_Y].mLinkerObject == mLinkerObject &&
data.mRegs[CPU_REG_Y].mFlags == mFlags &&
data.mRegs[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE_ADDRESS;
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_Y].mFlags = mFlags;
data.mRegs[CPU_REG_Z].Reset();
}
}
else
{
if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_ABSOLUTE_X)
data.mRegs[CPU_REG_Y].Reset();
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_INY:
case ASMIT_DEY:
data.ResetY();
data.mRegs[CPU_REG_Y].Reset();
data.mRegs[CPU_REG_Z].Reset();
break;
case ASMIT_TXA:
if (data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_X]) && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
}
else
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TYA:
if (data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_Y]) && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
}
else
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TAX:
if (data.mRegs[CPU_REG_X].SameData(data.mRegs[CPU_REG_A]) && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.ResetX();
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
}
else
data.mRegs[CPU_REG_Z].Reset();
}
break;
case ASMIT_TAY:
if (data.mRegs[CPU_REG_Y].SameData(data.mRegs[CPU_REG_A]) && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
data.ResetY();
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue;
}
else
data.mRegs[CPU_REG_Z].Reset();
}
break;
}
#if 1
if (mMode == ASMIM_ABSOLUTE_X && data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
mMode = ASMIM_ABSOLUTE;
mAddress += data.mRegs[CPU_REG_X].mValue;
changed = true;
}
else if (mMode == ASMIM_ABSOLUTE_Y && data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
mMode = ASMIM_ABSOLUTE;
mAddress += data.mRegs[CPU_REG_Y].mValue;
changed = true;
}
#endif
#if 1
if (mMode == ASMIM_ABSOLUTE_X && data.mRegs[CPU_REG_X].SameData(data.mRegs[CPU_REG_Y]) && HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y) && !(mFlags & NICT_INDEXFLIPPED))
{
mFlags |= NICT_INDEXFLIPPED;
mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
else if (final && mMode == ASMIM_ABSOLUTE_Y && data.mRegs[CPU_REG_X].SameData(data.mRegs[CPU_REG_Y]) && HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X) && !(mFlags & NICT_INDEXFLIPPED))
{
mFlags |= NICT_INDEXFLIPPED;
mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
#endif
#if 1
if (mMode == ASMIM_ABSOLUTE && final && !(mFlags & NCIF_VOLATILE) && !ChangesAddress() && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
{
if (mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
}
else
{
int i = data.FindAbsolute(mLinkerObject, mAddress);
if (i >= 0)
{
mMode = ASMIM_ZERO_PAGE;
mAddress = i;
mLinkerObject = nullptr;
changed = true;
}
}
}
#endif
#if 1
if (final && mType == ASMIT_STX && data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_X]))
{
mType = ASMIT_STA;
changed = true;
}
else if (final && mType == ASMIT_STY && data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_Y]))
{
mType = ASMIT_STA;
changed = true;
}
#endif
if (mMode == ASMIM_ZERO_PAGE)
{
switch (mType)
{
case ASMIT_LDA:
if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_A] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_A].mValue;
mMode = ASMIM_IMMEDIATE;
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS)
{
data.mRegs[CPU_REG_A] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_A].mValue;
mLinkerObject = data.mRegs[CPU_REG_A].mLinkerObject;
mFlags = (mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | (data.mRegs[CPU_REG_A].mFlags & (NCIF_LOWER | NCIF_UPPER));
mMode = ASMIM_IMMEDIATE_ADDRESS;
changed = true;
}
else if (data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A]))
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && (mAddress < BC_REG_FPARAMS || mAddress >= BC_REG_FPARAMS_END))
{
data.mRegs[CPU_REG_A] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
#if 1
else if (data.mRegs[CPU_REG_X].SameData(*this))
{
mType = ASMIT_TXA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
changed = true;
}
else if (data.mRegs[CPU_REG_Y].SameData(*this))
{
mType = ASMIT_TYA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
changed = true;
}
#else
else if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_X].mValue == mAddress)
{
mType = ASMIT_TXA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
changed = true;
}
else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mValue == mAddress)
{
mType = ASMIT_TYA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
changed = true;
}
#endif
else if (final && data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && data.mRegs[mAddress].mLinkerObject && (data.mRegs[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
data.mRegs[CPU_REG_A] = data.mRegs[mAddress];
mMode = ASMIM_ABSOLUTE;
mFlags |= data.mRegs[mAddress].mFlags;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress].mValue;
changed = true;
}
else
{
data.mRegs[CPU_REG_A].Reset();
if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_A].mValue = data.mRegs[mAddress].mValue;
}
else if (initial && mAddress == BC_REG_WORK_Y)
{
data.mRegs[CPU_REG_A].Reset();
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_A].mValue = mAddress;
}
}
break;
case ASMIT_LDX:
if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_X].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_X] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_X].mValue;
mMode = ASMIM_IMMEDIATE;
changed = true;
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAX;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
changed = true;
}
else if (data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A]))
{
mType = ASMIT_TAX;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
changed = true;
}
#if 1
else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE)
{
data.mRegs[CPU_REG_X] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_X].mValue;
changed = true;
}
#endif
else if (final && data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && data.mRegs[mAddress].mLinkerObject && (data.mRegs[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
data.mRegs[CPU_REG_X] = data.mRegs[mAddress];
mMode = ASMIM_ABSOLUTE;
mFlags |= data.mRegs[mAddress].mFlags;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress].mValue;
changed = true;
}
else
{
data.mRegs[CPU_REG_X].Reset();
if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_X].mValue = data.mRegs[mAddress].mValue;
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_X].mValue = mAddress;
}
}
break;
case ASMIT_LDY:
if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_Y].mValue;
mMode = ASMIM_IMMEDIATE;
changed = true;
}
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAY;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
changed = true;
}
else if (final && data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A]))
{
mType = ASMIT_TAY;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
changed = true;
}
#if 1
else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE)
{
data.mRegs[CPU_REG_Y] = data.mRegs[mAddress];
mAddress = data.mRegs[CPU_REG_Y].mValue;
changed = true;
}
#endif
else if (final && data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && data.mRegs[mAddress].mLinkerObject && (data.mRegs[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
data.mRegs[CPU_REG_Y] = data.mRegs[mAddress];
mMode = ASMIM_ABSOLUTE;
mFlags |= data.mRegs[mAddress].mFlags;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress].mValue;
changed = true;
}
else
{
data.mRegs[CPU_REG_Y].Reset();
if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
data.mRegs[CPU_REG_Y].mValue = data.mRegs[mAddress].mValue;
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_Y].mValue = mAddress;
}
}
break;
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_AND:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE)
{
mAddress = data.mRegs[mAddress].mValue;
mMode = ASMIM_IMMEDIATE;
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE)
{
mAddress = data.mRegs[mAddress].mValue;
changed = true;
}
else if (data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && !final)
{
mMode = ASMIM_ABSOLUTE;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress].mValue;
changed = true;
}
break;
case ASMIT_STA:
if (data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A]) || data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE &&
data.mRegs[mAddress].mValue == ((data.mRegs[CPU_REG_A].mValue - 1) & 255))
{
mType = ASMIT_INC;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE &&
data.mRegs[mAddress].mValue == ((data.mRegs[CPU_REG_A].mValue + 1) & 255))
{
mType = ASMIT_DEC;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue;
changed = true;
}
else
{
data.ResetZeroPage(mAddress);
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE || data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS)
{
data.mRegs[mAddress] = data.mRegs[CPU_REG_A];
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE)
{
#if 1
if (data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode == NRDM_UNKNOWN &&
(mAddress >= BC_REG_FPARAMS && mAddress < BC_REG_FPARAMS_END) &&
!(data.mRegs[CPU_REG_A].mValue >= BC_REG_FPARAMS && data.mRegs[CPU_REG_A].mValue < BC_REG_FPARAMS_END))
{
data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode = NRDM_ZERO_PAGE;
data.mRegs[data.mRegs[CPU_REG_A].mValue].mValue = mAddress;
data.mRegs[mAddress].Reset();
}
else
#endif
{
data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue;
}
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE)
{
data.mRegs[mAddress] = data.mRegs[CPU_REG_A];
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_A].mValue = mAddress;
}
}
break;
case ASMIT_STX:
data.ResetZeroPage(mAddress);
if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE)
{
data.mRegs[mAddress].mMode = NRDM_IMMEDIATE;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_X].mValue;
}
else if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE)
{
data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_X].mValue;
}
else if (data.mRegs[CPU_REG_X].mMode == NRDM_ABSOLUTE)
{
data.mRegs[mAddress] = data.mRegs[CPU_REG_X];
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_X].mValue = mAddress;
}
break;
case ASMIT_STY:
data.ResetZeroPage(mAddress);
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
{
data.mRegs[mAddress].mMode = NRDM_IMMEDIATE;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_Y].mValue;
}
else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE)
{
data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE;
data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_Y].mValue;
}
else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ABSOLUTE)
{
data.mRegs[mAddress] = data.mRegs[CPU_REG_Y];
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_ZERO_PAGE;
data.mRegs[CPU_REG_Y].mValue = mAddress;
}
break;
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ROL:
case ASMIT_ROR:
data.ResetZeroPage(mAddress);
break;
}
}
else if (final && mMode == ASMIM_IMMEDIATE)
{
#if 1
switch (mType)
{
case ASMIT_LDA:
if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_Y].mValue == mAddress)
{
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
mType = ASMIT_TYA;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_X].mValue == mAddress)
{
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
mType = ASMIT_TXA;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
case ASMIT_LDX:
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
mType = ASMIT_TAX;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
case ASMIT_LDY:
if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == mAddress)
{
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
mType = ASMIT_TAY;
mMode = ASMIM_IMPLIED;
changed = true;
}
break;
}
#endif
}
else if (mMode == ASMIM_INDIRECT_Y)
{
if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress + 1].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress].mValue + 1 == data.mRegs[mAddress + 1].mValue)
{
mFlags |= NICT_ZPFLIPPED;
mAddress = data.mRegs[mAddress].mValue;
if (mType == ASMIT_LDA)
data.mRegs[CPU_REG_A].Reset();
}
else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject)
{
mMode = ASMIM_ABSOLUTE_Y;
mLinkerObject = data.mRegs[mAddress].mLinkerObject;
mAddress = data.mRegs[mAddress + 1].mValue;
if (mType == ASMIT_LDA)
data.mRegs[CPU_REG_A].Reset();
}
else if (mType == ASMIT_LDA)
{
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_INDIRECT_Y && data.mRegs[CPU_REG_A].mValue == mAddress)
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (data.mRegs[CPU_REG_X].SameData(*this))
{
mType = ASMIT_TXA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
changed = true;
}
else if (data.mRegs[CPU_REG_Y].SameData(*this))
{
mType = ASMIT_TYA;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_INDIRECT_Y;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_A].Reset();
}
if (ChangesAddress())
data.ResetIndirect(mAddress);
}
else if (mMode == ASMIM_ABSOLUTE_X)
{
if (mType == ASMIT_LDA)
{
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE_X;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_A].Reset();
}
else if (mType == ASMIT_LDY)
{
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_ABSOLUTE_X && data.mRegs[CPU_REG_Y].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAY;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
changed = true;
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE_X;
data.mRegs[CPU_REG_Y].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_Y].Reset();
}
if (ChangesAddress())
data.ResetAbsoluteXY(mLinkerObject, mAddress);
}
else if (mMode == ASMIM_ABSOLUTE_Y)
{
if (mType == ASMIT_LDA)
{
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_Y && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE_Y;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_A].Reset();
}
else if (mType == ASMIT_LDX)
{
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_ABSOLUTE_Y && data.mRegs[CPU_REG_X].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_Y && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAX;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
changed = true;
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE_Y;
data.mRegs[CPU_REG_X].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_X].Reset();
}
if (ChangesAddress())
data.ResetAbsoluteXY(mLinkerObject, mAddress);
}
else if (mMode == ASMIM_ABSOLUTE)
{
switch (mType)
{
case ASMIT_LDA:
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
if (mLive & LIVE_CPU_REG_Z)
{
mType = ASMIT_ORA;
mMode = ASMIM_IMMEDIATE;
mAddress = 0;
}
else
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
}
changed = true;
}
else
{
data.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_A].Reset();
break;
#if 1
case ASMIT_STA:
if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
{
if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (final || data.mRegs[CPU_REG_A].mMode == NRDM_UNKNOWN)
{
data.ResetAbsolute(mLinkerObject, mAddress);
data.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_A].mValue = mAddress;
data.mRegs[CPU_REG_A].mFlags = mFlags;
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
break;
#endif
case ASMIT_LDY:
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_Y].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_Y].mValue == mAddress)
{
if (!(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
}
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAY;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A];
changed = true;
}
else
{
data.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_Y].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_Y].Reset();
break;
case ASMIT_STY:
if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
{
if (data.mRegs[CPU_REG_Y].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_Y].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_Y].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[CPU_REG_Y].mMode == NRDM_UNKNOWN)
{
data.ResetAbsolute(mLinkerObject, mAddress);
data.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_Y].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_Y].mValue = mAddress;
data.mRegs[CPU_REG_Y].mFlags = mFlags;
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
break;
case ASMIT_LDX:
if (!(mFlags & NCIF_VOLATILE))
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_X].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_X].mValue == mAddress)
{
if (!(mLive & LIVE_CPU_REG_Z))
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
}
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
{
mType = ASMIT_TAX;
mMode = ASMIM_IMPLIED;
data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A];
changed = true;
}
else
{
data.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_X].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mFlags = mFlags;
}
}
else
data.mRegs[CPU_REG_X].Reset();
break;
case ASMIT_STX:
if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
{
if (data.mRegs[CPU_REG_X].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_X].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_X].mValue == mAddress)
{
mType = ASMIT_NOP;
mMode = ASMIM_IMPLIED;
changed = true;
}
else if (data.mRegs[CPU_REG_X].mMode == NRDM_UNKNOWN)
{
data.ResetAbsolute(mLinkerObject, mAddress);
data.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE;
data.mRegs[CPU_REG_X].mLinkerObject = mLinkerObject;
data.mRegs[CPU_REG_X].mValue = mAddress;
data.mRegs[CPU_REG_X].mFlags = mFlags;
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
}
else
data.ResetAbsolute(mLinkerObject, mAddress);
break;
default:
if (ChangesAddress())
data.ResetAbsolute(mLinkerObject, mAddress);
}
}
return changed;
}
void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet& providedTemps)
{
// check runtime calls
if (mType == ASMIT_JSR)
{
#if 1
if (mFlags & NCIF_USE_CPU_REG_A)
{
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
}
if (mFlags & NCIF_USE_CPU_REG_X)
{
if (!providedTemps[CPU_REG_X])
requiredTemps += CPU_REG_X;
}
if (mFlags & NCIF_USE_CPU_REG_Y)
{
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
}
if (mFlags & NCIF_RUNTIME)
{
for (int i = 0; i < 4; i++)
{
if (!providedTemps[BC_REG_ACCU + i])
requiredTemps += BC_REG_ACCU + i;
if (!providedTemps[BC_REG_WORK + i])
requiredTemps += BC_REG_WORK + i;
}
if (mFlags & NCIF_USE_ZP_32_X)
{
for (int i = 0; i < 4; i++)
{
if (!providedTemps[mParam + i])
requiredTemps += mParam + i;
}
}
if (mFlags & NCIF_FEXEC)
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
if (!providedTemps[i])
requiredTemps += i;
}
}
else if (mFlags & NICF_USE_WORKREGS)
{
for (int i = 0; i < 10; i++)
if (!providedTemps[BC_REG_WORK + i])
requiredTemps += BC_REG_WORK + i;
}
else
{
if (mLinkerObject)
{
for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
{
for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++)
{
if (!providedTemps[mLinkerObject->mTemporaries[i] + j])
requiredTemps += mLinkerObject->mTemporaries[i] + j;
}
}
}
}
#endif
providedTemps += BC_REG_ADDR + 0;
providedTemps += BC_REG_ADDR + 1;
for (int i = 0; i < 4; i++)
providedTemps += BC_REG_ACCU + i;
for (int i = 0; i < 8; i++)
providedTemps += BC_REG_WORK + i;
providedTemps += CPU_REG_A;
providedTemps += CPU_REG_X;
providedTemps += CPU_REG_Y;
providedTemps += CPU_REG_C;
providedTemps += CPU_REG_Z;
return;
}
if (mType == ASMIT_RTS)
{
#if 1
if (mFlags & NCIF_USE_CPU_REG_A)
{
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
}
if (mFlags & NCIF_LOWER)
{
if (!providedTemps[BC_REG_ACCU + 0]) requiredTemps += BC_REG_ACCU + 0;
if (mFlags & NCIF_UPPER)
{
if (!providedTemps[BC_REG_ACCU + 1]) requiredTemps += BC_REG_ACCU + 1;
if (mFlags & NCIF_LONG)
{
if (!providedTemps[BC_REG_ACCU + 2]) requiredTemps += BC_REG_ACCU + 2;
if (!providedTemps[BC_REG_ACCU + 3]) requiredTemps += BC_REG_ACCU + 3;
}
}
}
#endif
#if 0
for (int i = 0; i < 4; i++)
{
if (!providedTemps[BC_REG_ACCU + i])
requiredTemps += BC_REG_ACCU + i;
}
#endif
if (!providedTemps[BC_REG_STACK])
requiredTemps += BC_REG_STACK;
if (!providedTemps[BC_REG_STACK + 1])
requiredTemps += BC_REG_STACK + 1;
if (!providedTemps[BC_REG_LOCALS])
requiredTemps += BC_REG_LOCALS;
if (!providedTemps[BC_REG_LOCALS + 1])
requiredTemps += BC_REG_LOCALS + 1;
return;
}
// check index
switch (mMode)
{
case ASMIM_ZERO_PAGE_X:
case ASMIM_INDIRECT_X:
case ASMIM_ABSOLUTE_X:
if (!providedTemps[CPU_REG_X])
requiredTemps += CPU_REG_X;
break;
case ASMIM_ZERO_PAGE_Y:
case ASMIM_ABSOLUTE_Y:
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
break;
case ASMIM_INDIRECT_Y:
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
if (!providedTemps[mAddress])
requiredTemps += mAddress;
if (!providedTemps[mAddress + 1])
requiredTemps += mAddress + 1;
break;
}
// check carry flags
switch (mType)
{
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
if (!providedTemps[CPU_REG_C])
requiredTemps += CPU_REG_C;
providedTemps += CPU_REG_C;
break;
case ASMIT_CMP:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_CLC:
case ASMIT_SEC:
providedTemps += CPU_REG_C;
break;
case ASMIT_BCC:
case ASMIT_BCS:
if (!providedTemps[CPU_REG_C])
requiredTemps += CPU_REG_C;
break;
case ASMIT_BEQ:
case ASMIT_BNE:
case ASMIT_BPL:
case ASMIT_BMI:
if (!providedTemps[CPU_REG_Z])
requiredTemps += CPU_REG_Z;
break;
}
// check zero flag
switch (mType)
{
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_INC:
case ASMIT_DEC:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
case ASMIT_LDA:
case ASMIT_LDX:
case ASMIT_LDY:
case ASMIT_BIT:
case ASMIT_TAX:
case ASMIT_TXA:
case ASMIT_TAY:
case ASMIT_TYA:
case ASMIT_DEY:
case ASMIT_INY:
case ASMIT_DEX:
case ASMIT_INX:
providedTemps += CPU_REG_Z;
break;
}
// check CPU register
switch (mType)
{
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_ASL:
case ASMIT_LSR:
if (mMode == ASMIM_IMPLIED)
{
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
providedTemps += CPU_REG_A;
}
break;
case ASMIT_LDA:
providedTemps += CPU_REG_A;
break;
case ASMIT_CMP:
case ASMIT_STA:
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
break;
case ASMIT_CPX:
case ASMIT_STX:
if (!providedTemps[CPU_REG_X])
requiredTemps += CPU_REG_X;
break;
case ASMIT_CPY:
case ASMIT_STY:
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
break;
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_AND:
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
providedTemps += CPU_REG_A;
break;
case ASMIT_LDX:
providedTemps += CPU_REG_X;
break;
case ASMIT_INX:
case ASMIT_DEX:
if (!providedTemps[CPU_REG_X])
requiredTemps += CPU_REG_X;
providedTemps += CPU_REG_X;
break;
case ASMIT_LDY:
providedTemps += CPU_REG_Y;
break;
case ASMIT_INY:
case ASMIT_DEY:
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
providedTemps += CPU_REG_Y;
break;
case ASMIT_TAX:
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
providedTemps += CPU_REG_X;
break;
case ASMIT_TAY:
if (!providedTemps[CPU_REG_A])
requiredTemps += CPU_REG_A;
providedTemps += CPU_REG_Y;
break;
case ASMIT_TXA:
if (!providedTemps[CPU_REG_X])
requiredTemps += CPU_REG_X;
providedTemps += CPU_REG_A;
break;
case ASMIT_TYA:
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
providedTemps += CPU_REG_A;
break;
}
if (mMode == ASMIM_ZERO_PAGE)
{
switch (mType)
{
case ASMIT_STA:
case ASMIT_STX:
case ASMIT_STY:
providedTemps += mAddress;
break;
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_INC:
case ASMIT_DEC:
if (!providedTemps[mAddress])
requiredTemps += mAddress;
providedTemps += mAddress;
break;
default:
if (!providedTemps[mAddress])
requiredTemps += mAddress;
}
}
}
void NativeCodeInstruction::CopyMode(const NativeCodeInstruction& ins)
{
mMode = ins.mMode;
mAddress = ins.mAddress;
mLinkerObject = ins.mLinkerObject;
mFlags = (mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | (ins.mFlags & (NCIF_LOWER | NCIF_UPPER | NCIF_VOLATILE));
}
void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block)
{
bool weak = true;
if (mIns)
{
if (ChangesAddress() && (mMode != ASMIM_ZERO_PAGE || mLinkerObject))
weak = false;
else if (mType == ASMIT_JSR && !(mFlags & NCIF_RUNTIME))
weak = false;
block->PutLocation(mIns->mLocation, weak);
}
if (mType == ASMIT_BYTE)
block->PutByte(mAddress);
else if (mType == ASMIT_JSR && (mFlags & NCIF_BREAKPOINT))
{
LinkerReference rl;
rl.mOffset = block->mCode.Size();
rl.mRefObject = nullptr;
rl.mRefOffset = 0;
rl.mFlags = LREF_BREAKPOINT;
block->mRelocations.Push(rl);
}
else if (mType == ASMIT_JSR && mLinkerObject && (mLinkerObject->mFlags & LOBJF_INLINE))
{
int pos = block->mCode.Size();
int size = mLinkerObject->mSize;
// skip RTS on embedding
if (mLinkerObject->mData[size - 1] == 0x60)
size--;
for (int i = 0; i < size; i++)
block->PutByte(mLinkerObject->mData[i]);
for (int i = 0; i < mLinkerObject->mReferences.Size(); i++)
{
LinkerReference rl = *(mLinkerObject->mReferences[i]);
if (rl.mFlags & LREF_TEMPORARY)
{
block->mCode[pos + rl.mOffset] += mLinkerObject->mTemporaries[rl.mRefOffset];
}
else
{
rl.mOffset += pos;
if (rl.mRefObject == rl.mObject)
{
rl.mRefObject = nullptr;
rl.mRefOffset += pos;
rl.mFlags |= LREF_INBLOCK;
}
block->mRelocations.Push(rl);
}
}
}
else
{
if (mType == ASMIT_JSR && (mFlags & NCIF_USE_ZP_32_X))
{
block->PutOpcode(AsmInsOpcodes[ASMIT_LDX][ASMIM_IMMEDIATE]);
block->PutByte(mParam);
}
AsmInsMode mode = mMode;
if (mode == ASMIM_ABSOLUTE && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
mode = ASMIM_ZERO_PAGE;
else if (mode == ASMIM_ABSOLUTE_X && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_X))
mode = ASMIM_ZERO_PAGE_X;
else if (mode == ASMIM_ABSOLUTE_Y && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_Y))
mode = ASMIM_ZERO_PAGE_Y;
else if (mode == ASMIM_ABSOLUTE && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
mode = ASMIM_ZERO_PAGE;
else if (mode == ASMIM_ABSOLUTE_X && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_X))
mode = ASMIM_ZERO_PAGE_X;
else if (mode == ASMIM_ABSOLUTE_Y && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_Y))
mode = ASMIM_ZERO_PAGE_Y;
if (mode == ASMIM_IMMEDIATE_ADDRESS)
{
assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
assert(HasAsmInstructionMode(mType, ASMIM_IMMEDIATE));
block->PutOpcode(AsmInsOpcodes[mType][ASMIM_IMMEDIATE]);
}
else
{
assert(HasAsmInstructionMode(mType, mode));
block->PutOpcode(AsmInsOpcodes[mType][mode]);
}
switch (mode)
{
case ASMIM_IMPLIED:
break;
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_ZERO_PAGE_Y:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
if (mLinkerObject)
{
LinkerReference rl;
rl.mOffset = block->mCode.Size();
rl.mRefObject = mLinkerObject;
rl.mRefOffset = mAddress;
rl.mFlags = LREF_LOWBYTE;
block->mRelocations.Push(rl);
block->PutByte(0);
}
else
{
if (mAddress == 0)
block->mProc->mGenerator->mErrors->Error(mIns->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced");
block->PutByte(uint8(mAddress));
}
break;
case ASMIM_IMMEDIATE:
block->PutByte(uint8(mAddress));
break;
case ASMIM_IMMEDIATE_ADDRESS:
if (mLinkerObject)
{
LinkerReference rl;
rl.mOffset = block->mCode.Size();
rl.mFlags = 0;
if (mFlags & NCIF_LOWER)
rl.mFlags |= LREF_LOWBYTE;
if (mFlags & NCIF_UPPER)
rl.mFlags |= LREF_HIGHBYTE;
rl.mRefObject = mLinkerObject;
rl.mRefObject = mLinkerObject;
rl.mRefOffset = mAddress;
if (mLinkerObject)
mLinkerObject->mFlags |= LOBJF_NO_CROSS;
block->mRelocations.Push(rl);
block->PutByte(0);
}
else
{
block->PutByte(uint8(mAddress));
}
break;
case ASMIM_ABSOLUTE:
case ASMIM_INDIRECT:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
if (mLinkerObject)
{
int w = 0;
LinkerReference rl;
rl.mOffset = block->mCode.Size();
rl.mRefObject = mLinkerObject;
if (mFlags & NCIF_LOWER)
{
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
rl.mRefOffset = mAddress;
}
else
{
rl.mFlags = LREF_HIGHBYTE;
rl.mOffset++;
rl.mRefOffset = mAddress & 0xff00;
w = mAddress & 0xff;
}
if (mode != ASMIM_ABSOLUTE)
mLinkerObject->mFlags |= LOBJF_NO_CROSS;
block->mRelocations.Push(rl);
block->PutWord(w);
}
else
{
if (mAddress == 0)
block->mProc->mGenerator->mErrors->Error(mIns->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced");
block->PutWord(uint16(mAddress));
}
break;
case ASMIM_RELATIVE:
block->PutByte(uint8(mAddress));
break;
}
}
if (mIns)
block->PutLocation(mIns->mLocation, weak);
}
void NativeCodeBasicBlock::PutLocation(const Location& location, bool weak)
{
int sz = mCodeLocations.Size();
if (sz > 0 &&
(weak ||
(mCodeLocations[sz - 1].mLocation.mFileName == location.mFileName &&
mCodeLocations[sz - 1].mLocation.mLine == location.mLine)))
{
mCodeLocations[sz - 1].mEnd = this->mCode.Size();
if (mCodeLocations[sz - 1].mWeak)
mCodeLocations[sz - 1].mWeak = weak;
}
else if (sz > 0 && mCodeLocations[sz - 1].mWeak)
{
mCodeLocations[sz - 1].mLocation = location;
mCodeLocations[sz - 1].mEnd = this->mCode.Size();
mCodeLocations[sz - 1].mWeak = weak;
}
else
{
CodeLocation loc;
loc.mLocation = location;
loc.mStart = loc.mEnd = this->mCode.Size();
loc.mWeak = weak;
mCodeLocations.Push(loc);
}
}
void NativeCodeBasicBlock::PutOpcode(short opcode)
{
assert(opcode >= 0 && opcode < 256);
this->mCode.Push(uint8(opcode));
}
void NativeCodeBasicBlock::PutByte(uint8 code)
{
this->mCode.Push(code);
}
void NativeCodeBasicBlock::PutWord(uint16 code)
{
this->mCode.Push((uint8)(code & 0xff));
this->mCode.Push((uint8)(code >> 8));
}
static AsmInsType InvertBranchCondition(AsmInsType code)
{
switch (code)
{
case ASMIT_BEQ: return ASMIT_BNE;
case ASMIT_BNE: return ASMIT_BEQ;
case ASMIT_BPL: return ASMIT_BMI;
case ASMIT_BMI: return ASMIT_BPL;
case ASMIT_BCS: return ASMIT_BCC;
case ASMIT_BCC: return ASMIT_BCS;
default:
return code;
}
}
static AsmInsType TransposeBranchCondition(AsmInsType code)
{
switch (code)
{
case ASMIT_BEQ: return ASMIT_BEQ;
case ASMIT_BNE: return ASMIT_BNE;
case ASMIT_BPL: return ASMIT_BMI;
case ASMIT_BMI: return ASMIT_BPL;
case ASMIT_BCS: return ASMIT_BCC;
case ASMIT_BCC: return ASMIT_BCS;
default:
return code;
}
}
int NativeCodeBasicBlock::PutJump(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, int offset)
{
if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
{
if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
{
this->mCode[this->mCode.Size() - 3] = 0x4c;
return 0;
}
else
{
PutByte(0x60);
return 1;
}
}
else if (target->mIns.Size() == 2 && target->mIns[0].IsSimpleJSR() && target->mIns[1].mType == ASMIT_RTS)
{
PutByte(0x4c);
LinkerReference rl;
rl.mObject = nullptr;
rl.mOffset = mCode.Size();
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
rl.mRefObject = target->mIns[0].mLinkerObject;
rl.mRefOffset = target->mIns[0].mAddress;
mRelocations.Push(rl);
PutWord(0);
return 3;
}
#if JUMP_TO_BRANCH
else if (offset >= -126 && offset <= 129)
{
if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
if (mNDataSet.mRegs[CPU_REG_C].mValue)
PutOpcode(AsmInsOpcodes[ASMIT_BCS][ASMIM_RELATIVE]);
else
PutOpcode(AsmInsOpcodes[ASMIT_BCC][ASMIM_RELATIVE]);
PutByte(offset - 2);
return 2;
}
else if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
if (mNDataSet.mRegs[CPU_REG_Z].mValue)
PutOpcode(AsmInsOpcodes[ASMIT_BNE][ASMIM_RELATIVE]);
else
PutOpcode(AsmInsOpcodes[ASMIT_BEQ][ASMIM_RELATIVE]);
PutByte(offset - 2);
return 2;
}
}
#endif
PutByte(0x4c);
LinkerReference rl;
rl.mObject = nullptr;
rl.mOffset = mCode.Size();
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
rl.mRefObject = nullptr;
rl.mRefOffset = target->mOffset;
mRelocations.Push(rl);
PutWord(0);
return 3;
}
int NativeCodeBasicBlock::BranchByteSize(NativeCodeBasicBlock* target, int from, int to)
{
if (to - from >= -126 && to - from <= 129)
return 2;
else
{
if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
return 3;
return 5;
}
}
int NativeCodeBasicBlock::JumpByteSize(NativeCodeBasicBlock* target, int offset)
{
if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
{
if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
return 0;
else
return 1;
}
else if (target->mIns.Size() == 2 && target->mIns[0].IsSimpleJSR() && target->mIns[1].mType == ASMIT_RTS)
{
return 3;
}
#if JUMP_TO_BRANCH
else if (offset >= -126 && offset <= 129)
{
if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
return 2;
else if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
return 2;
else
return 3;
}
#endif
else
return 3;
}
int NativeCodeBasicBlock::PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int offset)
{
if (offset >= -126 && offset <= 129)
{
PutOpcode(AsmInsOpcodes[code][ASMIM_RELATIVE]);
PutByte(offset - 2);
return 2;
}
else
{
PutOpcode(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]);
if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
{
PutByte(1);
PutByte(0x60);
return 3;
}
else
{
PutByte(3);
PutByte(0x4c);
LinkerReference rl;
rl.mObject = nullptr;
rl.mOffset = mCode.Size();
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
rl.mRefObject = nullptr;
rl.mRefOffset = mOffset + mCode.Size() + offset - 3;
mRelocations.Push(rl);
PutWord(0);
return 5;
}
}
}
void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure* proc, const InterInstruction* ins, const InterOperand& op, InterType type, int reg)
{
if (type == IT_FLOAT)
{
union { float f; unsigned int v; } cc;
cc.f = float(op.mFloatConst);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (type == IT_POINTER)
{
if (op.mMemory == IM_GLOBAL)
{
if (op.mIntConst < 0 || op.mIntConst > op.mLinkerObject->mSize)
proc->mModule->mErrors->Error(ins->mLocation, EWARN_UNDEFINED_POINTER_ARITHMETIC, "Undefined constant pointer arithmetic");
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (op.mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (op.mMemory == IM_FPARAM || op.mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + op.mVarIndex + op.mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (op.mMemory == IM_FRAME)
{
int index = op.mVarIndex + int(op.mIntConst) + 2;
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (op.mMemory == IM_LOCAL || op.mMemory == IM_PARAM)
{
int index = int(op.mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (op.mMemory == IM_LOCAL)
index += proc->mLocalVars[op.mVarIndex]->mOffset;
else
index += op.mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 2);
if (index != 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
if (index != 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
if (index != 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (op.mMemory == IM_PROCEDURE)
{
NativeCodeInstruction lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_LOWER);
NativeCodeInstruction hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_UPPER);
mIns.Push(lins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(hins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
else if (type == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
if (InterTypeSize[type] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
}
void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure * proc, const InterInstruction * ins, InterType type, int reg)
{
LoadConstantToReg(proc, ins, ins->mConst, type, reg);
}
void NativeCodeBasicBlock::LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins)
{
LoadConstantToReg(proc, ins, ins->mDst.mType, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]);
}
void NativeCodeBasicBlock::CheckFrameIndex(const InterInstruction* ins, int& reg, int& index, int size, int treg)
{
if (index < 0 || index + size > 256)
{
if (treg == 0)
treg = BC_REG_ADDR;
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
index = 0;
reg = treg;
}
}
void NativeCodeBasicBlock::StoreValue(InterCodeProcedure* proc, const InterInstruction * ins)
{
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mVolatile)
flags |= NCIF_VOLATILE;
if (ins->mSrc[0].mType == IT_FLOAT)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[0].mTemp < 0)
{
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[0].mFloatConst);
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y,BC_REG_STACK));
}
}
else
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
if (ins->mSrc[0].mFinal && CheckPredAccuStore(sreg))
{
// cull previous store from accu to temp using direcrt forwarding from accu
mIns.SetSize(mIns.Size() - 8);
sreg = BC_REG_ACCU;
}
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
}
else
{
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[0].mFloatConst);
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
if (stride * 4 <= 256)
{
CheckFrameIndex(ins, reg, index, stride * 4);
for (int i = 0; i < 4; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < 4; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
else
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
if (stride * 4 <= 256)
{
CheckFrameIndex(ins, reg, index, stride * 4);
for (int i = 0; i < 4; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < 4; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
}
}
else if (ins->mSrc[0].mType == IT_POINTER)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
}
else
{
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
if (2 * stride <= 256)
{
CheckFrameIndex(ins, reg, index, 2 * stride);
for (int i = 0; i < 2; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < 2; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
else
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
if (2 * stride <= 256)
{
CheckFrameIndex(ins, reg, index, 2 * stride);
for (int i = 0; i < 2; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < 2; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
}
}
else
{
if (ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[0].mTemp < 0)
{
if (InterTypeSize[ins->mSrc[0].mType] == 1)
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else if (InterTypeSize[ins->mSrc[0].mType] == 2)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + stride));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else if (InterTypeSize[ins->mSrc[0].mType] == 4)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3 * stride));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
}
else
{
if (InterTypeSize[ins->mSrc[0].mType] == 1)
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else if (InterTypeSize[ins->mSrc[0].mType] == 2)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + stride));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else if (InterTypeSize[ins->mSrc[0].mType] == 4)
{
int stride = ins->mSrc[1].mStride;
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3 * stride));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
int reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, reg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
}
}
else
{
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
int size = InterTypeSize[ins->mSrc[0].mType];
if (stride * size <= 256)
{
CheckFrameIndex(ins, reg, index, stride * size);
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < size; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
else
{
if (ins->mSrc[1].mMemory == IM_INDIRECT)
{
int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int index = int(ins->mSrc[1].mIntConst);
int stride = ins->mSrc[1].mStride;
int size = InterTypeSize[ins->mSrc[0].mType];
if (stride * size <= 256)
{
CheckFrameIndex(ins, reg, index, stride * size);
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
}
}
else
{
for (int i = 0; i < size; i++)
{
CheckFrameIndex(ins, reg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
index += stride;
}
}
}
}
}
}
}
void NativeCodeBasicBlock::LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
flags |= NCIF_VOLATILE;
for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
{
if (i != 0)
mIns.Push(NativeCodeInstruction(rins, ASMIT_INY, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
if (rins->mDst.mTemp == iins->mSrc[1].mTemp)
mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
else
mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
}
if (rins->mDst.mTemp == iins->mSrc[1].mTemp)
{
for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
}
}
}
void NativeCodeBasicBlock::StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
flags |= NCIF_VOLATILE;
for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
{
if (i != 0)
mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED));
if (wins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
}
}
void NativeCodeBasicBlock::LoadAbsoluteByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins)
{
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
int address = int(iins->mSrc[1].mIntConst + rins->mSrc[0].mIntConst);
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
flags |= NCIF_VOLATILE;
for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE_X, address + i * rins->mSrc[0].mStride, iins->mSrc[1].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
}
}
void NativeCodeBasicBlock::StoreAbsoluteByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
int address = int(iins->mSrc[1].mIntConst + wins->mSrc[1].mIntConst);
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
flags |= NCIF_VOLATILE;
for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
{
if (wins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE_X, address + i * wins->mSrc[1].mStride, iins->mSrc[1].mLinkerObject, flags));
}
}
void NativeCodeBasicBlock::StoreByteOffsetIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(iins, ASMIT_CLC));
mIns.Push(NativeCodeInstruction(iins, ASMIT_ADC, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(iins, ASMIT_TAY));
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
flags |= NCIF_VOLATILE;
for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
{
if (i != 0)
mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED));
if (wins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
}
}
void NativeCodeBasicBlock::LoadStoreIndirectPair(InterCodeProcedure* proc, const InterInstruction* wins0, const InterInstruction* wins1)
{
int sreg = BC_REG_TMP + proc->mTempOffset[wins0->mSrc[0].mTemp];
int ireg0 = BC_REG_TMP + proc->mTempOffset[wins0->mSrc[1].mTemp];
int index0 = int(wins0->mSrc[1].mIntConst);
uint32 wflags0 = NCIF_LOWER | NCIF_UPPER;
if (wins0->mVolatile)
wflags0 |= NCIF_VOLATILE;
int ireg1 = BC_REG_TMP + proc->mTempOffset[wins1->mSrc[1].mTemp];
int index1 = int(wins1->mSrc[1].mIntConst);
uint32 wflags1 = NCIF_LOWER | NCIF_UPPER;
if (wins1->mVolatile)
wflags1 |= NCIF_VOLATILE;
CheckFrameIndex(wins0, ireg0, index0, 1, BC_REG_ADDR);
CheckFrameIndex(wins1, ireg1, index1, 1, BC_REG_ACCU);
mIns.Push(NativeCodeInstruction(wins0, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(wins0, ASMIT_LDY, ASMIM_IMMEDIATE, index0));
mIns.Push(NativeCodeInstruction(wins0, ASMIT_STA, ASMIM_INDIRECT_Y, ireg0, nullptr, wflags0));
mIns.Push(NativeCodeInstruction(wins1, ASMIT_LDY, ASMIM_IMMEDIATE, index1));
mIns.Push(NativeCodeInstruction(wins1, ASMIT_STA, ASMIM_INDIRECT_Y, ireg1, nullptr, wflags1));
}
void NativeCodeBasicBlock::LoadStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* wins)
{
int size = InterTypeSize[wins->mSrc[0].mType];
AsmInsMode rmode = ASMIM_INDIRECT_Y;
int rindex = int(rins->mSrc[0].mIntConst);
int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
LinkerObject* rlobject = nullptr;
int rstride = rins->mSrc[0].mStride;
uint32 rflags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
rflags |= NCIF_VOLATILE;
switch (rins->mSrc[0].mMemory)
{
case IM_PARAM:
rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_LOCAL:
rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PROCEDURE:
case IM_GLOBAL:
rmode = ASMIM_ABSOLUTE;
rlobject = rins->mSrc[0].mLinkerObject;
rindex = int(rins->mSrc[0].mIntConst);
break;
case IM_FRAME:
rindex = int(rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst + 2);
rareg = BC_REG_STACK;
break;
case IM_INDIRECT:
rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
break;
case IM_ABSOLUTE:
rmode = ASMIM_ABSOLUTE;
rindex = int(rins->mSrc[0].mIntConst);
break;
case IM_FPARAM:
case IM_FFRAME:
rmode = ASMIM_ZERO_PAGE;
rareg = int(BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst);
break;
}
AsmInsMode wmode = ASMIM_INDIRECT_Y;
int windex = int(wins->mSrc[1].mIntConst);
int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
LinkerObject* wlobject = nullptr;
int wstride = wins->mSrc[1].mStride;
uint32 wflags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
wflags |= NCIF_VOLATILE;
switch (wins->mSrc[1].mMemory)
{
case IM_PARAM:
windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_LOCAL:
windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PROCEDURE:
case IM_GLOBAL:
wmode = ASMIM_ABSOLUTE;
wlobject = wins->mSrc[1].mLinkerObject;
windex = int(wins->mSrc[1].mIntConst);
break;
case IM_FRAME:
windex = int(wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst + 2);
wareg = BC_REG_STACK;
break;
case IM_INDIRECT:
wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
break;
case IM_ABSOLUTE:
wmode = ASMIM_ABSOLUTE;
windex = int(wins->mSrc[1].mIntConst);
break;
case IM_FPARAM:
case IM_FFRAME:
wmode = ASMIM_ZERO_PAGE;
wareg = BC_REG_FPARAMS + wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
break;
}
for (int i = 0; i < size; i++)
{
if (rmode == ASMIM_INDIRECT_Y)
CheckFrameIndex(rins, rareg, rindex, 1, BC_REG_ADDR);
if (wmode == ASMIM_INDIRECT_Y)
CheckFrameIndex(wins, wareg, windex, 1, BC_REG_ACCU);
if (rmode == ASMIM_INDIRECT_Y)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex));
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, rareg, nullptr, rflags));
}
else if (rmode == ASMIM_ZERO_PAGE)
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, rareg + i));
else
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rindex, rlobject, rflags));
if (wmode == ASMIM_INDIRECT_Y)
{
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, wareg, nullptr, wflags));
}
else if (wmode == ASMIM_ZERO_PAGE)
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, wareg + i));
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, windex, wlobject, wflags));
rindex += rstride;
windex += wstride;
}
}
void NativeCodeBasicBlock::LoadStoreValue(InterCodeProcedure* proc, const InterInstruction * rins, const InterInstruction * wins)
{
uint32 rflags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
rflags |= NCIF_VOLATILE;
uint32 wflags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
wflags |= NCIF_VOLATILE;
if (rins->mDst.mType == IT_FLOAT)
{
}
else if (rins->mDst.mType == IT_POINTER)
{
}
else
{
if (InterTypeSize[wins->mSrc[0].mType] == 1)
{
if (rins->mSrc[0].mTemp < 0)
{
if (rins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, rins->mSrc[0].mLinkerObject, rflags));
}
else if (rins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, nullptr, rflags));
}
else if (rins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst));
}
else if (rins->mSrc[0].mMemory == IM_LOCAL || rins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(rins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (rins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset;
else
index += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(rins, areg, index, 1);
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
}
}
else
{
if (rins->mSrc[0].mMemory == IM_INDIRECT)
{
int areg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
int index = int(rins->mSrc[0].mIntConst);
CheckFrameIndex(rins, areg, index, 1);
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
}
}
if (wins->mSrc[1].mTemp < 0)
{
if (wins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, wins->mSrc[1].mIntConst, wins->mSrc[1].mLinkerObject, wflags));
}
else if (wins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, wins->mSrc[1].mIntConst, nullptr, wflags));
}
else if (wins->mSrc[1].mMemory == IM_FPARAM || wins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst));
}
else if (wins->mSrc[1].mMemory == IM_LOCAL || wins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(wins->mSrc[1].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (wins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset;
else
index += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(wins, areg, index, 1);
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, areg));
}
else if (wins->mSrc[1].mMemory == IM_FRAME)
{
int index = wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst) + 2;
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
}
else
{
if (wins->mSrc[1].mMemory == IM_INDIRECT)
{
int areg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
int index = int(wins->mSrc[1].mIntConst);
CheckFrameIndex(wins, areg, index, 1);
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, areg));
}
}
}
}
}
bool NativeCodeBasicBlock::LoadLoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins1, const InterInstruction* rins0, const InterInstruction* oins, const InterInstruction* wins)
{
if (rins1->mSrc[0].mMemory == IM_INDIRECT && rins0->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT)
{
if (rins1->mSrc[0].mStride != 1 || rins0->mSrc[0].mStride != 1 || wins->mSrc[1].mStride != 1)
return false;
int size = InterTypeSize[oins->mDst.mType];
if (!wins->mSrc[0].mFinal)
{
if (wins->mSrc[0].mTemp == rins1->mSrc[0].mTemp || wins->mSrc[0].mTemp == rins0->mSrc[0].mTemp)
return false;
}
switch (oins->mOperator)
{
case IA_ADD:
mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
break;
default:
return false;
}
for (int i = 0; i < size; i++)
{
if (rins1->mSrc[0].mIntConst == wins->mSrc[1].mIntConst && rins0->mSrc[0].mIntConst != wins->mSrc[1].mIntConst)
{
mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i));
mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i));
mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp]));
}
else
{
mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i));
mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i));
mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp]));
}
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst + i));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));
if (!wins->mSrc[0].mFinal)
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
}
return true;
}
#if 1
else if (rins1->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT && rins0->mSrc[0].mMemory == IM_FPARAM)
{
if (rins1->mSrc[0].mTemp == wins->mSrc[1].mTemp && rins1->mSrc[0].mIntConst == wins->mSrc[1].mIntConst && rins1->mSrc[0].mStride == wins->mSrc[1].mStride &&
wins->mSrc[0].mFinal && wins->mSrc[1].mFinal)
{
int size = InterTypeSize[oins->mDst.mType];
AsmInsType aop;
switch (oins->mOperator)
{
case IA_ADD:
mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
aop = ASMIT_ADC;
break;
case IA_OR:
aop = ASMIT_ORA;
break;
case IA_XOR:
aop = ASMIT_EOR;
break;
case IA_AND:
aop = ASMIT_AND;
break;
default:
return false;
}
int offset = int(wins->mSrc[1].mIntConst);
for (int i = 0; i < size; i++)
{
while (offset >= 256)
{
mIns.Push(NativeCodeInstruction(rins1, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp] + 1));
offset -= 256;
}
mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, offset));
mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + rins0->mSrc[0].mVarIndex + int(rins0->mSrc[0].mIntConst) + i));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));
offset += wins->mSrc[1].mStride;
}
return true;
}
return false;
}
else if (rins0->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT && rins1->mSrc[0].mMemory == IM_FPARAM)
{
return false;
}
#endif
else
return false;
}
bool NativeCodeBasicBlock::LoadUnopStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, const InterInstruction* wins)
{
int size = InterTypeSize[wins->mSrc[0].mType];
int rstride = rins->mSrc[0].mStride;
int wstride = wins->mSrc[1].mStride;
if (size > 1 && rstride != wstride)
return false;
AsmInsMode ram = ASMIM_INDIRECT_Y, wam = ASMIM_INDIRECT_Y;
bool sfinal = wins->mSrc[0].mFinal;
int imm;
AsmInsType at;
switch (oins->mOperator)
{
case IA_NEG:
mIns.Push(NativeCodeInstruction(oins, ASMIT_SEC));
imm = 0x00;
at = ASMIT_SBC;
break;
case IA_NOT:
imm = 0xff;
at = ASMIT_EOR;
break;
default:
return false;
}
int rindex = int(rins->mSrc[0].mIntConst);
int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
switch (rins->mSrc[0].mMemory)
{
case IM_INDIRECT:
rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
break;
case IM_LOCAL:
rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PARAM:
rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_FPARAM:
case IM_FFRAME:
ram = ASMIM_ZERO_PAGE;
rareg = BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + int(rins->mSrc[0].mIntConst);
break;
default:
return false;
}
int windex = int(wins->mSrc[1].mIntConst);
int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
switch (wins->mSrc[1].mMemory)
{
case IM_INDIRECT:
wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
break;
case IM_LOCAL:
windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PARAM:
windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_FPARAM:
case IM_FFRAME:
wam = ASMIM_ZERO_PAGE;
wareg = BC_REG_FPARAMS + +wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
break;
default:
return false;
}
uint32 rflags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
rflags |= NCIF_VOLATILE;
uint32 wflags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
wflags |= NCIF_VOLATILE;
for (int i = 0; i < size; i++)
{
if (ram == ASMIM_INDIRECT_Y)
CheckFrameIndex(rins, rareg, rindex, 1, BC_REG_ADDR);
if (wam == ASMIM_INDIRECT_Y)
CheckFrameIndex(wins, wareg, windex, 1, BC_REG_ACCU);
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMMEDIATE, imm));
if (ram == ASMIM_INDIRECT_Y)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex));
mIns.Push(NativeCodeInstruction(oins, at, ram, rareg));
}
else
mIns.Push(NativeCodeInstruction(oins, at, ram, rareg + i));
if (!sfinal)
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
if (wam == ASMIM_INDIRECT_Y)
{
if (ram != ASMIM_INDIRECT_Y || rindex != windex)
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg));
}
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg + i));
rindex += rstride;
windex += wstride;
}
return true;
}
bool NativeCodeBasicBlock::LoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, int oindex, const InterInstruction* wins)
{
int size = InterTypeSize[oins->mDst.mType];
AsmInsType at = ASMIT_ADC, an = ASMIT_ADC;
AsmInsMode am = oins->mSrc[oindex].mTemp < 0 ? ASMIM_IMMEDIATE : ASMIM_ZERO_PAGE, ram = ASMIM_INDIRECT_Y, wam = ASMIM_INDIRECT_Y;
bool reverse = false, sfinal = wins->mSrc[0].mFinal;
switch (oins->mOperator)
{
case IA_ADD:
at = an = ASMIT_ADC;
break;
case IA_SUB:
at = an = ASMIT_SBC;
if (oindex == 1)
reverse = true;
break;
case IA_AND:
at = an = ASMIT_AND;
break;
case IA_OR:
at = an = ASMIT_ORA;
break;
case IA_XOR:
at = an = ASMIT_EOR;
break;
case IA_SHL:
if (oindex == 0 && oins->mSrc[oindex].mTemp < 0 && oins->mSrc[oindex].mIntConst == 1)
{
at = ASMIT_ASL;
an = ASMIT_ROL;
am = ASMIM_IMPLIED;
}
else
return false;
break;
default:
return false;
}
int rindex = int(rins->mSrc[0].mIntConst);
int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
int rstride = rins->mSrc[0].mStride;
switch (rins->mSrc[0].mMemory)
{
case IM_INDIRECT:
rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
break;
case IM_LOCAL:
rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PARAM:
rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_FPARAM:
case IM_FFRAME:
ram = ASMIM_ZERO_PAGE;
rareg = BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + int(rins->mSrc[0].mIntConst);
break;
default:
return false;
}
int windex = int(wins->mSrc[1].mIntConst);
int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
int wstride = wins->mSrc[1].mStride;
switch (wins->mSrc[1].mMemory)
{
case IM_INDIRECT:
wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
break;
case IM_LOCAL:
windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
break;
case IM_PARAM:
windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
break;
case IM_FPARAM:
case IM_FFRAME:
wam = ASMIM_ZERO_PAGE;
wareg = BC_REG_FPARAMS + +wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
break;
default:
return false;
}
if (rstride * (size - 1) >= 256 || wstride * (size - 1) >= 256)
return false;
uint32 rflags = NCIF_LOWER | NCIF_UPPER;
if (rins->mVolatile)
rflags |= NCIF_VOLATILE;
uint32 wflags = NCIF_LOWER | NCIF_UPPER;
if (wins->mVolatile)
wflags |= NCIF_VOLATILE;
if (ram == ASMIM_INDIRECT_Y && wam == ASMIM_INDIRECT_Y && rareg == wareg && rindex == windex)
{
CheckFrameIndex(rins, rareg, rindex, (size - 1) * rstride + 1, BC_REG_ADDR);
windex = rindex;
wareg = rareg;
}
else
{
if (ram == ASMIM_INDIRECT_Y)
CheckFrameIndex(rins, rareg, rindex, (size - 1) * rstride + 1, BC_REG_ADDR);
if (wam == ASMIM_INDIRECT_Y)
CheckFrameIndex(wins, wareg, windex, (size - 1) * wstride + 1, BC_REG_ACCU);
}
switch (oins->mOperator)
{
case IA_ADD:
mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
break;
case IA_SUB:
mIns.Push(NativeCodeInstruction(oins, ASMIT_SEC));
break;
}
for (int i = 0; i < size; i++)
{
if (reverse)
{
if (am == ASMIM_IMPLIED)
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMPLIED));
else if (am == ASMIM_IMMEDIATE)
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i));
if (ram == ASMIM_INDIRECT_Y)
{
mIns.Push(NativeCodeInstruction(oins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride));
mIns.Push(NativeCodeInstruction(oins, at, ram, rareg));
}
else
mIns.Push(NativeCodeInstruction(oins, at, ram, rareg + i));
}
else
{
if (ram == ASMIM_INDIRECT_Y)
{
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride));
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ram, rareg));
}
else
mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ram, rareg + i));
if (am == ASMIM_IMPLIED)
mIns.Push(NativeCodeInstruction(oins, at, ASMIM_IMPLIED));
else if (am == ASMIM_IMMEDIATE)
mIns.Push(NativeCodeInstruction(oins, at, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(oins, at, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i));
}
if (!sfinal)
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
at = an;
if (wam == ASMIM_INDIRECT_Y)
{
if (ram != ASMIM_INDIRECT_Y || rindex != windex)
mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex + i * wstride));
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg));
}
else
mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg + i));
}
return true;
}
void NativeCodeBasicBlock::LoadValueToReg(InterCodeProcedure* proc, const InterInstruction * ins, int reg, const NativeCodeInstruction* ainsl, const NativeCodeInstruction* ainsh)
{
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mVolatile)
flags |= NCIF_VOLATILE;
if (ins->mDst.mType == IT_FLOAT)
{
int stride = ins->mSrc[0].mStride;
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
}
else
{
if (ins->mSrc[0].mMemory == IM_INDIRECT)
{
int areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
int index = int(ins->mSrc[0].mIntConst);
int stride = ins->mSrc[0].mStride;
if (stride * 4 <= 256)
{
CheckFrameIndex(ins, areg, index, stride * 4);
for (int i = 0; i < 4; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
}
}
else
{
for (int i = 0; i < 4; i++)
{
CheckFrameIndex(ins, areg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
index += stride;
}
}
}
}
}
else if (ins->mDst.mType == IT_POINTER)
{
int stride = ins->mSrc[0].mStride;
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, ins->mSrc[0].mLinkerObject, flags));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, nullptr, flags));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + stride));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
else
{
if (ins->mSrc[0].mMemory == IM_INDIRECT)
{
int areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
int index = int(ins->mSrc[0].mIntConst);
CheckFrameIndex(ins, areg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
if (reg == areg)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
if (reg == areg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
}
}
}
else
{
if (ins->mSrc[0].mTemp < 0)
{
if (InterTypeSize[ins->mDst.mType] == 1)
{
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 1);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
}
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
else if (InterTypeSize[ins->mDst.mType] == 2)
{
int stride = ins->mSrc[0].mStride;
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 2);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
if (ainsh) mIns.Push(*ainsh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
else if (InterTypeSize[ins->mDst.mType] == 4)
{
int stride = ins->mSrc[0].mStride;
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, areg, index, 4);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
}
}
}
else
{
if (ins->mSrc[0].mMemory == IM_INDIRECT)
{
int areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
int index = int(ins->mSrc[0].mIntConst);
int stride = ins->mSrc[0].mStride;
int size = InterTypeSize[ins->mDst.mType];
bool accu = false;
if (size * stride <= 256)
{
CheckFrameIndex(ins, areg, index, size * stride);
accu = reg == areg;
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
if (i == 0)
{
if (ainsl)
{
if (ainsl->mType == ASMIT_ADC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
else if (ainsl->mType == ASMIT_SBC)
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(*ainsl);
}
}
else if (ainsh)
mIns.Push(*ainsh);
if (accu)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
}
}
else
{
assert(ainsl == nullptr && ainsh == nullptr);
for (int i = 0; i < size; i++)
{
CheckFrameIndex(ins, areg, index, 1);
if (reg == areg)
accu = true;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
if (accu)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
index += stride;
}
}
if (accu)
{
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
}
}
}
}
}
}
void NativeCodeBasicBlock::LoadValue(InterCodeProcedure* proc, const InterInstruction * ins)
{
LoadValueToReg(proc, ins, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], nullptr, nullptr);
}
NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc)
{
int size = ins->mConst.mOperandSize;
int msize = 4, dstride = ins->mSrc[1].mStride, sstride = ins->mSrc[0].mStride;
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mVolatile)
flags |= NCIF_VOLATILE;
if (sstride > 1 || dstride > 1)
msize = 32;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
msize = 8;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
msize = 2;
#if 1
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[0].mMemory == IM_GLOBAL && (ins->mSrc[1].mMemory == IM_FRAME || ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM) && size < 256 && dstride == 1 && sstride == 1)
{
int areg = BC_REG_STACK;
int index = int(ins->mSrc[1].mIntConst);
if (ins->mSrc[1].mMemory == IM_FRAME)
index += ins->mSrc[1].mVarIndex + 2;
else
{
if (!mNoFrame)
areg = BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
}
CheckFrameIndex(ins, areg, index, size, BC_REG_ADDR);
if (size <= msize)
{
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
}
return this;
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - index, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CPY, ASMIM_IMMEDIATE, (index + size) & 255));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
return eblock;
}
}
else if ((ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) && (ins->mSrc[1].mMemory == IM_GLOBAL || ins->mSrc[1].mMemory == IM_ABSOLUTE))
{
NativeCodeBasicBlock* block = this;
int offset = 0;
if (size >= 256)
{
block = nproc->AllocateBlock();
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
if (size > 256)
{
if (size < 512 && !(size & 1))
{
int step = size >> 1;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, block, ASMIT_BNE);
return block;
}
else if (size < 1024 && !(size & 3))
{
int step = size >> 2;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 2 * step - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 2 * step - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 3 * step - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 3 * step - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, block, ASMIT_BNE);
return block;
}
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
while (offset + 255 < size)
{
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
offset += 256;
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, block, ASMIT_BNE);
size &= 255;
}
if (size <= msize)
{
LinkerObject* slo = ins->mSrc[0].mLinkerObject;
if (slo && (slo->mFlags & LOBJF_CONST))
{
for (int i = 0; i < size; i++)
{
int64 si = ins->mSrc[0].mIntConst + offset + i * sstride;
LinkerReference* lr = slo->FindReference(si);
if (lr)
{
if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si)
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER));
else
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER));
}
else
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si]));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
}
}
else
{
for (int i = 0; i < size; i++)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
}
}
}
else if (size <= 128)
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BPL);
block = eblock;
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset - 1, ins->mSrc[0].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset - 1, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
block = eblock;
}
return block;
}
else if ((ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) && (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME))
{
LinkerObject* slo = ins->mSrc[0].mLinkerObject;
if (slo && (slo->mFlags & LOBJF_CONST))
{
for (int i = 0; i < size; i++)
{
int64 si = ins->mSrc[0].mIntConst + i * sstride;
LinkerReference* lr = slo->FindReference(si);
if (lr)
{
if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));
}
}
else
{
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));
}
}
return this;
}
}
#endif
int sreg, dreg;
int si = 0, di = 0;
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
else if (ins->mSrc[0].mMemory == IM_FPARAM)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[0].mIntConst);
sreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[0].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
else
index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, sreg, index, 256, BC_REG_ACCU);
}
}
else if (ins->mSrc[0].mIntConst != 0)
{
int index = int(ins->mSrc[0].mIntConst);
if (size <= msize && (size - 1) * sstride + 1 + index <= 256)
{
si = index;
sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
}
else if (size * sstride > 256 && !ins->mSrc[0].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
else
{
sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
}
if (ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
dreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, dreg, index, 256, BC_REG_ADDR);
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = ins->mSrc[1].mVarIndex + int(ins->mSrc[1].mIntConst) + 2;
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
}
else if (ins->mSrc[1].mIntConst != 0)
{
int index = int(ins->mSrc[1].mIntConst);
if (size <= msize && (size - 1) * dstride + 1 + index <= 256)
{
di = index;
dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
}
else if (size * dstride > 256 && !ins->mSrc[1].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else
{
dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
}
if (size <= msize)
{
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, si));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, di));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
si += sstride;
di += dstride;
if (si >= 256)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, sreg + 1));
si &= 0xff;
}
if (di >= 256)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
di &= 0xff;
}
}
return this;
}
else
{
NativeCodeBasicBlock* block = this;
if (size >= 256)
{
block = nproc->AllocateBlock();
if (sreg != BC_REG_ACCU && !ins->mSrc[0].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
sreg = BC_REG_ACCU;
}
if (dreg != BC_REG_ADDR && !ins->mSrc[1].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* lblock2 = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
if (size >= 512)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, size >> 8));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, lblock2, ASMIT_BNE);
lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, sreg + 1));
lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
if (size >= 512)
{
lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock2->Close(ins, lblock, block, ASMIT_BNE);
}
else
lblock2->Close(ins, block, nullptr, ASMIT_JMP);
size &= 0xff;
}
if (size > 0)
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (size < 128)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BPL);
}
else if (size <= 256)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
}
block = eblock;
}
return block;
}
}
NativeCodeBasicBlock* NativeCodeBasicBlock::FillValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
int size = ins->mConst.mOperandSize;
int msize = 4, dstride = ins->mSrc[1].mStride;
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mVolatile)
flags |= NCIF_VOLATILE;
if (dstride > 1)
msize = 32;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
msize = 8;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
msize = 2;
#if 1
if (ins->mSrc[1].mTemp < 0)
{
if ((ins->mSrc[1].mMemory == IM_FRAME || ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM) && size < 256 && dstride == 1)
{
int areg = BC_REG_STACK;
int index = int(ins->mSrc[1].mIntConst);
if (ins->mSrc[1].mMemory == IM_FRAME)
index += ins->mSrc[1].mVarIndex + 2;
else
{
if (!mNoFrame)
areg = BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
}
CheckFrameIndex(ins, areg, index, size, BC_REG_ADDR);
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (size <= msize)
{
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
}
return this;
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CPY, ASMIM_IMMEDIATE, (index + size) & 255));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
return eblock;
}
}
else if (ins->mSrc[1].mMemory == IM_GLOBAL || ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
NativeCodeBasicBlock* block = this;
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
int offset = 0;
if (size >= 256)
{
block = nproc->AllocateBlock();
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
if (size > 256)
{
if (size < 512 && !(size & 1))
{
int step = size >> 1;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step, ins->mSrc[1].mLinkerObject, flags));
lblock->Close(ins, lblock, block, ASMIT_BNE);
return block;
}
else if (size < 1024 && !(size & 3))
{
int step = size >> 2;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 2 * step, ins->mSrc[1].mLinkerObject, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 3 * step, ins->mSrc[1].mLinkerObject, flags));
lblock->Close(ins, lblock, block, ASMIT_BNE);
return block;
}
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
while (offset + 255 < size)
{
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
offset += 256;
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, block, ASMIT_BNE);
size &= 255;
}
if (size <= msize)
{
for (int i = 0; i < size; i++)
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
block = eblock;
}
return block;
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
for (int i = 0; i < size; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));
return this;
}
}
#endif
int dreg;
int di = 0;
if (ins->mSrc[1].mTemp < 0)
{
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int index = int(ins->mSrc[1].mIntConst);
dreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
CheckFrameIndex(ins, dreg, index, 256, BC_REG_ADDR);
}
else if (ins->mSrc[1].mMemory == IM_FRAME)
{
int index = ins->mSrc[1].mVarIndex + int(ins->mSrc[1].mIntConst) + 2;
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
}
else if (ins->mSrc[1].mIntConst != 0)
{
int index = int(ins->mSrc[1].mIntConst);
if (size <= msize && (size - 1) * dstride + 1 + index <= 256)
{
di = index;
dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
}
else if (size * dstride > 256 && !ins->mSrc[1].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
else
{
dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
}
if (size <= msize)
{
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
for (int i = 0; i < size; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, di));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
di += dstride;
if (di >= 256)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
di &= 0xff;
}
}
return this;
}
else
{
NativeCodeBasicBlock* block = this;
if (size >= 256)
{
block = nproc->AllocateBlock();
if (dreg != BC_REG_ADDR && !ins->mSrc[1].mFinal)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR;
}
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* lblock2 = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
if (size >= 512)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, size >> 8));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->Close(ins, lblock, lblock2, ASMIT_BNE);
lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
if (size >= 512)
{
lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock2->Close(ins, lblock, block, ASMIT_BNE);
}
else
lblock2->Close(ins, block, nullptr, ASMIT_JMP);
size &= 0xff;
}
else
{
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
}
if (size > 0)
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
block->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
block = eblock;
}
return block;
}
}
void NativeCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("malloc")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
if (ins->mDst.mTemp >= 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
}
void NativeCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("free")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0xff));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
return eblock;
}
bool NativeCodeBasicBlock::CheckPredAccuStore(int reg)
{
if (mIns.Size() < 8)
return false;
int p = mIns.Size() - 8;
for (int i = 0; i < 4; i++)
{
if (mIns[p + 0].mType != ASMIT_LDA || mIns[p + 0].mMode != ASMIM_ZERO_PAGE || mIns[p + 0].mAddress != BC_REG_ACCU + i)
return false;
if (mIns[p + 1].mType != ASMIT_STA || mIns[p + 1].mMode != ASMIM_ZERO_PAGE || mIns[p + 1].mAddress != reg + i)
return false;
p += 2;
}
return true;
}
void NativeCodeBasicBlock::ShiftRegisterRight(const InterInstruction* ins, int reg, int shift)
{
if (shift == 0)
{
}
else if (shift == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, reg));
}
else if (shift == 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0));
}
else if (shift == 14)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (shift >= 5)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
for (int i = shift; i < 8; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
for (int i = 1; i < shift; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
}
void NativeCodeBasicBlock::ShiftRegisterLeft(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift)
{
if (shift == 0)
{
}
else if (shift == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, reg + 1));
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else if (shift >= 5)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
for (int i = shift; i < 8; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
for (int i = 0; i < shift; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
void NativeCodeBasicBlock::ShiftRegisterLeftFromByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift, int max)
{
if (shift == 0)
{
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else if (shift == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
if (max >= 128)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (shift >= 5 && shift < 8 && (max << shift) >= 512)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
for (int i = shift; i < 7; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff >> (8 - shift)) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
else if (shift == 4 && max >= 128)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xf0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
while (shift > 0 && max < 256)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
shift--;
max *= 2;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
if (max > 255)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
while (shift > 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
shift--;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
}
}
void NativeCodeBasicBlock::ShiftRegisterLeftByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift)
{
if (shift == 0)
{
}
else if (shift == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
}
else if (shift >= 6)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
for (int i = shift; i < 8; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
for (int i = 0; i < shift; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
}
int NativeCodeBasicBlock::ShortSignedDivide(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction* ins, const InterInstruction* sins, int mul)
{
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
if (sins)
{
LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
sreg = dreg;
}
if (mul == 2)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else if (mul == 4)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x03));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
// Two signed shifts
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else if (mul == 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x07));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
// Three signed shifts
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x10));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x10));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
return dreg;
}
int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins, const InterInstruction* sins, int index, int mul)
{
mul &= 0xffff;
if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue == 1 && mul > 4 && mul < 256)
{
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];
if (sins)
{
LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
sreg = dreg;
}
if (mul == 128)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, mul));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
}
return dreg;
}
#if 1
if (mul >= 0xfffc)
{
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];
if (sins)
{
LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
sreg = dreg;
}
int wreg = BC_REG_ACCU;
if (sreg != dreg)
wreg = dreg;
switch (mul)
{
case 0xffff: // -1
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
break;
case 0xfffe: // -2
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
break;
case 0xfffd: // -3
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
break;
case 0xfffc: // -4
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
break;
}
return dreg;
}
#endif
int lshift = 0, lmul = mul;
while (!(lmul & 1))
{
lmul >>= 1;
lshift++;
}
if (mul > 1 && ((lshift & 7) > 3 || lmul != 1) && ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 16)
{
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
if (sins)
{
LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, dreg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp]));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, int(ins->mSrc[index].mRange.mMaxValue) + 1, false)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, int(ins->mSrc[index].mRange.mMaxValue) + 1, true)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
return dreg;
}
if (lmul == 1 && !sins && ins->mSrc[index].mTemp == ins->mDst.mTemp)
{
// shift in place
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else if (ins->mDst.IsSByte())
{
// Upper byte will retain sign
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
}
else if (ins->mSrc[index].IsUByte())
ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue));
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
}
int dreg = BC_REG_ACCU;
if (sins)
LoadValueToReg(proc, sins, BC_REG_ACCU, nullptr, nullptr);
else if (ins->mSrc[index].mTemp == ins->mDst.mTemp)
dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
else
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];
dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
int wreg = BC_REG_ACCU;
if (dreg == BC_REG_ACCU)
wreg = BC_REG_WORK + 4;
switch (lmul)
{
#if 1
case 1:
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else if (ins->mDst.IsSByte())
{
// Upper byte will retain sign
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
}
else if (ins->mSrc[index].IsUByte())
ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue));
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
case 3:
if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 85)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
}
else if (ins->mSrc[index].IsSByte() && ins->mSrc[index].mRange.mMinValue >= -42 && ins->mSrc[index].mRange.mMaxValue <= 42)
{
// Will retain sign
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else if (ins->mDst.IsSByte())
{
// Upper byte will retain sign
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
}
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
case 5:
if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 51)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue) * 5);
}
else if (ins->mSrc[index].IsSByte() && ins->mSrc[index].mRange.mMinValue >= -25 && ins->mSrc[index].mRange.mMaxValue <= 25)
{
// Will retain sign
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
if (ins->mDst.IsSByte())
{
// Upper byte will retain sign
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
}
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
}
return dreg;
case 7:
if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 64)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
else if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 128)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
case 9:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
if (ins->mDst.IsUByte())
{
ShiftRegisterLeftByte(proc, ins, dreg, lshift);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
#if 1
case 25:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAY, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TYA, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
ShiftRegisterLeft(proc, ins, dreg, lshift);
return dreg;
#endif
#endif
default:
if (mul & 0xff00)
{
if (ins->mSrc[index].IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, mul & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, mul >> 8));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
}
else
{
if (dreg != BC_REG_ACCU)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul >> 8));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
}
else
{
if (dreg != BC_REG_ACCU)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul));
// mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
}
return BC_REG_WORK + 2;
}
}
static bool IsPowerOf2(unsigned n)
{
return (n & (n - 1)) == 0;
}
static int Binlog(unsigned n)
{
int k = -1;
while (n)
{
n >>= 1;
k++;
}
return k;
}
void NativeCodeBasicBlock::AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins)
{
mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mSrc[1].mTemp]));
for (int i = 0; i < sins->mSrc[0].mIntConst; i++)
{
mIns.Push(NativeCodeInstruction(sins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR));
}
mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(sins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(sins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(sins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mDst.mTemp] + 1));
}
void NativeCodeBasicBlock::BinaryDivModPair(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction* ins1, const InterInstruction* ins2)
{
if (ins1->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, ins1->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
if (ins1->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
}
else
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
if (ins1->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
}
if (ins1->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, ins1->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
if (ins1->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
}
else
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
if (ins1->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
}
if (ins1->mDst.mType == IT_INT32)
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu32")));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
else
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16")));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 1));
if (ins1->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 3));
}
if (ins2->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 4));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 5));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 6));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 7));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 1));
}
}
NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins, const InterInstruction * sins1, const InterInstruction * sins0)
{
int treg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
if (ins->mDst.mType == IT_FLOAT)
{
int sop0 = 0, sop1 = 1;
bool flipop = false;
bool changedSign = false;
if (ins->mOperator == IA_ADD || ins->mOperator == IA_MUL || ins->mOperator == IA_SUB)
{
if (!sins0 && ins->mSrc[sop0].mTemp >= 0 && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop0].mTemp]))
{
flipop = true;
sop0 = 1; sop1 = 0;
const InterInstruction* sins = sins0; sins0 = sins1; sins1 = sins;
}
else if (!sins1 && !sins0 && ins->mSrc[sop0].mTemp < 0 && ins->mSrc[sop1].mTemp >= 0 && !CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]))
{
flipop = true;
sop0 = 1; sop1 = 0;
const InterInstruction* sins = sins0; sins0 = sins1; sins1 = sins;
}
else if (!sins1 && !sins0 && ins->mSrc[sop1].mTemp >= 0 && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]) && ins->mSrc[sop1].mFinal)
{
// no flip in this case
}
else if (!sins0 && !sins1 && ins->mSrc[sop0].mTemp >= 0 && ins->mSrc[sop1].mTemp >= 0 && ins->mDst.mTemp == ins->mSrc[sop0].mTemp)
{
flipop = true;
sop0 = 1; sop1 = 0;
}
}
int sreg0 = ins->mSrc[sop0].mTemp < 0 ? -1 : BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop0].mTemp];
if (ins->mSrc[sop1].mTemp >= 0 && ins->mSrc[sop0].mTemp >= 0 && sins1 && sins1 == sins0)
{
LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitx")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, BC_REG_ACCU));
}
else
{
if (ins->mSrc[sop1].mTemp < 0)
{
union { float f; unsigned int v; } cc;
if (ins->mOperator == IA_SUB && flipop)
{
changedSign = true;
cc.f = float(-ins->mSrc[sop1].mFloatConst);
}
else
cc.f = float(ins->mSrc[sop1].mFloatConst);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
else if (sins1)
{
LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
}
else if (CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]))
{
if (ins->mSrc[sop1].mFinal)
{
// cull previous store from accu to temp using direcrt forwarding
mIns.SetSize(mIns.Size() - 8);
}
if (sreg0 == BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp])
sreg0 = BC_REG_ACCU;
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
if (ins->mSrc[sop0].mTemp < 0)
{
union { float f; unsigned int v; } cc;
if (ins->mOperator == IA_SUB && !flipop)
{
changedSign = true;
cc.f = float(-ins->mSrc[sop0].mFloatConst);
}
else
cc.f = float(ins->mSrc[sop0].mFloatConst);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitt")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
else if (sins0)
{
LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitt")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
else
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitx")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, sreg0));
}
}
switch (ins->mOperator)
{
case IA_ADD:
{
NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_SUB:
{
if (!changedSign)
{
if (flipop)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
}
NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_MUL:
{
NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("fmul")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_DIVS:
case IA_DIVU:
{
NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("fdiv")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
}
else if (ins->mDst.mType == IT_INT32)
{
switch (ins->mOperator)
{
case IA_ADD:
case IA_SUB:
case IA_OR:
case IA_AND:
case IA_XOR:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
AsmInsType atype;
switch (ins->mOperator)
{
case IA_ADD:
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
atype = ASMIT_ADC;
break;
case IA_SUB:
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
atype = ASMIT_SBC;
break;
case IA_OR:
atype = ASMIT_ORA;
break;
case IA_AND:
atype = ASMIT_AND;
break;
case IA_XOR:
atype = ASMIT_EOR;
break;
}
for (int i = 0; i < 4; i++)
{
if (ins->mSrc[1].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + i));
if (ins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + i));
}
} break;
case IA_MUL:
case IA_DIVS:
case IA_MODS:
case IA_DIVU:
case IA_MODU:
{
if (sins1)
LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
else if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
if (sins0)
LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
else if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
int reg = BC_REG_ACCU;
switch (ins->mOperator)
{
case IA_MUL:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul32")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 4;
} break;
case IA_DIVS:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divs32")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_MODS:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mods32")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 4;
} break;
case IA_DIVU:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu32")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_MODU:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("modu32")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 4;
} break;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
} break;
case IA_SHL:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int shift = ins->mSrc[0].mIntConst & 31;
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
if (shift >= 24)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
sreg = treg;
shift -= 24;
}
else if (shift >= 16)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
sreg = treg;
shift -= 16;
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
sreg = treg;
shift -= 8;
}
if (shift == 0)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
}
else if (shift == 1)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
}
}
else if (shift == 2)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
return eblock;
}
}
else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 1)
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* hblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x10));
this->Close(ins, lblock, hblock, ASMIT_BEQ);
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 8, frt.mLinkerObject));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset, frt.mLinkerObject));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
lblock->Close(ins, eblock, nullptr, ASMIT_JMP);
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset - 8, frt.mLinkerObject));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset - 16, frt.mLinkerObject));
hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
hblock->Close(ins, eblock, nullptr, ASMIT_JMP);
return eblock;
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
return eblock;
}
} break;
case IA_SHR:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int shift = ins->mSrc[0].mIntConst & 31;
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int nvbits = 32;
if (ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND)
{
int64 mv = ins->mSrc[1].mRange.mMaxValue;
while (nvbits > 0 && mv < (1LL << (nvbits - 1)))
nvbits--;
}
if (shift >= nvbits)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
return this;
}
if (shift >= 24)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 24;
nvbits -= 24;
}
else if (shift >= 16)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 16;
nvbits -= 16;
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 8;
nvbits -= 8;
}
if (shift == 0)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
}
else if (shift == 1)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
}
}
else if (shift == 2)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
}
else
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
int nregs = (nvbits + 7) >> 3;
if ((nvbits & 7) == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + nregs - 1));
for (int i = nregs - 1; i > 0; i--)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1));
nvbits--;
nregs--;
shift--;
}
if (nregs <= 2)
{
ShiftRegisterRight(ins, treg, shift);
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
for (int i = nregs - 1; i > 0; i--)
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1));
// lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
// lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1));
return eblock;
}
}
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
return eblock;
}
} break;
case IA_SAR:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int shift = ins->mSrc[0].mIntConst & 31;
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int nbytes = 4;
if (shift >= 24)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 24;
nbytes = 1;
}
else if (shift >= 16)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 16;
nbytes = 2;
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
sreg = treg;
shift -= 8;
nbytes = 3;
}
if (shift == 0)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
}
else if (shift == 1)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + nbytes - 1));
for(int i=nbytes - 2; i >=0; i--)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
}
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
int lcost = 8 + 2 * (nbytes - 1);
int ucost = shift * (1 + 2 * nbytes);
if ((nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost ||
!(nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
this->Close(ins, lblock, nullptr, ASMIT_JMP);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
for (int i = nbytes - 2; i >= 0; i--)
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
return eblock;
}
else
{
for (int si = 0; si < shift; si++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
for (int i = nbytes - 2; i >= 0; i--)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
}
}
}
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
return eblock;
}
} break;
}
}
else
{
switch (ins->mOperator)
{
case IA_ADD:
case IA_OR:
case IA_AND:
case IA_XOR:
{
if (ins->mOperator == IA_ADD && InterTypeSize[ins->mDst.mType] == 1 && (
ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp ||
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 1 && !sins0 && ins->mSrc[0].mTemp == ins->mDst.mTemp))
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
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(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
NativeCodeBasicBlock* iblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
this->Close(ins, eblock, iblock, ASMIT_BNE);
iblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, treg + 1));
iblock->Close(ins, eblock, nullptr, ASMIT_JMP);
return eblock;
}
}
}
else if (ins->mOperator == IA_ADD && InterTypeSize[ins->mDst.mType] == 1 && (
ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == -1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp ||
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == -1 && !sins0 && ins->mSrc[0].mTemp == ins->mDst.mTemp))
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_DEC, ASMIM_ZERO_PAGE, treg));
}
else
{
NativeCodeInstruction insl, insh;
AsmInsType atype;
switch (ins->mOperator)
{
case IA_ADD:
atype = ASMIT_ADC;
break;
case IA_OR:
atype = ASMIT_ORA;
break;
case IA_AND:
atype = ASMIT_AND;
break;
case IA_XOR:
atype = ASMIT_EOR;
break;
}
if (ins->mSrc[1].mTemp < 0)
{
insl = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff);
insh = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff);
if (sins0)
{
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);
LoadValueToReg(proc, sins0, treg, &insl, &insh);
}
else
{
if (ins->mOperator == IA_ADD)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(insl);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(insh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
}
else if (ins->mSrc[0].mTemp < 0)
{
insl = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
insh = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);
if (sins1)
{
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);
LoadValueToReg(proc, sins1, treg, &insl, &insh);
}
else
{
if (ins->mOperator == IA_ADD)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(insl);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(insh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
}
else
{
if (sins1 && sins0)
{
if (sins0->mSrc[0].mMemory == IM_INDIRECT && sins1->mSrc[0].mMemory == IM_INDIRECT &&
sins0->mSrc[0].mIntConst + (InterTypeSize[ins->mDst.mType] - 1) * sins0->mSrc[0].mStride < 255 &&
sins1->mSrc[0].mIntConst + (InterTypeSize[ins->mDst.mType] - 1) * sins1->mSrc[0].mStride < 255)
{
if (ins->mOperator == IA_ADD)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + 0));
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins1->mSrc[0].mTemp]));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.mTemp == sins0->mSrc[0].mTemp || ins->mDst.mTemp == sins1->mSrc[0].mTemp)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + sins0->mSrc[0].mStride));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + sins1->mSrc[0].mStride));
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins1->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
if (ins->mDst.mTemp == sins0->mSrc[0].mTemp || ins->mDst.mTemp == sins1->mSrc[0].mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
else
{
insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, treg);
insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, treg + 1);
if (sins1->mDst.mTemp == ins->mDst.mTemp)
{
LoadValueToReg(proc, sins1, treg, nullptr, nullptr);
LoadValueToReg(proc, sins0, treg, &insl, &insh);
}
else
{
LoadValueToReg(proc, sins0, treg, nullptr, nullptr);
LoadValueToReg(proc, sins1, treg, &insl, &insh);
}
}
}
else if (sins1)
{
insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]);
insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1);
LoadValueToReg(proc, sins1, treg, &insl, &insh);
}
else if (sins0)
{
insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]);
insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1);
LoadValueToReg(proc, sins0, treg, &insl, &insh);
}
else
{
if (ins->mOperator == IA_ADD)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
#if 1
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
#endif
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
}
}
} break;
case IA_SUB:
{
NativeCodeInstruction insl, insh;
if (InterTypeSize[ins->mDst.mType] == 1 &&
ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_DEC, ASMIM_ZERO_PAGE, treg));
}
else if (ins->mSrc[0].mTemp < 0)
{
insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
else
insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);
if (sins1)
LoadValueToReg(proc, sins1, treg, &insl, &insh);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(insl);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(insh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else if (ins->mSrc[1].mTemp < 0)
{
if ((ins->mSrc[1].mIntConst & (ins->mSrc[1].mIntConst + 1)) == 0 && ins->mSrc[0].IsUnsigned() && ins->mSrc[0].mRange.mMaxValue <= ins->mSrc[1].mIntConst)
{
NativeCodeInstruction insl = NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff);
NativeCodeInstruction insh = NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff);
if (sins0)
{
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);
LoadValueToReg(proc, sins0, treg, &insl, &insh);
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(insl);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(insh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
}
else if (sins0)
{
LoadValueToReg(proc, sins0, treg, nullptr, nullptr);
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else
{
if (sins0)
{
insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 0);
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
else
insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 1);
LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
}
else
{
insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]);
if (ins->mDst.IsUByte())
insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
else
insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1);
}
if (sins1)
{
LoadValueToReg(proc, sins1, treg, &insl, &insh);
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(insl);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(insh);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
}
} break;
case IA_MUL:
case IA_DIVS:
case IA_MODS:
case IA_DIVU:
case IA_MODU:
{
int reg = BC_REG_ACCU;
if (ins->mOperator == IA_MUL && ins->mSrc[1].mTemp < 0)
{
reg = ShortMultiply(proc, nproc, ins, sins0, 0, int(ins->mSrc[1].mIntConst));
}
else if (ins->mOperator == IA_MUL && ins->mSrc[0].mTemp < 0)
{
reg = ShortMultiply(proc, nproc, ins, sins1, 1, int(ins->mSrc[0].mIntConst));
}
else if (ins->mOperator == IA_MUL && ins->mSrc[0].IsUByte())
{
if (sins1)
LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
if (sins0)
{
LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
reg = BC_REG_WORK + 2;
}
else if (ins->mOperator == IA_MUL && ins->mSrc[1].IsUByte())
{
if (sins0)
LoadValueToReg(proc, sins0, BC_REG_ACCU, nullptr, nullptr);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
if (sins1)
{
LoadValueToReg(proc, sins1, BC_REG_WORK, nullptr, nullptr);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
reg = BC_REG_WORK + 2;
}
#if 1
else if (ins->mOperator == IA_DIVS && ins->mSrc[0].mTemp < 0 && (ins->mSrc[0].mIntConst == 2 || ins->mSrc[0].mIntConst == 4 || ins->mSrc[0].mIntConst == 8))
{
reg = ShortSignedDivide(proc, nproc, ins, sins1, int(ins->mSrc[0].mIntConst));
}
#endif
else
{
if (sins1)
LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
else if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
if (sins0)
LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
else if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
}
switch (ins->mOperator)
{
case IA_MUL:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 2;
} break;
case IA_DIVS:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divs16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_MODS:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mods16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 2;
} break;
case IA_DIVU:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
} break;
case IA_MODU:
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("modu16")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
reg = BC_REG_WORK + 2;
} break;
}
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
} break;
case IA_SHL:
{
if (ins->mSrc[0].mTemp < 0 && (ins->mSrc[0].mIntConst & 15) == 1 && sins1)
{
NativeCodeInstruction insl(ins, ASMIT_ASL, ASMIM_IMPLIED);
NativeCodeInstruction insh(ins, ASMIT_ROL, ASMIM_IMPLIED);
LoadValueToReg(proc, sins1, treg, &insl, &insh);
return this;
}
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
int shift = ins->mSrc[0].mIntConst & 15;
if (ins->mDst.IsUByte() || InterTypeSize[ins->mDst.mType] == 1)
{
if (shift == 0)
{
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
}
else if (shift == 1)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
}
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (shift > 5)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
for(int i=shift; i<8; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg ));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
for (int i = 0; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
if (shift == 0)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift == 1)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mSrc[1].IsUByte())
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
}
}
#if 1
else if (shift == 6)
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xc0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
#endif
else if (shift == 7)
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (shift == 4 && ins->mSrc[1].IsUByte() && ins->mSrc[1].mRange.mMaxValue >= 128)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xf0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mSrc[1].IsUByte())
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
}
else
{
if (ins->mSrc[1].IsUByte())
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
}
int check = 0xffff;
if (ins->mSrc[1].IsUByte())
check = int(ins->mSrc[1].mRange.mMaxValue);
check <<= 1;
if (check >= 0x100)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
for (int i = 1; i < shift; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
check <<= 1;
if (check >= 0x100)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
{
int l = Binlog(ins->mSrc[1].mIntConst & 0xffff);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));
if (l < 8)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 8 + l, frt.mLinkerObject));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (ins->mSrc[1].mTemp < 0)
{
int size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
size = 16;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, int(ins->mSrc[1].mIntConst), size, false)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, int(ins->mSrc[1].mIntConst), size, true)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
return eblock;
}
} break;
case IA_SHR:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int shift = ins->mSrc[0].mIntConst & 15;
#if 1
if (ins->mSrc[1].IsUByte() || InterTypeSize[ins->mSrc[1].mType] == 1)
{
if (shift == 0)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else if (shift == 7)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
if (InterTypeSize[ins->mDst.mType] > 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (shift == 6)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
if (InterTypeSize[ins->mDst.mType] > 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
for (int i = 0; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else
#endif
{
if (shift == 0)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift == 1)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg));
}
}
else if (shift == 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (shift == 14)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (shift >= 5)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
for (int i = shift; i < 8; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
uint32 mask = 0xffff;
if (ins->mSrc[1].IsPositive() && ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND)
mask = uint32(ins->mSrc[1].mRange.mMaxValue);
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
for (int i = 1; i < shift; i++)
{
mask >>= 1;
if (mask > 0xff)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
}
}
else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
{
int l = Binlog(ins->mSrc[1].mIntConst & 0xffff);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (ins->mSrc[1].mTemp < 0)
{
int size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
size = 16;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, int(ins->mSrc[1].mIntConst), size, false)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, int(ins->mSrc[1].mIntConst), size, true)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (ins->mSrc[1].IsUByte())
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
if (ins->mSrc[0].IsInRange(1, 15))
this->Close(ins, lblock, nullptr, ASMIT_JMP);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
return eblock;
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
}
if (ins->mSrc[0].IsInRange(1, 15))
this->Close(ins, lblock, nullptr, ASMIT_JMP);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
return eblock;
}
} break;
case IA_SAR:
{
if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
if (ins->mSrc[0].mTemp < 0)
{
int shift = ins->mSrc[0].mIntConst & 15;
if (ins->mSrc[1].IsUByte())
{
if (shift == 0)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift == 7)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (shift == 6)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
for (int i = 0; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (InterTypeSize[ins->mDst.mType] == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
if (shift > 5)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
for (int i = shift; i < 8; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
}
else if (shift > 0)
{
for (int i = 0; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
}
else if (ins->mSrc[1].IsSByte() && shift != 0 && shift < 5)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
for (int i = 0; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
if (shift == 0)
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift == 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
}
else if (shift == 7)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (shift == 6)
{
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
if (sreg != treg)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (shift >= 8)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
for (int i = 8; i < shift; i++)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> (shift - 8)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> (shift - 8)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
}
for (int i = 0; i < shift; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
}
else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
{
int l = Binlog(ins->mSrc[1].mIntConst & 0xffff);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));
if (l == 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else if (ins->mSrc[1].mTemp < 0)
{
int size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
size = 16;
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, int(ins->mSrc[1].mIntConst), size, false)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mDst.IsUByte())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, int(ins->mSrc[1].mIntConst), size, true)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
if (ins->mSrc[1].IsUByte())
{
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
}
if (ins->mSrc[0].IsInRange(1, 15))
this->Close(ins, lblock, nullptr, ASMIT_JMP);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (ins->mSrc[1].IsSByte())
{
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
}
if (ins->mSrc[0].IsInRange(1, 15))
this->Close(ins, lblock, nullptr, ASMIT_JMP);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
if (ins->mSrc[1].mTemp < 0)
{
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
}
else
{
if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
}
else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
}
if (ins->mSrc[0].IsInRange(1, 15))
this->Close(ins, lblock, nullptr, ASMIT_JMP);
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
this->Close(ins, lblock, eblock, ASMIT_BNE);
}
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
lblock->Close(ins, lblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
}
return eblock;
}
} break;
}
}
return this;
}
void NativeCodeBasicBlock::SignExtendAddImmediate(InterCodeProcedure* proc, const InterInstruction* xins, const InterInstruction* ains)
{
int val = ains->mSrc[0].mTemp == xins->mDst.mTemp ? int(ains->mSrc[1].mIntConst) : int(ains->mSrc[0].mIntConst);
val -= 128;
mIns.Push(NativeCodeInstruction(xins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[xins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(xins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ains, ASMIT_CLC));
mIns.Push(NativeCodeInstruction(ains, ASMIT_ADC, ASMIM_IMMEDIATE, val & 0xff));
mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ains, ASMIT_ADC, ASMIM_IMMEDIATE, (val >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 1));
}
void NativeCodeBasicBlock::BinaryFloatOperatorLookup(InterCodeProcedure* proc, const InterInstruction* cins, const InterInstruction* ins)
{
mIns.Push(NativeCodeInstruction(cins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(cins, ASMIT_SEC));
mIns.Push(NativeCodeInstruction(cins, ASMIT_SBC, ASMIM_IMMEDIATE, cins->mSrc[0].mRange.mMinValue));
mIns.Push(NativeCodeInstruction(cins, ASMIT_TAX));
bool reverse = false;
double fconst;
if (ins->mSrc[0].mTemp < 0)
{
fconst = ins->mSrc[0].mFloatConst;
}
else
{
fconst = ins->mSrc[1].mFloatConst;
if (ins->mOperator == IA_SUB || ins->mOperator == IA_DIVS)
reverse = true;
}
for (int i = 0; i < 4; i++)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, mProc->mGenerator->AllocateFloatTable(ins->mOperator, reverse,
int(cins->mSrc[0].mRange.mMinValue), int(cins->mSrc[0].mRange.mMaxValue), float(fconst), i)));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + i));
}
}
void NativeCodeBasicBlock::UnaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins)
{
int treg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
if (ins->mDst.mType == IT_FLOAT)
{
switch (ins->mOperator)
{
case IA_NEG:
case IA_ABS:
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
if (ins->mOperator == IA_NEG)
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x7f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
case IA_FLOOR:
case IA_CEIL:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
NativeCodeGenerator::Runtime& frx(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplita")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frx.mOffset, frx.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
if (ins->mOperator == IA_FLOOR)
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffloor")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
else
{
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fceil")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
}
}
else
{
switch (ins->mOperator)
{
case IA_NEG:
mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
if (ins->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
break;
case IA_NOT:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
if (ins->mDst.mType == IT_INT32)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
}
break;
}
}
}
void NativeCodeBasicBlock::NumericConversion(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins)
{
switch (ins->mOperator)
{
case IA_FLOAT2INT:
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftoi")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
} break;
case IA_INT2FLOAT:
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromi")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
} break;
case IA_FLOAT2UINT:
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftou")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
} break;
case IA_UINT2FLOAT:
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromu")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
} break;
case IA_EXT8TO16S:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
break;
case IA_EXT8TO16U:
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
break;
case IA_EXT16TO32S:
if (ins->mSrc[0].IsUnsigned())
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
}
else
{
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
case IA_EXT16TO32U:
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
case IA_EXT8TO32S:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
case IA_EXT8TO32U:
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
}
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
break;
}
}
void NativeCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump)
{
InterOperator op = ins->mOperator;
bool scmp = (op == IA_CMPGES) || (op == IA_CMPLES) || (op == IA_CMPGS) || (op == IA_CMPLS) || (op == IA_CMPEQ) || (op == IA_CMPNE);
bool ucmp = (op == IA_CMPGEU) || (op == IA_CMPLEU) || (op == IA_CMPGU) || (op == IA_CMPLU) || (op == IA_CMPEQ) || (op == IA_CMPNE);
if (ins->mSrc[0].mType == IT_FLOAT)
{
if (ins->mSrc[0].mTemp < 0 || ins->mSrc[1].mTemp < 0)
{
InterOperator op = ins->mOperator;
int ci = 0, vi = 1;
if (ins->mSrc[1].mTemp < 0)
{
ci = 1;
vi = 0;
op = MirrorRelational(op);
}
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[ci].mFloatConst);
int ti = BC_REG_TMP + proc->mTempOffset[ins->mSrc[vi].mTemp];
if (cc.f == 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x7f));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 0));
if (op == IA_CMPEQ)
{
Close(ins, trueJump, falseJump, ASMIT_BEQ);
}
else if (op == IA_CMPNE)
{
Close(ins, trueJump, falseJump, ASMIT_BNE);
}
else
{
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPLES || op == IA_CMPLEU)
Close(ins, trueJump, nblock, ASMIT_BEQ);
else
Close(ins, falseJump, nblock, ASMIT_BEQ);
nblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPGS || op == IA_CMPGU)
nblock->Close(ins, trueJump, falseJump, ASMIT_BPL);
else
nblock->Close(ins, trueJump, falseJump, ASMIT_BMI);
}
return;
}
else
{
NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
if (op == IA_CMPEQ)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
Close(ins, eblock1, falseJump, ASMIT_BEQ);
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
eblock1->Close(ins, eblock2, falseJump, ASMIT_BEQ);
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
eblock2->Close(ins, eblock3, falseJump, ASMIT_BEQ);
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
eblock3->Close(ins, trueJump, falseJump, ASMIT_BEQ);
return;
}
else if (op == IA_CMPNE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
Close(ins, eblock1, trueJump, ASMIT_BEQ);
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
eblock1->Close(ins, eblock2, trueJump, ASMIT_BEQ);
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
eblock2->Close(ins, eblock3, trueJump, ASMIT_BEQ);
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
eblock3->Close(ins, falseJump, trueJump, ASMIT_BEQ);
return;
}
else if (op == IA_CMPGS || op == IA_CMPGES || op == IA_CMPGU || op == IA_CMPGEU)
{
NativeCodeBasicBlock* eblock0 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
if (cc.f < 0)
Close(ins, trueJump, eblock0, ASMIT_BPL);
else
Close(ins, falseJump, eblock0, ASMIT_BMI);
eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
eblock0->Close(ins, nblock, eblock1, ASMIT_BNE);
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
eblock1->Close(ins, nblock, eblock2, ASMIT_BNE);
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
eblock2->Close(ins, nblock, eblock3, ASMIT_BNE);
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU)
eblock3->Close(ins, nblock, trueJump, ASMIT_BNE);
else
eblock3->Close(ins, nblock, falseJump, ASMIT_BNE);
if (cc.f < 0)
nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
else
nblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
return;
}
else
{
NativeCodeBasicBlock* eblock0 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
if (cc.f < 0)
Close(ins, falseJump, eblock0, ASMIT_BPL);
else
Close(ins, trueJump, eblock0, ASMIT_BMI);
eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
eblock0->Close(ins, nblock, eblock1, ASMIT_BNE);
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
eblock1->Close(ins, nblock, eblock2, ASMIT_BNE);
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
eblock2->Close(ins, nblock, eblock3, ASMIT_BNE);
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU)
eblock3->Close(ins, nblock, trueJump, ASMIT_BNE);
else
eblock3->Close(ins, nblock, falseJump, ASMIT_BNE);
if (cc.f < 0)
nblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
else
nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
return;
}
}
}
int li = 0, ri = 1;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 1; ri = 0;
}
if (ins->mSrc[li].mTemp < 0)
{
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[li].mFloatConst);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
else if (ins->mSrc[li].mFinal && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]))
{
// cull previous store from accu to temp using direcrt forwarding
mIns.SetSize(mIns.Size() - 8);
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
}
if (ins->mSrc[ri].mTemp < 0)
{
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[ri].mFloatConst);
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fcmp")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_JSRFLAGS));
switch (op)
{
case IA_CMPEQ:
Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
Close(ins, trueJump, falseJump, ASMIT_BMI);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
Close(ins, falseJump, trueJump, ASMIT_BMI);
break;
}
}
else if (ins->mSrc[0].mType == IT_POINTER)
{
int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 0; ri = 1;
}
int lreg = ins->mSrc[li].mTemp, rreg = ins->mSrc[ri].mTemp;
if (lreg < 0)
{
lreg = BC_REG_ACCU;
LoadConstantToReg(proc, ins, ins->mSrc[li], IT_POINTER, lreg);
}
else
lreg = BC_REG_TMP + proc->mTempOffset[lreg];
if (rreg < 0)
{
rreg = BC_REG_ACCU;
LoadConstantToReg(proc, ins, ins->mSrc[ri], IT_POINTER, rreg);
}
else
rreg = BC_REG_TMP + proc->mTempOffset[rreg];
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
if (op == IA_CMPEQ || op == IA_CMPNE)
{
// Lower byte compare more likely to miss on not equal with first
// compare
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg));
Close(ins, nblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg + 1));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg + 1));
Close(ins, nblock, eblock, ASMIT_BNE);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg));
}
switch (op)
{
case IA_CMPEQ:
nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
}
else if (ins->mSrc[0].mType == IT_INT32)
{
int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 0; ri = 1;
}
if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS)
{
if (ins->mSrc[ri].mTemp >= 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 24) & 0xff) ^ 0x80));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
}
if (ins->mSrc[ri].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ((ins->mSrc[ri].mIntConst >> 24) & 0xff) ^ 0x80));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
else
{
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 24) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
if (ins->mSrc[ri].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 24) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
}
NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
this->Close(ins, nblock, eblock3, ASMIT_BNE);
if (ins->mSrc[li].mTemp < 0)
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 16) & 0xff));
else
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
if (ins->mSrc[ri].mTemp < 0)
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 16) & 0xff));
else
eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2));
eblock3->Close(ins, nblock, eblock2, ASMIT_BNE);
if (ins->mSrc[li].mTemp < 0)
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff));
else
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
if (ins->mSrc[ri].mTemp < 0)
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 8) & 0xff));
else
eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
eblock2->Close(ins, nblock, eblock1, ASMIT_BNE);
if (ins->mSrc[li].mTemp < 0)
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
else
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
if (ins->mSrc[ri].mTemp < 0)
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[ri].mIntConst & 0xff));
else
eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
switch (op)
{
case IA_CMPEQ:
nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
eblock1->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
eblock1->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
eblock1->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
eblock1->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
}
else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0)
{
int rt = ins->mSrc[1].mTemp;
if (rt < 0)
{
rt = ins->mSrc[0].mTemp;
switch (op)
{
case IA_CMPLEU:
op = IA_CMPGEU;
break;
case IA_CMPGEU:
op = IA_CMPLEU;
break;
case IA_CMPLU:
op = IA_CMPGU;
break;
case IA_CMPGU:
op = IA_CMPLU;
break;
case IA_CMPLES:
op = IA_CMPGES;
break;
case IA_CMPGES:
op = IA_CMPLES;
break;
case IA_CMPLS:
op = IA_CMPGS;
break;
case IA_CMPGS:
op = IA_CMPLS;
break;
}
}
switch (op)
{
case IA_CMPEQ:
case IA_CMPLEU:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
if (InterTypeSize[ins->mSrc[0].mType] > 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
case IA_CMPGU:
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
if (InterTypeSize[ins->mSrc[0].mType] > 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, trueJump, falseJump, ASMIT_BNE);
break;
case IA_CMPGEU:
this->Close(ins, trueJump, nullptr, ASMIT_JMP);
break;
case IA_CMPLU:
this->Close(ins, falseJump, nullptr, ASMIT_JMP);
break;
case IA_CMPGES:
if (InterTypeSize[ins->mSrc[0].mType] == 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, trueJump, falseJump, ASMIT_BPL);
break;
case IA_CMPLS:
if (InterTypeSize[ins->mSrc[0].mType] == 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, trueJump, falseJump, ASMIT_BMI);
break;
case IA_CMPGS:
{
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (InterTypeSize[ins->mSrc[0].mType] == 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, eblock, falseJump, ASMIT_BPL);
if (InterTypeSize[ins->mSrc[0].mType] != 1)
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, trueJump, falseJump, ASMIT_BNE);
break;
}
case IA_CMPLES:
{
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (InterTypeSize[ins->mSrc[0].mType] == 1)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
this->Close(ins, eblock, trueJump, ASMIT_BPL);
if (InterTypeSize[ins->mSrc[0].mType] != 1)
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
}
}
}
else if (InterTypeSize[ins->mSrc[0].mType] == 1 ||
scmp && ins->mSrc[0].IsSByte() && ins->mSrc[1].IsSByte() ||
ucmp && ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte())
{
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 0; ri = 1;
}
int iconst = 0;
bool rconst = false;
if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPGES || op == IA_CMPLS) && int16(ins->mSrc[li].mIntConst) > - 128)
{
iconst = int(ins->mSrc[li].mIntConst) - 1;
rconst = true;
li = ri; ri = 1 - li;
NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
}
else if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPLES || op == IA_CMPGS) && int16(ins->mSrc[li].mIntConst) < 127)
{
iconst = int(ins->mSrc[li].mIntConst) + 1;
rconst = true;
li = ri; ri = 1 - li;
NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
}
else if (ins->mSrc[ri].mTemp < 0)
{
iconst = int(ins->mSrc[ri].mIntConst);
rconst = true;
}
if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS)
{
if (!rconst)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst & 0xff) ^ 0x80));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
}
if (rconst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (iconst & 0xff) ^ 0x80));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
else
{
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
if (rconst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
}
switch (op)
{
case IA_CMPEQ:
this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
this->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
this->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
}
#if 1
else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst < 256 && ins->mSrc[1].mIntConst > 0 || ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst < 256 && ins->mSrc[0].mIntConst > 0)
{
int rt = ins->mSrc[1].mTemp;
int ival = int(ins->mSrc[0].mIntConst);
bool u8 = ins->mSrc[1].IsUByte();
if (rt < 0)
{
rt = ins->mSrc[0].mTemp;
u8 = ins->mSrc[0].IsUByte();;
ival = int(ins->mSrc[1].mIntConst);
switch (op)
{
case IA_CMPLEU:
op = IA_CMPGEU;
break;
case IA_CMPGEU:
op = IA_CMPLEU;
break;
case IA_CMPLU:
op = IA_CMPGU;
break;
case IA_CMPGU:
op = IA_CMPLU;
break;
case IA_CMPLES:
op = IA_CMPGES;
break;
case IA_CMPGES:
op = IA_CMPLES;
break;
case IA_CMPLS:
op = IA_CMPGS;
break;
case IA_CMPGS:
op = IA_CMPLS;
break;
}
}
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
if (u8)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
switch (op)
{
case IA_CMPEQ:
{
this->Close(ins, eblock, falseJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
}
case IA_CMPNE:
{
this->Close(ins, eblock, trueJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
}
case IA_CMPLEU:
{
this->Close(ins, eblock, falseJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
case IA_CMPGEU:
{
this->Close(ins, eblock, trueJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
case IA_CMPLU:
{
this->Close(ins, eblock, falseJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
}
case IA_CMPGU:
{
this->Close(ins, eblock, trueJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
}
case IA_CMPLES:
{
NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
this->Close(ins, sblock, trueJump, ASMIT_BPL);
sblock->Close(ins, eblock, falseJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
case IA_CMPGES:
{
NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
this->Close(ins, sblock, falseJump, ASMIT_BPL);
sblock->Close(ins, eblock, trueJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
case IA_CMPLS:
{
NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
this->Close(ins, sblock, trueJump, ASMIT_BPL);
sblock->Close(ins, eblock, falseJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
}
case IA_CMPGS:
{
NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
this->Close(ins, sblock, falseJump, ASMIT_BPL);
sblock->Close(ins, eblock, trueJump, ASMIT_BEQ);
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
}
}
}
#endif
#if 1
// Special case counting to 256
else if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 256 && op == IA_CMPLU &&
ins->mSrc[1].mRange.mMinState == IntegerValueRange::S_BOUND && ins->mSrc[1].mRange.mMinValue > 0 &&
ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND && ins->mSrc[1].mRange.mMaxValue == 256)
{
if (ins->mSrc[1].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
}
#endif
#if 1
// Special case >= or < with multiple of 256, no need to check low byte then
else if (ins->mSrc[0].mTemp < 0 && !(ins->mSrc[0].mIntConst & 255) && op == IA_CMPGEU)
{
if (ins->mSrc[1].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst >> 8));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst >> 8));
this->Close(ins, trueJump, falseJump, ASMIT_BCS);
}
#endif
else if (ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte())
{
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 0; ri = 1;
}
int iconst = 0;
bool rconst = false;
if (ins->mSrc[ri].mTemp < 0)
{
iconst = int(ins->mSrc[ri].mIntConst);
rconst = true;
}
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
if (rconst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
switch (op)
{
case IA_CMPEQ:
this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
this->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
this->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
}
else
{
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
NativeCodeBasicBlock* cblock = this;
if (op == IA_CMPLU && ins->mSrc[0].mTemp == -1 && ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxValue == ins->mSrc[0].mIntConst)
op = IA_CMPNE;
int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{
li = 0; ri = 1;
}
int iconst = 0;
bool rconst = false;
if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPGES || op == IA_CMPLS) && int16(ins->mSrc[li].mIntConst) > - 32768)
{
iconst = int(ins->mSrc[li].mIntConst) - 1;
rconst = true;
li = ri; ri = 1 - li;
NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
}
else if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPLES || op == IA_CMPGS) && int16(ins->mSrc[li].mIntConst) < 32767)
{
iconst = int(ins->mSrc[li].mIntConst) + 1;
rconst = true;
li = ri; ri = 1 - li;
NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
}
else if (ins->mSrc[ri].mTemp < 0)
{
iconst = int(ins->mSrc[ri].mIntConst);
rconst = true;
}
if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS)
{
if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[li].IsPositive() && (op == IA_CMPGS || op == IA_CMPLS))
{
cblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
this->Close(ins, falseJump, cblock, ASMIT_BMI);
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
}
else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES))
{
cblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
this->Close(ins, falseJump, cblock, ASMIT_BMI);
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
}
else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGS || op == IA_CMPLS))
{
cblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
this->Close(ins, trueJump, cblock, ASMIT_BMI);
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
}
else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[li].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES))
{
cblock = nproc->AllocateBlock();
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
this->Close(ins, trueJump, cblock, ASMIT_BMI);
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
}
else
{
if (!rconst)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 8) & 0xff) ^ 0x80));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
}
if (rconst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ((iconst >> 8) & 0xff) ^ 0x80));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK));
}
}
else
{
if (ins->mSrc[li].mTemp < 0)
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
if (rconst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (iconst >> 8) & 0xff));
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
}
cblock->Close(ins, nblock, eblock, ASMIT_BNE);
if (ins->mSrc[li].mTemp < 0)
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
else
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
if (rconst)
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
else
eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
switch (op)
{
case IA_CMPEQ:
nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
break;
case IA_CMPNE:
nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
break;
case IA_CMPLU:
case IA_CMPLS:
case IA_CMPGU:
case IA_CMPGS:
eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
break;
case IA_CMPLEU:
case IA_CMPLES:
case IA_CMPGEU:
case IA_CMPGES:
eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
nblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
break;
}
}
}
void NativeCodeBasicBlock::LoadStoreOpAbsolute2D(InterCodeProcedure* proc, const InterInstruction* lins1, const InterInstruction* lins2, const InterInstruction* mins)
{
mIns.Push(NativeCodeInstruction(lins1, ASMIT_CLC));
if (lins1->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(lins1, ASMIT_LDA, ASMIM_IMMEDIATE, lins1->mSrc[0].mIntConst));
else
mIns.Push(NativeCodeInstruction(lins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins1->mSrc[0].mTemp]));
if (lins2->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(lins2, ASMIT_ADC, ASMIM_IMMEDIATE, lins2->mSrc[0].mIntConst));
else
mIns.Push(NativeCodeInstruction(lins2, ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins2->mSrc[0].mTemp]));
mIns.Push(NativeCodeInstruction(mins, ASMIT_TAY));
if (mins->mCode == IC_STORE)
{
for (int i = 0; i < InterTypeSize[mins->mSrc[0].mType]; i++)
{
if (mins->mSrc[0].mTemp < 0)
mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_IMMEDIATE, (mins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
else
mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[mins->mSrc[0].mTemp] + i));
mIns.Push(NativeCodeInstruction(mins, ASMIT_STA, ASMIM_ABSOLUTE_Y, lins1->mSrc[1].mIntConst + mins->mSrc[1].mIntConst + i, lins1->mSrc[1].mLinkerObject));
}
}
else
{
for (int i = 0; i < InterTypeSize[mins->mDst.mType]; i++)
{
mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, lins1->mSrc[1].mIntConst + mins->mSrc[0].mIntConst + i, lins1->mSrc[1].mLinkerObject));
mIns.Push(NativeCodeInstruction(mins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[mins->mDst.mTemp] + i));
}
}
}
void NativeCodeBasicBlock::LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction * ins, const InterInstruction* sins1, const InterInstruction* sins0, bool addrvalid)
{
bool isub = false;
int ireg = ins->mSrc[0].mTemp;
AsmInsType iop = ASMIT_ADC;
if (sins0)
{
isub = true;
ireg = sins0->mSrc[0].mTemp;
iop = ASMIT_SBC;
}
if (sins1)
{
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0)
LoadValueToReg(proc, sins1, ins->mDst.mTemp, nullptr, nullptr);
else
{
if (ins->mSrc[0].mTemp < 0)
{
NativeCodeInstruction ainsl(ins, ASMIT_ADC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
NativeCodeInstruction ainsh(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);
LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
}
else
{
NativeCodeInstruction ainsl(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]);
if (ins->mSrc[0].IsUByte())
{
NativeCodeInstruction ainsh(ins, iop, ASMIM_IMMEDIATE, 0);
LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
}
else
{
NativeCodeInstruction ainsh(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1);
LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
}
}
}
}
else if (ins->mSrc[1].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, isub ? ASMIT_SEC : ASMIT_CLC, ASMIM_IMPLIED));
if (ins->mSrc[1].mMemory == IM_GLOBAL)
{
if (!ins->mSrc[0].IsUnsigned() && ins->mSrc[1].mIntConst != 0 && ins->mSrc[1].mLinkerObject->mSize < 256)
{
// Negative index, small global
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst & 0xffff, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
// if the global variable is smaller than 256 bytes, we can safely ignore the upper byte?
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst & 0xffff, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
#if 1
if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else if ((ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].IsUnsigned()) &&
(ins->mSrc[1].mLinkerObject->mSize - ins->mSrc[1].mIntConst < 256 || (addrvalid && ins->mSrc[1].mLinkerObject->mSize - ins->mSrc[1].mIntConst <= 256)))
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
#endif
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
}
else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
#if 1
if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
#endif
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
else if (ins->mSrc[1].mMemory == IM_PROCEDURE)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
#if 1
if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
#endif
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
{
int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
int index = int(ins->mSrc[1].mIntConst);
int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
if (ins->mSrc[1].mMemory == IM_LOCAL)
index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
else
index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
index += mFrameOffset;
if (ins->mSrc[0].IsUByte() && ins->mSrc[0].mRange.mMaxValue + index < 256 && !isub)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index));
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, areg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
if (index != 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
}
}
}
}
else
{
if (ins->mSrc[0].mTemp >= 0 || ins->mSrc[0].mIntConst != 0)
mIns.Push(NativeCodeInstruction(ins, isub ? ASMIT_SEC : ASMIT_CLC, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mIntConst)
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
}
else
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mIntConst)
mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
}
else if (ins->mSrc[0].IsUByte())
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
else
mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
}
void NativeCodeBasicBlock::CallFunction(InterCodeProcedure* proc, NativeCodeProcedure * nproc, const InterInstruction * ins)
{
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mLinkerObject)
{
NativeCodeInstruction lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER);
NativeCodeInstruction hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER);
mIns.Push(lins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(hins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
NativeCodeInstruction lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
NativeCodeInstruction hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);
mIns.Push(lins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(hins);
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_FEXEC));
if (ins->mDst.mTemp >= 0)
{
if (ins->mDst.mType == IT_FLOAT)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
if (InterTypeSize[ins->mDst.mType] > 1)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
if (InterTypeSize[ins->mDst.mType] > 2)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
}
}
}
}
NativeCodeInstruction NativeCodeBasicBlock::DecodeNative(const InterInstruction* ins, LinkerObject* lobj, int& offset) const
{
uint8 op = lobj->mData[offset++];
AsmInsData d = DecInsData[op];
int address = 0;
LinkerObject * linkerObject = nullptr;
uint32 flags = NCIF_LOWER | NCIF_UPPER;
LinkerReference * lref;
switch (d.mMode)
{
case ASMIM_ABSOLUTE:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
case ASMIM_INDIRECT:
lref = lobj->FindReference(offset);
address = lobj->mData[offset++];
address += lobj->mData[offset++] << 8;
if (lref)
{
linkerObject = lref->mRefObject;
address = lref->mRefOffset;
}
else if (d.mType != ASMIT_JSR)
flags |= NCIF_VOLATILE;
break;
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_ZERO_PAGE_Y:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
lref = lobj->FindReference(offset);
address = lobj->mData[offset++];
if (lref && (lref->mFlags & LREF_TEMPORARY))
address += lobj->mTemporaries[lref->mRefOffset];
else if (address >= BC_REG_TMP)
flags |= NCIF_VOLATILE;
break;
case ASMIM_RELATIVE:
address = lobj->mData[offset++];
address += offset;
break;
case ASMIM_IMMEDIATE:
lref = lobj->FindReference(offset);
address = lobj->mData[offset++];
if (lref)
{
if (lref->mFlags & LREF_TEMPORARY)
{
address = lobj->mTemporaries[lref->mRefOffset];
flags |= NICF_TMPREF | NCIF_LOWER;
if (lobj->mTempSizes[lref->mRefOffset] > 1)
flags |= NCIF_UPPER;
}
else
{
d.mMode = ASMIM_IMMEDIATE_ADDRESS;
linkerObject = lref->mRefObject;
address = lref->mRefOffset;
if (lref->mFlags & LREF_LOWBYTE)
flags = NCIF_LOWER;
else
flags = NCIF_UPPER;
}
}
break;
}
return NativeCodeInstruction(ins, d.mType, d.mMode, address, linkerObject, flags);
}
void NativeCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, NativeCodeProcedure * nproc, const InterInstruction* ins)
{
if (ins->mCode == IC_ASSEMBLER)
{
for (int i = 1; i < ins->mNumOperands; i++)
{
if (ins->mSrc[i].mTemp < 0)
{
if (ins->mSrc[i].mMemory == IM_FPARAM || ins->mSrc[i].mMemory == IM_FFRAME)
ins->mSrc[0].mLinkerObject->mTemporaries[i - 1] = BC_REG_FPARAMS + ins->mSrc[i].mVarIndex + int(ins->mSrc[i].mIntConst);
}
else
ins->mSrc[0].mLinkerObject->mTemporaries[i - 1] = BC_REG_TMP + proc->mTempOffset[ins->mSrc[i].mTemp];
ins->mSrc[0].mLinkerObject->mTempSizes[i - 1] = InterTypeSize[ins->mSrc[i].mType];
}
ins->mSrc[0].mLinkerObject->mNumTemporaries = ins->mNumOperands - 1;
}
uint32 lf = 0;
if (ins->mSrc[0].mTemp < 0)
{
uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_A)
{
flags |= NCIF_USE_CPU_REG_A;
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS));
}
if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_X)
flags |= NCIF_USE_CPU_REG_X;
if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_Y)
flags |= NCIF_USE_CPU_REG_Y;
assert(ins->mSrc[0].mLinkerObject);
if (ins->mCode == IC_ASSEMBLER && (proc->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER) && ins->mSrc[0].mLinkerObject->mSection == proc->mLinkerObject->mSection)
{
ExpandingArray<NativeCodeInstruction> tains;
uint32 uflags = 0;
bool simple = true;
int i = 0;
while (i < ins->mSrc[0].mLinkerObject->mSize)
{
NativeCodeInstruction dins = DecodeNative(ins, ins->mSrc[0].mLinkerObject, i);
if (dins.mMode == ASMIM_RELATIVE)
simple = false;
if (dins.mType == ASMIT_JMP)
simple = false;
if (dins.mType == ASMIT_RTS && i != ins->mSrc[0].mLinkerObject->mSize)
simple = false;
if (dins.mType == ASMIT_JSR)
{
dins.mFlags |= uflags | NCIF_JSRFLAGS;
}
if (dins.mType == ASMIT_BRK || dins.mMode == ASMIM_INDIRECT_X || dins.mMode == ASMIM_INDIRECT ||
dins.mType == ASMIT_SEI || dins.mType == ASMIT_CLI || dins.mType == ASMIT_SED || dins.mType == ASMIT_CLD ||
dins.mType == ASMIT_RTI || dins.mType == ASMIT_TXS || dins.mType == ASMIT_TSX ||
dins.mType == ASMIT_PHP || dins.mType == ASMIT_PLP || dins.mType == ASMIT_PHA || dins.mType == ASMIT_PLA)
simple = false;
if (dins.mFlags & NCIF_VOLATILE)
simple = false;
if (dins.mMode == ASMIM_ZERO_PAGE && dins.mAddress >= BC_REG_WORK && dins.mAddress < BC_REG_WORK + 8)
uflags |= NICF_USE_WORKREGS;
if (dins.ChangesAccu())
uflags |= NCIF_USE_CPU_REG_A;
if (dins.ChangesXReg())
uflags |= NCIF_USE_CPU_REG_X;
if (dins.ChangesYReg())
uflags |= NCIF_USE_CPU_REG_Y;
tains.Push(dins);
}
if (simple)
{
for (int i = 0; i + 1 < tains.Size(); i++)
mIns.Push(tains[i]);
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
}
else
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
lf = ins->mSrc[0].mLinkerObject->mFlags;
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_FEXEC));
}
if (ins->mDst.mTemp >= 0)
{
if (ins->mDst.mType == IT_FLOAT)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
}
else
{
if (!(lf & LOBJF_RET_REG_A))
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
if (InterTypeSize[ins->mDst.mType] > 1)
{
if (lf & LOBJF_RET_REG_X)
mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
}
if (InterTypeSize[ins->mDst.mType] > 2)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
}
}
}
}
void NativeCodeBasicBlock::BuildLocalRegSets(void)
{
int i;
if (!mVisited)
{
mVisited = true;
mLocalRequiredRegs.Reset(NUM_REGS);
mLocalProvidedRegs.Reset(NUM_REGS);
mEntryRequiredRegs.Reset(NUM_REGS);
mEntryProvidedRegs.Reset(NUM_REGS);
mExitRequiredRegs.Reset(NUM_REGS);
mExitProvidedRegs.Reset(NUM_REGS);
if (mEntryRegA)
mLocalProvidedRegs += CPU_REG_A;
if (mEntryRegX)
mLocalProvidedRegs += CPU_REG_X;
if (mEntryRegY)
mLocalProvidedRegs += CPU_REG_Y;
for (i = 0; i < mIns.Size(); i++)
{
mIns[i].FilterRegUsage(mLocalRequiredRegs, mLocalProvidedRegs);
}
switch (mBranch)
{
case ASMIT_BCC:
case ASMIT_BCS:
if (!mLocalProvidedRegs[CPU_REG_C])
mLocalRequiredRegs += CPU_REG_C;
break;
case ASMIT_BEQ:
case ASMIT_BNE:
case ASMIT_BMI:
case ASMIT_BPL:
if (!mLocalProvidedRegs[CPU_REG_Z])
mLocalRequiredRegs += CPU_REG_Z;
break;
}
if (mExitRegA)
{
if (!mLocalProvidedRegs[CPU_REG_A])
mLocalRequiredRegs += CPU_REG_A;
}
if (mExitRegX)
{
if (!mLocalProvidedRegs[CPU_REG_X])
mLocalRequiredRegs += CPU_REG_X;
}
mEntryRequiredRegs = mLocalRequiredRegs;
mExitProvidedRegs = mLocalProvidedRegs;
if (mTrueJump) mTrueJump->BuildLocalRegSets();
if (mFalseJump) mFalseJump->BuildLocalRegSets();
}
}
void NativeCodeBasicBlock::BuildGlobalProvidedRegSet(NumberSet fromProvidedRegs)
{
if (!mVisited || !(fromProvidedRegs <= mEntryProvidedRegs))
{
mEntryProvidedRegs |= fromProvidedRegs;
fromProvidedRegs |= mExitProvidedRegs;
mVisited = true;
if (mTrueJump) mTrueJump->BuildGlobalProvidedRegSet(fromProvidedRegs);
if (mFalseJump) mFalseJump->BuildGlobalProvidedRegSet(fromProvidedRegs);
}
}
bool NativeCodeBasicBlock::BuildGlobalRequiredRegSet(NumberSet& fromRequiredRegs)
{
bool revisit = false;
if (!mVisited)
{
mVisited = true;
mNewRequiredRegs = mExitRequiredRegs;
if (mTrueJump && mTrueJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true;
if (mFalseJump && mFalseJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true;
if (!(mNewRequiredRegs <= mExitRequiredRegs))
{
revisit = true;
mExitRequiredRegs = mNewRequiredRegs;
mNewRequiredRegs -= mLocalProvidedRegs;
mEntryRequiredRegs |= mNewRequiredRegs;
}
}
fromRequiredRegs |= mEntryRequiredRegs;
return revisit;
}
bool NativeCodeBasicBlock::RemoveUnusedResultInstructions(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
NumberSet requiredRegs(mExitRequiredRegs);
int i;
switch (mBranch)
{
case ASMIT_BCC:
case ASMIT_BCS:
requiredRegs += CPU_REG_C;
break;
case ASMIT_BEQ:
case ASMIT_BNE:
case ASMIT_BMI:
case ASMIT_BPL:
requiredRegs += CPU_REG_Z;
break;
}
for (i = mIns.Size() - 1; i >= 0; i--)
{
if (mIns[i].mType != ASMIT_NOP && !mIns[i].IsUsedResultInstructions(requiredRegs))
{
if (i > 0 && mIns[i - 1].mMode == ASMIM_RELATIVE && mIns[i - 1].mAddress > 0)
{
mIns[i - 1].mType = ASMIT_NOP;
mIns[i - 1].mMode = ASMIM_IMPLIED;
}
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
}
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (mTrueJump)
{
if (mTrueJump->RemoveUnusedResultInstructions())
changed = true;
}
if (mFalseJump)
{
if (mFalseJump->RemoveUnusedResultInstructions())
changed = true;
}
}
return changed;
}
void NativeCodeBasicBlock::BuildCollisionTable(NumberSet* collisionSets)
{
if (!mVisited)
{
mVisited = true;
NumberSet requiredTemps(mExitRequiredRegs);
int i, j;
for (i = 0; i < mExitRequiredRegs.Size(); i++)
{
if (mExitRequiredRegs[i])
{
for (j = 0; j < mExitRequiredRegs.Size(); j++)
{
if (mExitRequiredRegs[j])
{
collisionSets[i] += j;
}
}
}
}
for (i = mIns.Size() - 1; i >= 0; i--)
{
mIns[i].BuildCollisionTable(requiredTemps, collisionSets);
}
if (mTrueJump) mTrueJump->BuildCollisionTable(collisionSets);
if (mFalseJump) mFalseJump->BuildCollisionTable(collisionSets);
}
}
void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from, DominatorStacks& stacks)
{
if (from == this)
return;
else if (!mDominator)
mDominator = from;
else if (from == mDominator)
return;
else
{
stacks.d1.SetSize(0);
stacks.d2.SetSize(0);
NativeCodeBasicBlock* b = mDominator;
while (b)
{
stacks.d1.Push(b);
b = b->mDominator;
}
b = from;
while (b)
{
stacks.d2.Push(b);
b = b->mDominator;
}
b = nullptr;
while (stacks.d1.Size() > 0 && stacks.d2.Size() > 0 && stacks.d1.Last() == stacks.d2.Last())
{
b = stacks.d1.Pop(); stacks.d2.Pop();
}
if (mDominator == b)
return;
mDominator = b;
}
if (mTrueJump)
mTrueJump->BuildDominatorTree(this, stacks);
if (mFalseJump)
mFalseJump->BuildDominatorTree(this, stacks);
}
void NativeCodeBasicBlock::CountEntries(NativeCodeBasicBlock * fromJump)
{
if (mVisiting)
mLoopHead = true;
if (mNumEntries == 0)
mFromJump = fromJump;
else
mFromJump = nullptr;
mNumEntries++;
if (!mVisited)
{
mVisited = true;
mVisiting = true;
if (mTrueJump)
mTrueJump->CountEntries(this);
if (mFalseJump)
mFalseJump->CountEntries(this);
mVisiting = false;
}
}
bool NativeCodeBasicBlock::IsSame(const NativeCodeBasicBlock* block) const
{
if (block->mIns.Size() != mIns.Size())
return false;
if (block->mBranch != mBranch)
return false;
if (mTrueJump)
{
if (!block->mTrueJump)
return false;
if (mTrueJump == this)
{
if (block->mTrueJump != block)
return false;
}
else if (mTrueJump != block->mTrueJump)
return false;
}
else if (block->mTrueJump)
return false;
if (mFalseJump)
{
if (!block->mFalseJump)
return false;
if (mFalseJump == this)
{
if (block->mFalseJump != block)
return false;
}
else if (mFalseJump != block->mFalseJump)
return false;
}
else if (block->mFalseJump)
return false;
for (int i = 0; i < mIns.Size(); i++)
if (!mIns[i].IsSame(block->mIns[i]))
return false;
return true;
}
bool NativeCodeBasicBlock::FindSameBlocks(NativeCodeProcedure* nproc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (!mSameBlock && this != mProc->mEntryBlock)
{
for (int i = 0; i < nproc->mBlocks.Size(); i++)
{
if (nproc->mBlocks[i] != this && nproc->mBlocks[i]->IsSame(this))
{
nproc->mBlocks[i]->mSameBlock = this;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->FindSameBlocks(nproc))
changed = true;
if (mFalseJump && mFalseJump->FindSameBlocks(nproc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::MergeSameBlocks(NativeCodeProcedure* nproc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (this == mProc->mEntryBlock && mSameBlock && mIns.Size() > 1)
{
mTrueJump = mSameBlock;
mFalseJump = nullptr;
mBranch = ASMIT_JMP;
mIns.SetSize(0);
changed = true;
mSameBlock = nullptr;
}
if (mTrueJump && mTrueJump->mSameBlock)
{
mTrueJump = mTrueJump->mSameBlock;
changed = true;
}
if (mFalseJump && mFalseJump->mSameBlock)
{
mFalseJump = mFalseJump->mSameBlock;
changed = true;
}
if (mTrueJump && mTrueJump->MergeSameBlocks(nproc))
changed = true;
if (mFalseJump && mFalseJump->MergeSameBlocks(nproc))
changed = true;
}
return changed;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::ForwardAccuBranch(bool eq, bool ne, bool pl, bool mi, int limit)
{
if (limit == 4)
return this;
limit++;
if (mIns.Size() == 0 && mNumEntries == 1 || mIns.Size() == 1 && mIns[0].mType == ASMIT_ORA && mIns[0].mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == 0)
{
if (mBranch == ASMIT_BEQ)
{
if (eq)
return mTrueJump->ForwardAccuBranch(true, false, true, false, limit);
if (ne || mi)
return mFalseJump->ForwardAccuBranch(false, true, pl, mi, limit);
}
else if (mBranch == ASMIT_BNE)
{
if (eq)
return mFalseJump->ForwardAccuBranch(true, false, true, false, limit);
if (ne || mi)
return mTrueJump->ForwardAccuBranch(false, true, pl, mi, limit);
}
else if (mBranch == ASMIT_BPL)
{
if (eq || pl)
return mTrueJump->ForwardAccuBranch(eq, ne, true, false, limit);
if (mi)
return mFalseJump->ForwardAccuBranch(false, true, false, true, limit);
}
else if (mBranch == ASMIT_BMI)
{
if (eq || pl)
return mFalseJump->ForwardAccuBranch(eq, ne, true, false, limit);
if (mi)
return mTrueJump->ForwardAccuBranch(false, true, false, true, limit);
}
}
return this;
}
void NativeCodeBasicBlock::RemoveJumpToBranch(void)
{
if (!mVisited)
{
mVisited = true;
if (mTrueJump) mTrueJump->RemoveJumpToBranch();
if (mFalseJump) mFalseJump->RemoveJumpToBranch();
if (mTrueJump && !mFalseJump && mTrueJump != this && mTrueJump->mIns.Size() == 0)
{
mTrueJump->mNumEntries--;
mBranch = mTrueJump->mBranch;
mFalseJump = mTrueJump->mFalseJump;
mTrueJump = mTrueJump->mTrueJump;
if (mTrueJump)
mTrueJump->mNumEntries++;
if (mFalseJump)
mFalseJump->mNumEntries++;
}
}
}
bool NativeCodeBasicBlock::MergeBasicBlocks(void)
{
bool changed = false;
if (!mVisited)
{
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
mVisited = true;
if (!mLocked)
{
if (mTrueJump && mFalseJump && mTrueJump != this && mFalseJump != this && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI))
{
if (mIns.Size() > 0 && mIns[mIns.Size() - 1].mType == ASMIT_LDA)
{
if (mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].IsSame(mIns[mIns.Size() - 1]))
{
if (mTrueJump->mBranch == mBranch)
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
else if (mTrueJump->mBranch == InvertBranchCondition(mBranch))
{
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
}
if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].IsSame(mIns[mIns.Size() - 1]))
{
if (mFalseJump->mBranch == mBranch)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
else if (mFalseJump->mBranch == InvertBranchCondition(mBranch))
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
}
}
if (mFalseJump)
{
if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump)
{
if (mTrueJump->mBranch == mBranch)
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
else if (mTrueJump->mBranch == InvertBranchCondition(mBranch))
{
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
}
if (mFalseJump->mIns.Size() == 0 && mFalseJump->mFalseJump)
{
if (mFalseJump->mBranch == mBranch)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
else if (mFalseJump->mBranch == InvertBranchCondition(mBranch))
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
}
while (mTrueJump && !mFalseJump && mTrueJump->mNumEntries == 1 && mTrueJump != this && !mTrueJump->mLocked)
{
for (int i = 0; i < mTrueJump->mIns.Size(); i++)
mIns.Push(mTrueJump->mIns[i]);
mBranch = mTrueJump->mBranch;
mFalseJump = mTrueJump->mFalseJump;
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
int steps = 100;
while (mTrueJump && mTrueJump->mIns.Size() == 0 && !mTrueJump->mFalseJump && !mTrueJump->mLocked && mTrueJump != this && mTrueJump->mTrueJump != mTrueJump && steps > 0)
{
mTrueJump->mNumEntries--;
mTrueJump = mTrueJump->mTrueJump;
mTrueJump->mNumEntries++;
changed = true;
steps--;
}
steps = 100;
while (mFalseJump && mFalseJump->mTrueJump && mFalseJump->mIns.Size() == 0 && !mFalseJump->mFalseJump && !mFalseJump->mLocked && mFalseJump != this && mFalseJump->mTrueJump != mFalseJump && steps > 0)
{
mFalseJump->mNumEntries--;
mFalseJump = mFalseJump->mTrueJump;
mFalseJump->mNumEntries++;
changed = true;
steps--;
}
if (mTrueJump && mTrueJump == mFalseJump)
{
mBranch = ASMIT_JMP;
mFalseJump = nullptr;
changed = true;
}
#if 1
if (mIns.Size() > 0 && mIns.Last().ChangesAccuAndFlag() && mTrueJump && mFalseJump)
{
NativeCodeBasicBlock* ntb = mTrueJump, * nfb = mFalseJump;
if (mBranch == ASMIT_BEQ)
{
ntb = ntb->ForwardAccuBranch(true, false, true, false, 0);
nfb = nfb->ForwardAccuBranch(false, true, false, false, 0);
}
else if (mBranch == ASMIT_BNE)
{
nfb = nfb->ForwardAccuBranch(true, false, true, false, 0);
ntb = ntb->ForwardAccuBranch(false, true, false, false, 0);
}
else if (mBranch == ASMIT_BPL)
{
ntb = ntb->ForwardAccuBranch(false, false, true, false, 0);
nfb = nfb->ForwardAccuBranch(false, true, false, true, 0);
}
else if (mBranch == ASMIT_BMI)
{
nfb = nfb->ForwardAccuBranch(false, false, true, false, 0);
ntb = ntb->ForwardAccuBranch(false, true, false, true, 0);
}
if (ntb != mTrueJump)
{
mTrueJump->mNumEntries--;
mTrueJump = ntb;
mTrueJump->mNumEntries++;
changed = true;
}
if (nfb != mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump = nfb;
mFalseJump->mNumEntries++;
changed = true;
}
}
#endif
}
if (mTrueJump && mTrueJump->MergeBasicBlocks())
changed = true;
if (mFalseJump && mFalseJump->MergeBasicBlocks())
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
return changed;
}
void NativeCodeBasicBlock::CollectEntryBlocks(NativeCodeBasicBlock* block)
{
if (block)
mEntryBlocks.Push(block);
if (!mVisited)
{
mVisited = true;
if (mTrueJump)
mTrueJump->CollectEntryBlocks(this);
if (mFalseJump)
mFalseJump->CollectEntryBlocks(this);
}
}
void NativeCodeBasicBlock::BuildEntryDataSet(const NativeRegisterDataSet& set)
{
if (!mVisited)
mEntryRegisterDataSet = set;
else
{
bool changed = false;
for (int i = 0; i < NUM_REGS; i++)
{
if (set.mRegs[i].mMode == NRDM_IMMEDIATE)
{
if (mEntryRegisterDataSet.mRegs[i].mMode == NRDM_IMMEDIATE && set.mRegs[i].mValue == mEntryRegisterDataSet.mRegs[i].mValue)
{
}
else if (mEntryRegisterDataSet.mRegs[i].mMode != NRDM_UNKNOWN)
{
mEntryRegisterDataSet.mRegs[i].Reset();
mVisited = false;
}
}
else if (set.mRegs[i].mMode == NRDM_IMMEDIATE_ADDRESS)
{
if (mEntryRegisterDataSet.mRegs[i].mMode == NRDM_IMMEDIATE_ADDRESS &&
set.mRegs[i].mValue == mEntryRegisterDataSet.mRegs[i].mValue &&
set.mRegs[i].mLinkerObject == mEntryRegisterDataSet.mRegs[i].mLinkerObject &&
set.mRegs[i].mFlags == mEntryRegisterDataSet.mRegs[i].mFlags)
{
}
else if (mEntryRegisterDataSet.mRegs[i].mMode != NRDM_UNKNOWN)
{
mEntryRegisterDataSet.mRegs[i].Reset();
mVisited = false;
}
}
else if (mEntryRegisterDataSet.mRegs[i].mMode != NRDM_UNKNOWN)
{
mEntryRegisterDataSet.mRegs[i].Reset();
mVisited = false;
}
}
}
if (!mVisited)
{
mVisited = true;
mNDataSet = mEntryRegisterDataSet;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].Simulate(mNDataSet);
mFDataSet = mNDataSet;
if (mBranch == ASMIT_BCC)
{
mNDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_C].mValue = 0;
mFDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_C].mValue = 1;
}
else if (mBranch == ASMIT_BCS)
{
mNDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_C].mValue = 1;
mFDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_C].mValue = 0;
}
if (mTrueJump)
mTrueJump->BuildEntryDataSet(mNDataSet);
if (mFalseJump)
mFalseJump->BuildEntryDataSet(mFDataSet);
}
}
bool NativeCodeBasicBlock::ApplyEntryDataSet(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
mNDataSet = mEntryRegisterDataSet;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].ApplySimulation(mNDataSet))
changed = true;
mIns[i].Simulate(mNDataSet);
}
if (mTrueJump && mTrueJump->ApplyEntryDataSet())
changed = true;
if (mFalseJump && mFalseJump->ApplyEntryDataSet())
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu)
{
if (!mVisited)
{
mVisited = true;
if (mNumEntries > 1)
accu = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mType == ASMIT_LDA)
accu = mIns[i].mAddress;
else if (mIns[i].mType == ASMIT_STA)
{
if (accu < 0 || !statics[accu])
invalid += mIns[i].mAddress;
else if (alias[mIns[i].mAddress])
{
if (alias[mIns[i].mAddress] != accu)
invalid += mIns[i].mAddress;
}
else
{
alias[mIns[i].mAddress] = accu;
}
}
else if (mIns[i].ChangesAccu())
accu = -1;
else if (mIns[i].ChangesAddress())
invalid += mIns[i].mAddress;
}
else if (mIns[i].mType == ASMIT_JSR && (mIns[i].mFlags & NCIF_USE_ZP_32_X))
{
int j = mIns[i].mParam;
invalid += j;
invalid += j + 1;
invalid += j + 2;
invalid += j + 3;
accu = -1;
}
else if (mIns[i].ChangesAccu())
accu = -1;
}
if (mTrueJump)
mTrueJump->FindZeroPageAlias(statics, invalid, alias, accu);
if (mFalseJump)
mFalseJump->FindZeroPageAlias(statics, invalid, alias, accu);
}
}
bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global, bool ignorefcall)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
switch (mIns[i].mMode)
{
case ASMIM_ZERO_PAGE:
if (mIns[i].ChangesAddress())
locals += mIns[i].mAddress;
break;
case ASMIM_ABSOLUTE:
if (mIns[i].mType == ASMIT_JSR)
{
if (mIns[i].mFlags & NCIF_RUNTIME)
{
if (mIns[i].mFlags & NCIF_FEXEC)
{
if (!ignorefcall)
return false;
}
else
{
for (int j = 0; j < 4; j++)
{
locals += BC_REG_ACCU + j;
locals += BC_REG_WORK + j;
}
}
}
if (mIns[i].mLinkerObject)
{
LinkerObject* lo = mIns[i].mLinkerObject;
if (lo->mFlags & LOBJF_ZEROPAGESET)
{
global |= lo->mZeroPageSet;
}
else if (!lo->mProc)
{
for (int i = 0; i < lo->mNumTemporaries; i++)
{
for (int j = 0; j < lo->mTempSizes[i]; j++)
global += lo->mTemporaries[i] + j;
}
}
else
return false;
}
}
break;
case ASMIM_ZERO_PAGE_X:
if (mIns[i].ChangesAddress())
{
if (i > 1 && i + 2 < mIns.Size())
{
if (mIns[i - 2].mType == ASMIT_LDX && mIns[i - 2].mMode == ASMIM_IMMEDIATE &&
mIns[i - 1].mType == ASMIT_LDA &&
mIns[i + 0].mType == ASMIT_STA &&
mIns[i + 1].mType == ASMIT_DEX &&
mIns[i + 2].mType == ASMIT_BPL)
{
for (int j = 0; j < mIns[i - 2].mAddress; j++)
locals += mIns[i].mAddress + j;
}
}
}
break;
}
}
if (mTrueJump && !mTrueJump->CollectZeroPageSet(locals, global, ignorefcall))
return false;
if (mFalseJump && !mFalseJump->CollectZeroPageSet(locals, global, ignorefcall))
return false;
}
return true;
}
void NativeCodeBasicBlock::CollectZeroPageUsage(NumberSet& used, NumberSet &modified, NumberSet& pairs)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
switch (mIns[i].mMode)
{
case ASMIM_ZERO_PAGE:
used += mIns[i].mAddress;
if (mIns[i].ChangesAddress())
modified += mIns[i].mAddress;
break;
case ASMIM_INDIRECT_Y:
used += mIns[i].mAddress + 0;
used += mIns[i].mAddress + 1;
pairs += mIns[i].mAddress;
break;
case ASMIM_ABSOLUTE:
if (mIns[i].mType == ASMIT_JSR)
{
if (mIns[i].mFlags & NCIF_RUNTIME)
{
for (int j = 0; j < 4; j++)
{
used += BC_REG_ACCU + j;
used += BC_REG_WORK + j;
modified += BC_REG_ACCU + j;
modified += BC_REG_WORK + j;
}
if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
{
for (int j = 0; j < 4; j++)
used += mIns[i].mParam + j;
for (int j = 0; j < 3; j++)
pairs += mIns[i].mParam + j;
}
}
if (mIns[i].mLinkerObject)
{
LinkerObject* lo = mIns[i].mLinkerObject;
for (int i = 0; i < lo->mNumTemporaries; i++)
{
for (int j = 0; j < lo->mTempSizes[i]; j++)
used += lo->mTemporaries[i] + j;
}
}
}
break;
}
}
if (mTrueJump)
mTrueJump->CollectZeroPageUsage(used, modified, pairs);
if (mFalseJump)
mFalseJump->CollectZeroPageUsage(used, modified, pairs);
}
}
void NativeCodeBasicBlock::GlobalRegisterXMap(int reg)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
switch (ins.mType)
{
case ASMIT_STA:
ins.mType = ASMIT_TAX;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDA:
ins.mType = ASMIT_TXA;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_INC:
ins.mType = ASMIT_INX;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_DEC:
ins.mType = ASMIT_DEX;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDX:
assert(ins.mAddress == reg);
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
break;
}
}
}
if (mTrueJump)
mTrueJump->GlobalRegisterXMap(reg);
if (mFalseJump)
mFalseJump->GlobalRegisterXMap(reg);
}
}
void NativeCodeBasicBlock::GlobalRegisterYMap(int reg)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
switch (ins.mType)
{
case ASMIT_STA:
ins.mType = ASMIT_TAY;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDA:
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_INC:
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_DEC:
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDY:
assert(ins.mAddress == reg);
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
break;
}
}
}
if (mTrueJump)
mTrueJump->GlobalRegisterYMap(reg);
if (mFalseJump)
mFalseJump->GlobalRegisterYMap(reg);
}
}
bool NativeCodeBasicBlock::ReplaceYRegWithXReg(int start, int end)
{
bool changed = false;
// CheckLive();
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.ReplaceYRegWithXReg())
changed = true;
}
// CheckLive();
return changed;
}
bool NativeCodeBasicBlock::ReduceLocalYPressure(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
#if 1
if (mLoopHead && mFalseJump && mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_X] && !mExitRequiredRegs[CPU_REG_X] && mEntryBlocks.Size() == 2 && (mFalseJump == this || mTrueJump == this))
{
NativeCodeBasicBlock* pblock, * nblock;
if (mTrueJump == this)
nblock = mFalseJump;
else
nblock = mTrueJump;
if (mEntryBlocks[0] == this)
pblock = mEntryBlocks[1];
else
pblock = mEntryBlocks[0];
if (!pblock->mFalseJump && !nblock->mEntryRequiredRegs[CPU_REG_Y])
{
int pz = pblock->mIns.Size();
while (pz > 0 && !pblock->mIns[pz - 1].ReferencesYReg() && !pblock->mIns[pz - 1].ReferencesXReg())
pz--;
if (mEntryRequiredRegs[CPU_REG_Y] && pz > 0 && pblock->mIns[pz - 1].mType == ASMIT_LDY && pblock->mIns[pz - 1].mMode == ASMIM_IMMEDIATE)
{
if (CanReplaceYRegWithXReg(0, mIns.Size()))
{
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
pblock->mExitRequiredRegs += CPU_REG_X; pblock->mExitRequiredRegs -= CPU_REG_Y;
ReplaceYRegWithXReg(0, mIns.Size());
mEntryRequiredRegs -= CPU_REG_Y;
mExitRequiredRegs -= CPU_REG_Y;
pz--;
pblock->mIns[pz].mType = ASMIT_LDX;
while (pz < pblock->mIns.Size())
{
pblock->mIns[pz].mLive |= LIVE_CPU_REG_X;
pz++;
}
changed = true;
}
}
}
}
#endif
int start = 0;
while (start < mIns.Size())
{
const NativeCodeInstruction& ins(mIns[start]);
if ((ins.mType == ASMIT_LDY || ins.mType == ASMIT_TAY) && ins.mMode != ASMIM_ABSOLUTE_X && !(ins.mLive & LIVE_CPU_REG_X))
{
int end = start + 1;
while (end < mIns.Size())
{
const NativeCodeInstruction& eins(mIns[end]);
if (eins.mType == ASMIT_LDY || eins.mType == ASMIT_TAY)
{
ReplaceYRegWithXReg(start, end);
changed = true;
break;
}
else if (eins.ChangesXReg() || eins.mMode == ASMIM_INDIRECT_Y)
{
break;
}
else if (!(eins.mLive & LIVE_CPU_REG_Y))
{
end++;
ReplaceYRegWithXReg(start, end);
changed = true;
break;
}
end++;
}
start = end;
}
else
start++;
}
CheckLive();
if (mTrueJump && mTrueJump->ReduceLocalYPressure())
changed = true;
if (mFalseJump && mFalseJump->ReduceLocalYPressure())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ForwardAccuAddSub(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int aoffset = 0, apred = 0, aload = -1;
int carry = 0;
CheckLive();
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
{
if (aload != -1 && mIns[i].SameEffectiveAddress(mIns[aload]))
{
if (aoffset == 0)
{
for (int j = apred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_A;
if (mIns[i].mLive & LIVE_CPU_REG_Z)
{
mIns[i].mType = ASMIT_ORA; mIns[i].mMode = ASMIM_IMMEDIATE; mIns[i].mAddress = 0;
}
else
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
for (int j = apred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mAddress = (mIns[i + 2].mAddress - aoffset) & 0xff;
changed = true;
}
else if (carry == 1 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
for (int j = apred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mAddress = (mIns[i + 1].mAddress - aoffset) & 0xff;
changed = true;
}
else
{
aload = i;
aoffset = 0;
}
}
else
{
aload = i;
aoffset = 0;
}
apred = i;
}
else if (mIns[i + 0].mType == ASMIT_CLC)
carry = 1;
else if (mIns[i + 0].mType == ASMIT_SEC)
carry = -1;
else if (aload != -1 && carry == 1 &&
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE)
{
aoffset = (aoffset + mIns[i + 0].mAddress) & 0xff;
apred = i;
carry = 0;
}
else if (aload != -1 && carry == -1 &&
mIns[i + 0].mType == ASMIT_SBC && mIns[i + 0].mMode == ASMIM_IMMEDIATE)
{
aoffset = (aoffset - mIns[i + 0].mAddress) & 0xff;
apred = i;
}
else if (aload != -1 && mIns[i].mType == ASMIT_STA && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && mIns[i].SameEffectiveAddress(mIns[aload]))
{
aoffset = 0;
apred = i;
}
else if (aload != -1 && mIns[i].mType == ASMIT_STA && mIns[aload].mMode != ASMIM_ZERO_PAGE&& mIns[i].mMode == ASMIM_ZERO_PAGE)
{
aload = i;
aoffset = 0;
apred = i;
}
else
{
if (mIns[i].ChangesCarry())
carry = 0;
if (aload != -1 && mIns[i].ChangesAccu())
aload = -1;
if (aload != -1 && mIns[aload].MayBeChangedOnAddress(mIns[i]))
aload = -1;
}
}
CheckLive();
if (mTrueJump && mTrueJump->ForwardAccuAddSub())
changed = true;
if (mFalseJump && mFalseJump->ForwardAccuAddSub())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ForwardAXYReg(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
bool xisa = false, yisa = false;
int xoffset = -1, yoffset = -1;
int zpx = -1, zpy = -1, zpa = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TAX)
{
xisa = true;
xoffset = i;
zpx = zpa;
}
else if (mIns[i].mType == ASMIT_TXA)
{
xisa = true;
yisa = false;
xoffset = i;
zpa = zpx;
}
else if (mIns[i].mType == ASMIT_TAY)
{
yisa = true;
yoffset = i;
zpy = zpa;
}
else if (mIns[i].mType == ASMIT_TYA)
{
yisa = true;
xisa = false;
yoffset = i;
zpa = zpy;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (zpx == mIns[i].mAddress)
{
mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;
xisa = true;
yisa = false;
int j = i;
while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_X))
{
mIns[j - 1].mLive |= LIVE_CPU_REG_X;
j--;
}
}
else if (zpy == mIns[i].mAddress)
{
mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
yisa = true;
xisa = false;
int j = i;
while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_Y))
{
mIns[j - 1].mLive |= LIVE_CPU_REG_Y;
j--;
}
}
else
{
xisa = false;
yisa = false;
}
zpa = mIns[i].mAddress;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
xisa = false;
zpx = mIns[i].mAddress;
}
else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
yisa = false;
zpy = mIns[i].mAddress;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
zpa = mIns[i].mAddress;
if (yisa)
zpy = mIns[i].mAddress;
else if (zpy == mIns[i].mAddress)
zpy = -1;
if (xisa)
zpx = mIns[i].mAddress;
else if (zpx == mIns[i].mAddress)
zpx = -1;
}
else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
zpx = mIns[i].mAddress;
if (xisa)
zpa = mIns[i].mAddress;
else if (zpa == mIns[i].mAddress)
zpa = -1;
if (zpy == mIns[i].mAddress)
zpy = -1;
}
else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
zpy = mIns[i].mAddress;
if (yisa)
zpa = mIns[i].mAddress;
else if (zpa == mIns[i].mAddress)
zpa = -1;
if (zpx == mIns[i].mAddress)
zpx = -1;
}
else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
if (xisa && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
if (mIns[i + 1].mAddress == 1)
{
mIns[i + 0].mType = ASMIT_INX;
mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
for (int j = xoffset; j < i + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
xisa = false;
changed = true;
}
}
else if (yisa && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
if (mIns[i + 1].mAddress == 1)
{
mIns[i + 0].mType = ASMIT_INY;
mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mMode = ASMIM_IMPLIED;
for (int j = yoffset; j < i + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
yisa = false;
changed = true;
}
}
}
else
{
if (mIns[i].ChangesXReg())
{
xisa = false;
zpx = -1;
}
if (mIns[i].ChangesYReg())
{
yisa = false;
zpy = -1;
}
if (mIns[i].ChangesAccu())
{
xisa = false;
yisa = false;
zpa = -1;
}
if (zpa >= 0 && mIns[i].ChangesZeroPage(zpa))
zpa = -1;
if (zpx >= 0 && mIns[i].ChangesZeroPage(zpx))
zpx = -1;
if (zpy >= 0 && mIns[i].ChangesZeroPage(zpy))
zpy = -1;
}
}
if (mTrueJump && mTrueJump->ForwardAXYReg())
changed = true;
if (mFalseJump && mFalseJump->ForwardAXYReg())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ForwardZpYIndex(bool full)
{
CheckLive();
bool changed = false;
if (!mVisited)
{
mVisited = true;
int yreg = -1, yoffset = 0, ypred = 0;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (yreg == mIns[i].mAddress)
{
if (yoffset == 0)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (yoffset == 1 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (yoffset == 1)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED;
yoffset = 0;
changed = true;
}
else if (yoffset == 2 && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY && mIns[i + 2].mType == ASMIT_INY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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;
changed = true;
}
else if (yoffset == 2 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEY;
changed = true;
}
else if (yoffset == 3 && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY && mIns[i + 2].mType == ASMIT_INY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (yoffset == 3 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED;
yoffset = 2;
changed = true;
}
else if (yoffset == 0xff && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (yoffset == 0xff)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED;
yoffset = 0;
changed = true;
}
else if (yoffset == 0xfe && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY && mIns[i + 2].mType == ASMIT_DEY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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;
changed = true;
}
else if (yoffset == 0xfe && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INY;
changed = true;
}
else if (yoffset == 0xfd && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY && mIns[i + 2].mType == ASMIT_DEY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (yoffset == 0xfd && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
yoffset = 0xfe;
changed = true;
}
else
yoffset = 0;
ypred = i;
}
else
{
if (full && yreg >= 0)
{
int j = i;
while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(yreg))
j++;
if (j + 2 < mIns.Size() &&
mIns[j - 1].mType == ASMIT_CLC &&
mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == yreg &&
!(mIns[j + 2].mLive & LIVE_CPU_REG_C))
{
if (mIns[j + 1].mAddress == ((yoffset + 1) & 0xff))
{
for (int k = ypred; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
mIns.Remove(j + 2);
mIns.Remove(j + 1);
mIns.Remove(j - 1);
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
i += 2;
changed = true;
}
else if (mIns[j + 1].mAddress == ((yoffset - 1) & 0xff))
{
for (int k = ypred; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
mIns.Remove(j + 2);
mIns.Remove(j + 1);
mIns.Remove(j - 1);
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
i += 2;
changed = true;
}
}
}
yreg = mIns[i].mAddress;
yoffset = 0;
ypred = i;
}
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_TAY)
{
if (mIns[i + 1].mAddress == yreg && mIns[i + 2].mAddress == ((yoffset + 1) & 0xff) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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;
mIns[i + 3].mType = ASMIT_INY;
changed = true;
}
else if (mIns[i + 1].mAddress == yreg && mIns[i + 2].mAddress == ((yoffset - 1) & 0xff) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
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;
mIns[i + 3].mType = ASMIT_DEY;
changed = true;
}
else
{
yreg = mIns[i + 1].mAddress;
yoffset = mIns[i + 2].mAddress;
ypred = i + 3;
i += 3;
}
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset + 1) & 0xff) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
for (int j = ypred; j < i + 3; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
mIns[i + 0].mType = ASMIT_INY;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mAddress = mIns[i + 3].mAddress;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
ypred = i + 1;
yoffset = (yoffset + 1) & 0xff;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
{
mIns[i + 3].mType = ASMIT_TYA;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset - 1) & 0xff) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
for (int j = ypred; j < i + 3; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
mIns[i + 0].mType = ASMIT_DEY;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mAddress = mIns[i + 3].mAddress;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
ypred = i + 1;
yoffset = (yoffset - 1) & 0xff;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
{
mIns[i + 3].mType = ASMIT_TYA;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset + 2) & 0xff) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
for (int j = ypred; j < i + 3; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
mIns[i + 0].mType = ASMIT_INY;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].CopyMode(mIns[i + 3]);
ypred = i + 1;
yoffset = (yoffset + 2) & 0xff;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
{
mIns[i + 3].mType = ASMIT_TYA;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
}
changed = true;
}
else if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == yreg &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg && yoffset == 0)
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY;
ypred = i + 1;
yoffset = (yoffset + 1) & 0xff;
changed = true;
}
else if (i + 2 < mIns.Size() && full &&
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == yreg &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg && yoffset == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY, ASMIM_IMPLIED));
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
yreg = -1;
changed = true;
}
else if (mIns[i].mType == ASMIT_INY)
{
yoffset = (yoffset + 1) & 255;
}
else if (mIns[i].mType == ASMIT_DEY)
{
yoffset = (yoffset - 1) & 255;
}
else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
i++;
yreg = mIns[i].mAddress;
yoffset = 0;
ypred = i;
}
else if (mIns[i].ChangesYReg())
{
if (full && yreg >= 0 && !mIns[i].RequiresYReg())
{
int j = i;
while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(yreg))
j++;
if (j + 2 < mIns.Size() &&
mIns[j - 1].mType == ASMIT_CLC &&
mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == yreg &&
!(mIns[j + 2].mLive & LIVE_CPU_REG_C))
{
if (mIns[j + 1].mAddress == yoffset + 1)
{
for (int k = ypred; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
mIns.Remove(j + 2);
mIns.Remove(j + 1);
mIns.Remove(j - 1);
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
i += 2;
changed = true;
}
}
}
yreg = -1;
}
else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg)
{
yoffset = 0;
ypred = i;
}
else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 1 && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
mIns[i].mType = ASMIT_STY;
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
yoffset = 0;
ypred = i;
changed = true;
}
#if 1
else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 0 && mIns[ypred].mType == ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
{
for (int j = ypred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
mIns[i].mType = ASMIT_STY;
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
ypred = i + 1;
}
#endif
else if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
{
yreg = -1;
}
}
CheckLive();
if (mTrueJump && mTrueJump->ForwardZpYIndex(full))
changed = true;
if (mFalseJump && mFalseJump->ForwardZpYIndex(full))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CanCombineSameYtoX(int start, int end)
{
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_INDIRECT_Y)
return false;
if (ins.mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_X))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CanCombineSameXtoY(int start, int end)
{
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_INDIRECT_X)
return false;
if (ins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CombineSameXtoY(int xpos, int ypos, int end)
{
if (xpos < ypos)
{
if (CanCombineSameXtoY(xpos, ypos) &&
CanCombineSameXtoY(ypos + 1, end) &&
!ReferencesYReg(xpos, ypos))
{
ReplaceXRegWithYReg(xpos, ypos);
ReplaceXRegWithYReg(ypos + 1, end);
for (int i = xpos; i < ypos; i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z))
{
mIns[ypos].mType = ASMIT_NOP;
mIns[ypos].mMode = ASMIM_IMPLIED;
}
return true;
}
}
else
{
if (CanCombineSameXtoY(xpos, end))
{
ReplaceXRegWithYReg(xpos, end);
for (int i = ypos; i < xpos; i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z))
{
mIns[xpos].mType = ASMIT_NOP;
mIns[xpos].mMode = ASMIM_IMPLIED;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::CombineSameYtoX(int xpos, int ypos, int end)
{
if (ypos < xpos)
{
if (CanCombineSameYtoX(ypos, xpos) &&
CanCombineSameYtoX(xpos + 1, end) &&
!ReferencesXReg(ypos, xpos))
{
ReplaceYRegWithXReg(ypos, xpos);
ReplaceYRegWithXReg(xpos + 1, end);
for (int i = ypos; i < xpos; i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z))
{
mIns[xpos].mType = ASMIT_NOP;
mIns[xpos].mMode = ASMIM_IMPLIED;
}
return true;
}
}
else
{
if (CanCombineSameYtoX(ypos, end))
{
ReplaceYRegWithXReg(ypos, end);
for (int i = xpos; i < ypos; i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z))
{
mIns[ypos].mType = ASMIT_NOP;
mIns[ypos].mMode = ASMIM_IMPLIED;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::CombineSameXY(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int xreg = -1, yreg = -1;
int xpos, ypos;
bool samexy = false;
CheckLive();
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.ChangesXReg())
{
if (samexy)
{
if (!ins.RequiresXReg() && CombineSameXtoY(xpos, ypos, i))
changed = true;
else if (!ins.RequiresYReg() && !(ins.mLive & LIVE_CPU_REG_Y) && CombineSameYtoX(xpos, ypos, i))
{
changed = true;
yreg = -1;
}
CheckLive();
}
xreg = -1;
samexy = false;
}
if (ins.ChangesYReg())
{
if (samexy)
{
if (!ins.RequiresYReg() && CombineSameYtoX(xpos, ypos, i))
changed = true;
else if (!ins.RequiresXReg() && !(ins.mLive & LIVE_CPU_REG_X) && CombineSameXtoY(xpos, ypos, i))
{
changed = true;
xreg = -1;
}
CheckLive();
}
yreg = -1;
samexy = false;
}
if (ins.mType == ASMIT_TAX)
{
xreg = CPU_REG_A;
xpos = i;
samexy = yreg == xreg;
}
else if (ins.mType == ASMIT_TAY)
{
yreg = CPU_REG_A;
ypos = i;
samexy = xreg == yreg;
}
else if (ins.mType == ASMIT_LDX)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
{
xreg = ins.mAddress;
xpos = i;
samexy = yreg == xreg;
}
else
xreg = -1;
}
else if (ins.mType == ASMIT_LDY)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
{
yreg = ins.mAddress;
ypos = i;
samexy = xreg == yreg;
}
else
yreg = -1;
}
else if (ins.ChangesAccu())
{
if (xreg == CPU_REG_A)
xreg = -1;
if (yreg == CPU_REG_A)
yreg = -1;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
{
if (xreg == ins.mAddress)
xreg = -1;
if (yreg == ins.mAddress)
yreg = -1;
}
}
if (samexy)
{
if (!mExitRequiredRegs[CPU_REG_X] && CombineSameXtoY(xpos, ypos, mIns.Size()))
changed = true;
else if (!mExitRequiredRegs[CPU_REG_Y] && CombineSameYtoX(xpos, ypos, mIns.Size()))
changed = true;
}
CheckLive();
if (mTrueJump && mTrueJump->CombineSameXY())
changed = true;
if (mFalseJump && mFalseJump->CombineSameXY())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::JoinXYCrossBlock(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int xins = -1, yins = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX)
{
xins = i;
if (yins >= 0 && mIns[yins].SameEffectiveAddress(mIns[xins]))
{
if (CanCombineSameXtoYCrossBlock(xins + 1))
{
for (int j = yins; j <= xins; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
if (CombineSameXtoYCrossBlock(xins + 1))
changed = true;
}
else if (CanCombineSameYtoX(yins + 1, xins) && CanCombineSameYtoXCrossBlock(xins + 1))
{
ReplaceXRegWithYReg(yins, xins);
for (int j = yins; j <= xins; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
if (CombineSameYtoXCrossBlock(xins + 1))
changed = true;
}
}
yins = -1;
}
else if (mIns[i].mType == ASMIT_LDY)
{
yins = i;
if (xins >= 0 && mIns[yins].SameEffectiveAddress(mIns[xins]))
{
if (CanCombineSameYtoXCrossBlock(yins + 1))
{
for (int j = xins; j <= yins; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
if (CombineSameYtoXCrossBlock(yins + 1))
changed = true;
}
else if (CanCombineSameXtoY(xins + 1, yins) && CanCombineSameXtoYCrossBlock(yins + 1))
{
ReplaceYRegWithXReg(xins, yins);
for (int j = xins; j <= yins; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
if (CombineSameXtoYCrossBlock(yins + 1))
changed = true;
}
}
xins = -1;
}
else
{
if (mIns[i].ChangesXReg())
xins = -1;
if (mIns[i].ChangesYReg())
yins = -1;
if (xins >= 0 && mIns[xins].MayBeChangedOnAddress(mIns[i]))
xins = -1;
if (yins >= 0 && mIns[yins].MayBeChangedOnAddress(mIns[i]))
yins = -1;
}
}
if (mTrueJump && mTrueJump->JoinXYCrossBlock())
changed = true;
if (mFalseJump && mFalseJump->JoinXYCrossBlock())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CanCombineSameXtoYCrossBlock(int from)
{
if (!from)
{
if (!mEntryRequiredRegs[CPU_REG_X])
return true;
if (mEntryBlocks.Size() > 1)
return false;
}
for (int i = from; i < mIns.Size(); i++)
{
if (mIns[i].ChangesXReg())
return !mIns[i].ReferencesXReg();
if (mIns[i].ChangesYReg())
return false;
if (mIns[i].mMode == ASMIM_INDIRECT_X)
return false;
if (mIns[i].mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
return false;
}
if (mTrueJump && !mTrueJump->CanCombineSameXtoYCrossBlock(0))
return false;
if (mFalseJump && !mFalseJump->CanCombineSameXtoYCrossBlock(0))
return false;
return true;
}
bool NativeCodeBasicBlock::CanCombineSameYtoXCrossBlock(int from)
{
if (!from)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return true;
if (mEntryBlocks.Size() > 1)
return false;
}
for (int i = from; i < mIns.Size(); i++)
{
if (mIns[i].ChangesYReg())
return !mIns[i].ReferencesYReg();
if (mIns[i].ChangesXReg())
return false;
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
return false;
if (mIns[i].mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
return false;
}
if (mTrueJump && !mTrueJump->CanCombineSameYtoXCrossBlock(0))
return false;
if (mFalseJump && !mFalseJump->CanCombineSameYtoXCrossBlock(0))
return false;
return true;
}
bool NativeCodeBasicBlock::CombineSameXtoYCrossBlock(int from)
{
if (!from)
{
if (!mEntryRequiredRegs[CPU_REG_X])
return false;
mEntryRequiredRegs += CPU_REG_Y;
assert(mEntryBlocks.Size() == 1);
}
bool changed = false;
for (int i = from; i < mIns.Size(); i++)
{
if (mIns[i].ChangesXReg())
return changed;
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mMode == ASMIM_ABSOLUTE_X)
{
mIns[i].mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
if (mIns[i].mType == ASMIT_TXA)
{
mIns[i].mType = ASMIT_TYA;
changed = true;
}
else if (mIns[i].mType == ASMIT_STX)
{
mIns[i].mType = ASMIT_STY;
changed = true;
}
}
mExitRequiredRegs += CPU_REG_Y;
if (mTrueJump && mTrueJump->CombineSameXtoYCrossBlock(0))
changed = true;
if (mFalseJump && !mFalseJump->CombineSameXtoYCrossBlock(0))
changed = true;
return changed;
}
bool NativeCodeBasicBlock::CombineSameYtoXCrossBlock(int from)
{
if (!from)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return false;
mEntryRequiredRegs += CPU_REG_X;
assert(mEntryBlocks.Size() == 1);
}
bool changed = false;
for (int i = from; i < mIns.Size(); i++)
{
if (mIns[i].ChangesYReg())
return changed;
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
{
mIns[i].mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
if (mIns[i].mType == ASMIT_TYA)
{
mIns[i].mType = ASMIT_TXA;
changed = true;
}
else if (mIns[i].mType == ASMIT_STY)
{
mIns[i].mType = ASMIT_STX;
changed = true;
}
}
mExitRequiredRegs += CPU_REG_X;
if (mTrueJump && mTrueJump->CombineSameYtoXCrossBlock(0))
changed = true;
if (mFalseJump && !mFalseJump->CombineSameYtoXCrossBlock(0))
changed = true;
return changed;
}
bool NativeCodeBasicBlock::JoinXYCascade(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
bool restart;
do {
restart = false;
int predXPos = -1, predYPos = -1;
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
if (predXPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)) && ((mIns[predXPos + 2].mAddress + 1) & 0xff) == mIns[i + 2].mAddress)
{
// Remove add
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
// Insert INX
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
// Insert TAX
mIns[predXPos + 2].mLive &= ~LIVE_CPU_REG_X;
mIns.Insert(predXPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));
// Restart
restart = true;
predXPos = -1;
predYPos = -1;
changed = true;
}
else if (predXPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)) && ((mIns[predXPos + 2].mAddress - 1) & 0xff) == mIns[i + 2].mAddress)
{
// Remove add
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
// Insert DEX
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
// Insert TAX
mIns[predXPos + 2].mLive &= ~LIVE_CPU_REG_X;
mIns.Insert(predXPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));
// Restart
restart = true;
predXPos = -1;
predYPos = -1;
changed = true;
}
else
predXPos = i;
}
else if (mIns[i + 0].ReferencesXReg())
predXPos = -1;
else if (mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
if (predYPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)) && ((mIns[predYPos + 2].mAddress + 1) & 0xff) == mIns[i + 2].mAddress)
{
// Remove add
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
// Insert INY
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
// Insert TAX
mIns[predYPos + 2].mLive &= ~LIVE_CPU_REG_Y;
mIns.Insert(predYPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));
// Restart
restart = true;
predXPos = -1;
predYPos = -1;
changed = true;
}
else if (predYPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)) && ((mIns[predYPos + 2].mAddress - 1) & 0xff) == mIns[i + 2].mAddress)
{
// Remove add
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
// Insert DEY
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
// Insert TAX
mIns[predYPos + 2].mLive &= ~LIVE_CPU_REG_Y;
mIns.Insert(predYPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));
// Restart
restart = true;
predXPos = -1;
predYPos = -1;
changed = true;
}
else
predYPos = i;
}
else if (mIns[i + 0].ReferencesYReg())
predYPos = -1;
}
} while (restart);
if (mTrueJump && mTrueJump->JoinXYCascade())
changed = true;
if (mFalseJump && mFalseJump->JoinXYCascade())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::GlobalLoadStoreForwarding(bool zpage, const NativeCodeInstruction & als, const NativeCodeInstruction & xls, const NativeCodeInstruction & yls)
{
bool changed = false;
if (!mVisited)
{
mNumEntered++;
if (mLoopHead)
{
mALSIns.mType = ASMIT_INV;
mXLSIns.mType = ASMIT_INV;
mYLSIns.mType = ASMIT_INV;
}
else if (mNumEntered == 1)
{
mALSIns = als;
mXLSIns = xls;
mYLSIns = yls;
}
else
{
if (als.mType == ASMIT_INV || (mALSIns.mType != ASMIT_INV && !mALSIns.SameEffectiveAddress(als))) mALSIns.mType = ASMIT_INV;
if (xls.mType == ASMIT_INV || (mXLSIns.mType != ASMIT_INV && !mXLSIns.SameEffectiveAddress(xls))) mXLSIns.mType = ASMIT_INV;
if (yls.mType == ASMIT_INV || (mYLSIns.mType != ASMIT_INV && !mYLSIns.SameEffectiveAddress(yls))) mYLSIns.mType = ASMIT_INV;
}
if (!mLoopHead && mNumEntered != mNumEntries)
return false;
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (mALSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
mIns[i + 1].SameEffectiveAddress(mALSIns) && mIns[i + 1].IsCommutative())
{
ins.mType = mIns[i + 1].mType;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mXLSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
mIns[i + 1].SameEffectiveAddress(mXLSIns) && mIns[i + 1].IsCommutative())
{
mIns[i + 1].CopyMode(ins);
ins.mType = ASMIT_TXA;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mYLSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
mIns[i + 1].SameEffectiveAddress(mYLSIns) && mIns[i + 1].IsCommutative())
{
mIns[i + 1].CopyMode(ins);
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
if (ins.mType == ASMIT_STA)
{
if (mALSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mALSIns) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
mALSIns = ins;
if (mXLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mXLSIns))
mXLSIns.mType = ASMIT_INV;
if (mYLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mYLSIns))
mYLSIns.mType = ASMIT_INV;
}
}
else if (ins.mType == ASMIT_LDA)
{
if (mALSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mALSIns) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_ORA;
ins.mMode = ASMIM_IMMEDIATE;
ins.mAddress = 0;
changed = true;
}
else if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
mALSIns = ins;
else
mALSIns.mType = ASMIT_INV;
}
else if (ins.mType == ASMIT_STX)
{
if (mXLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mXLSIns) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
mXLSIns = ins;
if (mALSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mALSIns))
mALSIns.mType = ASMIT_INV;
if (mYLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mYLSIns))
mYLSIns.mType = ASMIT_INV;
}
}
else if (ins.mType == ASMIT_LDX)
{
if (mXLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mXLSIns) && !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
ins.mAddress = 0;
changed = true;
}
else
{
if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
mXLSIns = ins;
else
mXLSIns.mType = ASMIT_INV;
if (mALSIns.mType != ASMIT_INV && mALSIns.mMode == ASMIM_ABSOLUTE_X)
mALSIns.mType = ASMIT_INV;
if (mYLSIns.mType != ASMIT_INV && mYLSIns.mMode == ASMIM_ABSOLUTE_X)
mYLSIns.mType = ASMIT_INV;
}
}
else if (ins.mType == ASMIT_STY)
{
if (mYLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mYLSIns) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X) && !(ins.mFlags & NCIF_VOLATILE))
mYLSIns = ins;
if (mALSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mALSIns))
mALSIns.mType = ASMIT_INV;
if (mXLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mXLSIns))
mXLSIns.mType = ASMIT_INV;
}
}
else if (ins.mType == ASMIT_LDY)
{
if (mYLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mYLSIns) && !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
ins.mAddress = 0;
changed = true;
}
else
{
if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X) && !(ins.mFlags & NCIF_VOLATILE))
mYLSIns = ins;
else
mYLSIns.mType = ASMIT_INV;
if (mALSIns.mType != ASMIT_INV && mALSIns.mMode == ASMIM_ABSOLUTE_Y)
mALSIns.mType = ASMIT_INV;
if (mXLSIns.mType != ASMIT_INV && mYLSIns.mMode == ASMIM_ABSOLUTE_Y)
mXLSIns.mType = ASMIT_INV;
}
}
else if (ins.mType == ASMIT_TAY)
{
mYLSIns = mALSIns;
}
else if (ins.mType == ASMIT_TAX)
{
mXLSIns = mALSIns;
}
else if (ins.mType == ASMIT_TYA)
{
mALSIns = mYLSIns;
}
else if (ins.mType == ASMIT_TXA)
{
mALSIns = mXLSIns;
}
else
{
if (ins.ChangesAccu())
mALSIns.mType = ASMIT_INV;
if (ins.ChangesXReg())
{
mXLSIns.mType = ASMIT_INV;
if (mALSIns.mMode == ASMIM_ABSOLUTE_X)
mALSIns.mType = ASMIT_INV;
if (mYLSIns.mMode == ASMIM_ABSOLUTE_X)
mYLSIns.mType = ASMIT_INV;
}
if (ins.ChangesYReg())
{
mYLSIns.mType = ASMIT_INV;
if (mALSIns.mMode == ASMIM_ABSOLUTE_Y)
mALSIns.mType = ASMIT_INV;
if (mXLSIns.mMode == ASMIM_ABSOLUTE_Y)
mXLSIns.mType = ASMIT_INV;
}
if (ins.ChangesAddress())
{
if (mALSIns.mType != ASMIT_INV && mALSIns.MayBeSameAddress(ins))
mALSIns.mType = ASMIT_INV;
if (mXLSIns.mType != ASMIT_INV && mXLSIns.MayBeSameAddress(ins))
mXLSIns.mType = ASMIT_INV;
if (mYLSIns.mType != ASMIT_INV && mYLSIns.MayBeSameAddress(ins))
mYLSIns.mType = ASMIT_INV;
}
}
}
if (mTrueJump && mTrueJump->GlobalLoadStoreForwarding(zpage, mALSIns, mXLSIns, mYLSIns))
changed = true;
if (mFalseJump && mFalseJump->GlobalLoadStoreForwarding(zpage, mALSIns, mXLSIns, mYLSIns))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::RegisterValueForwarding(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
FastNumberSet xreg(261), yreg(261), areg(261);
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mType == ASMIT_LDX)
{
if (xreg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
xreg.Clear();
xreg += mIns[i].mAddress;
}
}
else if (mIns[i].mType == ASMIT_STX)
{
if (xreg[mIns[i].mAddress])
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
xreg += mIns[i].mAddress;
yreg -= mIns[i].mAddress;
areg -= mIns[i].mAddress;
}
}
else if (mIns[i].mType == ASMIT_LDY)
{
if (yreg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
yreg.Clear();
yreg += mIns[i].mAddress;
}
}
else if (mIns[i].mType == ASMIT_STY)
{
if (yreg[mIns[i].mAddress])
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
yreg += mIns[i].mAddress;
xreg -= mIns[i].mAddress;
areg -= mIns[i].mAddress;
}
}
else if (mIns[i].mType == ASMIT_LDA)
{
if (areg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
areg.Clear();
areg += mIns[i].mAddress;
}
}
else if (mIns[i].mType == ASMIT_STA)
{
if (areg[mIns[i].mAddress])
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
areg += mIns[i].mAddress;
xreg -= mIns[i].mAddress;
yreg -= mIns[i].mAddress;
}
}
else if (mIns[i].ChangesAddress())
{
xreg -= mIns[i].mAddress;
yreg -= mIns[i].mAddress;
areg -= mIns[i].mAddress;
}
else if (mIns[i].ChangesAccu())
{
areg.Clear();
}
}
else if (mIns[i].mType == ASMIT_JSR)
{
xreg.Clear();
yreg.Clear();
areg.Clear();
}
else if (mIns[i].ChangesXReg())
{
xreg.Clear();
}
else if (mIns[i].ChangesYReg())
{
yreg.Clear();
}
else if (mIns[i].ChangesAccu())
{
areg.Clear();
}
}
if (mTrueJump && mTrueJump->RegisterValueForwarding())
changed = true;
if (mFalseJump && mFalseJump->RegisterValueForwarding())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ForwardZpXIndex(bool full)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int xreg = -1, xoffset = 0, xpred = 0;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (xreg == mIns[i].mAddress)
{
if (xoffset == 0)
{
for (int j = xpred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (xoffset == 1 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INX)
{
for (int j = xpred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (xoffset == 2 && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_INX)
{
for (int j = xpred; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
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;
changed = true;
}
else
xoffset = 0;
xpred = i;
}
else
{
xreg = mIns[i].mAddress;
xoffset = 0;
xpred = i;
}
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_TAX)
{
if (mIns[i + 1].mAddress == xreg && mIns[i + 2].mAddress == xoffset + 1 && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
for (int j = xpred; j < i + 3; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
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;
mIns[i + 3].mType = ASMIT_INX;
changed = true;
}
else
{
xreg = mIns[i + 1].mAddress;
xoffset = mIns[i + 2].mAddress;
xpred = i + 3;
i += 3;
}
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == xreg &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == xoffset + 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == xreg &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
for (int j = xpred; j < i + 3; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
mIns[i + 0].mType = ASMIT_INX;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_STX;
xoffset++;
xpred = i + 1;
changed = true;
}
else if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == xreg &&
mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == xreg && xoffset == 0)
{
for (int j = xpred; j < i + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX;
xoffset++;
xpred = i + 1;
changed = true;
}
else if (mIns[i].mType == ASMIT_INX)
{
xoffset = (xoffset + 1) & 255;
}
else if (mIns[i].mType == ASMIT_DEX)
{
xoffset = (xoffset - 1) & 255;
}
else if (mIns[i].ChangesXReg())
{
xreg = -1;
}
else if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
{
xreg = -1;
}
}
CheckLive();
if (mTrueJump && mTrueJump->ForwardZpXIndex(full))
changed = true;
if (mFalseJump && mFalseJump->ForwardZpXIndex(full))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ReplaceXRegWithYReg(int start, int end)
{
bool changed = false;
//CheckLive();
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.ReplaceXRegWithYReg())
changed = true;
}
//CheckLive();
return changed;
}
bool NativeCodeBasicBlock::CanReplaceYRegWithXReg(int start, int end)
{
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if ((ins.mLive & LIVE_CPU_REG_X) && (ins.mLive & LIVE_CPU_REG_Y))
return false;
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ABSOLUTE_X)
return false;
if (ins.mMode == ASMIM_INDIRECT_Y)
return false;
if (ins.mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_X))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CanReplaceXRegWithYReg(int start, int end)
{
for (int i = start; i < end; i++)
{
NativeCodeInstruction& ins(mIns[i]);
if ((ins.mLive & LIVE_CPU_REG_X) && (ins.mLive & LIVE_CPU_REG_Y))
return false;
if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ABSOLUTE_Y)
return false;
if (ins.mMode == ASMIM_INDIRECT_X)
return false;
if (ins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CanGlobalSwapXY(void)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_INDIRECT_Y)
return false;
if (ins.mMode == ASMIM_INDIRECT_X)
return false;
if (ins.mMode == ASMIM_ABSOLUTE_X && (ins.mType != ASMIT_LDY && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y)))
return false;
if (ins.mType == ASMIT_JSR && (ins.mFlags & (NCIF_USE_CPU_REG_X | NCIF_USE_ZP_32_X)))
return false;
}
if (mTrueJump && !mTrueJump->CanGlobalSwapXY())
return false;
if (mFalseJump && !mFalseJump->CanGlobalSwapXY())
return false;
}
return true;
}
bool NativeCodeBasicBlock::IsSimpleSubExpression(int at, NativeSimpleSubExpression& ex)
{
ex.mIndex = at;
if (at + 2 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STA && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
(mIns[at + 1].mMode == ASMIM_IMMEDIATE || mIns[at + 1].mMode == ASMIM_ZERO_PAGE) && (mIns[at + 1].mType == ASMIT_AND || mIns[at + 1].mType == ASMIT_ORA || mIns[at + 1].mType == ASMIT_EOR))
{
ex.mType = mIns[at + 1].mType;
ex.mValue = mIns[at + 1].mAddress;
ex.mMode = mIns[at + 1].mMode;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mMode = mIns[at + 2].mMode;
ex.mSrc = &(mIns[at + 0]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 1].mType == ASMIT_LDA && (mIns[at + 1].mMode == ASMIM_ZERO_PAGE || mIns[at + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
(mIns[at + 0].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 0].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mMode = mIns[at + 2].mMode;
ex.mSrc = &(mIns[at + 1]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_STA && mIns[at + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mMode = mIns[at + 2].mMode;
ex.mSrc = &(mIns[at + 0]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 2 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDX && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STX && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 1].mType == ASMIT_INX)
{
ex.mType = ASMIT_ADC;
ex.mValue = 1;
ex.mMode = ASMIM_IMMEDIATE;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at + 2 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDY && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STY && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 1].mType == ASMIT_INY)
{
ex.mType = ASMIT_ADC;
ex.mValue = 1;
ex.mMode = ASMIM_IMMEDIATE;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE || mIns[at + 0].mMode == ASMIM_ABSOLUTE_X) &&
mIns[at + 3].mType == ASMIT_TAY &&
(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mMode = mIns[at + 2].mMode;
ex.mSrc = &(mIns[at + 0]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
return false;
}
int NativeSimpleSubExpressions::FindCommon(const NativeSimpleSubExpression& ex) const
{
if (ex.mSrc->mType == ASMIT_LDA || ex.mSrc->mType == ASMIT_LDX || ex.mSrc->mType == ASMIT_LDY)
{
for (int i = 0; i < mExps.Size(); i++)
{
if (mExps[i].mType == ex.mType && mExps[i].mMode == ex.mMode && mExps[i].mValue == ex.mValue && ex.mSrc->SameEffectiveAddress(*(mExps[i].mSrc)))
{
if (mExps[i].mDst->mMode == ASMIM_IMPLIED)
{
if (mExps[i].mDst->mType == ex.mDst->mType)
return i;
}
else
return i;
}
}
}
return -1;
}
bool NativeSimpleSubExpression::MayBeChangedBy(const NativeCodeInstruction& ins)
{
if (ins.ChangesAddress())
{
if (mSrc->MayBeChangedOnAddress(ins))
return true;
if (&ins != mDst && mDst->MayBeChangedOnAddress(ins))
return true;
if (mMode == ASMIM_ZERO_PAGE && ins.ChangesZeroPage(mValue))
return true;
}
if (ins.ChangesYReg())
{
if (&ins != mDst && mDst->mType == ASMIT_TAY)
return true;
if (mSrc->mMode == ASMIM_ABSOLUTE_Y)
return true;
}
if (ins.ChangesXReg())
{
if (&ins != mDst && mDst->mType == ASMIT_TAX)
return true;
if (mSrc->mMode == ASMIM_ABSOLUTE_X)
return true;
}
return false;
}
void NativeSimpleSubExpressions::Filter(const NativeCodeInstruction& ins)
{
if (ins.mType == ASMIT_JSR)
mExps.SetSize(0);
else
{
int i = 0;
while (i < mExps.Size())
{
if (mExps[i].MayBeChangedBy(ins))
mExps.Remove(i);
else
i++;
}
}
}
bool NativeCodeBasicBlock::PropagateCommonSubExpression(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
NativeSimpleSubExpressions exps;
for (int i = 0; i < mIns.Size(); i++)
{
NativeSimpleSubExpression ex;
if (IsSimpleSubExpression(i, ex))
{
int j = exps.FindCommon(ex);
if (j >= 0)
{
if (ex.mDst->mType == ASMIT_TAY)
{
for (int k = exps.mExps[j].mIndex; k < i + 2; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
ex.mOp->mLive |= LIVE_CPU_REG_Y;
ex.mDst->mType = ASMIT_NOP;
}
else if (ex.mDst->mType == ASMIT_TAX)
{
for (int k = exps.mExps[j].mIndex; k < i + 2; k++)
mIns[k].mLive |= LIVE_CPU_REG_X;
ex.mOp->mLive |= LIVE_CPU_REG_Y;
ex.mDst->mType = ASMIT_NOP;
}
else
{
*ex.mSrc = NativeCodeInstruction(ex.mDst->mIns, ex.mSrc->mType, *(exps.mExps[j].mDst));
ex.mSrc = exps.mExps[j].mSrc;
ex.mOp->mType = ASMIT_NOP;
ex.mOp->mMode = ASMIM_IMPLIED;
}
changed = true;
}
exps.mExps.Push(ex);
}
else
exps.Filter(mIns[i]);
}
if (mTrueJump && mTrueJump->PropagateCommonSubExpression())
changed = true;
if (mFalseJump && mFalseJump->PropagateCommonSubExpression())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::LocalSwapXY(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int pre = -1;
if (mEntryRequiredRegs[CPU_REG_X] || mEntryRequiredRegs[CPU_REG_Y])
pre = -2;
for (int i = 0; i < mIns.Size(); i++)
{
uint32 live = mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y);
if (live)
{
if (pre == -1)
pre = i;
}
else if (!live)
{
if (pre >= 0)
{
int k = pre;
while (k <= i && mIns[k].CanSwapXYReg())
k++;
if (k > i)
{
for (int k = pre; k <= i; k++)
{
if (mIns[k].SwapXYReg())
changed = true;
}
}
}
pre = -1;
}
}
if (mTrueJump && mTrueJump->LocalSwapXY())
changed = true;
if (mFalseJump && mFalseJump->LocalSwapXY())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::GlobalSwapXY(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ABSOLUTE_X)
{
ins.mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
else if (ins.mMode == ASMIM_ABSOLUTE_Y)
{
ins.mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
switch (ins.mType)
{
case ASMIT_LDX:
ins.mType = ASMIT_LDY;
changed = true;
break;
case ASMIT_STX:
ins.mType = ASMIT_STY;
changed = true;
break;
case ASMIT_CPX:
ins.mType = ASMIT_CPY;
changed = true;
break;
case ASMIT_INX:
ins.mType = ASMIT_INY;
changed = true;
break;
case ASMIT_DEX:
ins.mType = ASMIT_DEY;
changed = true;
break;
case ASMIT_TAX:
ins.mType = ASMIT_TAY;
changed = true;
break;
case ASMIT_TXA:
ins.mType = ASMIT_TYA;
changed = true;
break;
case ASMIT_LDY:
ins.mType = ASMIT_LDX;
changed = true;
break;
case ASMIT_STY:
ins.mType = ASMIT_STX;
changed = true;
break;
case ASMIT_CPY:
ins.mType = ASMIT_CPX;
changed = true;
break;
case ASMIT_INY:
ins.mType = ASMIT_INX;
changed = true;
break;
case ASMIT_DEY:
ins.mType = ASMIT_DEX;
changed = true;
break;
case ASMIT_TAY:
ins.mType = ASMIT_TAX;
changed = true;
break;
case ASMIT_TYA:
ins.mType = ASMIT_TXA;
changed = true;
break;
}
}
if (mTrueJump && !mTrueJump->GlobalSwapXY())
changed = true;
if (mFalseJump && !mFalseJump->GlobalSwapXY())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::AlternateXXUsage(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 3 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X &&
!(mIns[i + 3].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y &&
!(mIns[i + 3].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
}
if (mTrueJump && mTrueJump->AlternateXXUsage())
changed = true;
if (mFalseJump && mFalseJump->AlternateXXUsage())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::UntangleXYUsage(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int xins = -1, yins = -1;
for (int i = 0; i + 1 < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
NativeCodeInstruction& nins(mIns[i + 1]);
if (ins.mType == ASMIT_LDX)
{
if (yins >= 0 && mIns[yins].SameEffectiveAddress(ins) && nins.mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(nins.mType, ASMIM_ABSOLUTE_Y))
{
mIns.Insert(i, NativeCodeInstruction(nins.mIns, nins.mType, ASMIM_ABSOLUTE_Y, nins.mAddress, nins.mLinkerObject, nins.mFlags));
mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Remove(i + 2);
for (int j = yins; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
changed = true;
}
else
xins = i;
}
else if (ins.mType == ASMIT_LDY)
{
if (xins >= 0 && mIns[xins].SameEffectiveAddress(ins) && nins.mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(nins.mType, ASMIM_ABSOLUTE_X))
{
mIns.Insert(i, NativeCodeInstruction(nins.mIns, nins.mType, ASMIM_ABSOLUTE_X, nins.mAddress, nins.mLinkerObject, nins.mFlags));
mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Remove(i + 2);
for (int j = xins; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
changed = true;
}
else
yins = i;
}
else
{
if (xins >= 0 && (mIns[xins].MayBeChangedOnAddress(ins) || ins.ChangesXReg()))
xins = -1;
if (yins >= 0 && (mIns[yins].MayBeChangedOnAddress(ins) || ins.ChangesYReg()))
yins = -1;
}
}
if (mTrueJump && mTrueJump->UntangleXYUsage())
changed = true;
if (mFalseJump && mFalseJump->UntangleXYUsage())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeXYPairUsage(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_X] && !mExitRequiredRegs[CPU_REG_Y])
{
int yreg = -1, xreg = -1, areg = -1;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction & ins(mIns[i]);
if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg ||
ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
int j = i;
while (j + 1 < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && mIns[j + 1].CanSwapXYReg())
j++;
if (j + 1 == mIns.Size() || !(mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
{
bool tox = ins.mType == ASMIT_LDY, toy = ins.mType == ASMIT_LDX;
for (int k = i; k <= j; k++)
{
if (mIns[k].ChangesXReg())
tox = false;
if (mIns[k].ChangesYReg())
toy = false;
if (tox)
mIns[k].ReplaceYRegWithXReg();
else if (toy)
mIns[k].ReplaceXRegWithYReg();
else
mIns[k].SwapXYReg();
}
CheckLive();
changed = true;
}
}
if (ins.mType == ASMIT_LDY)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
yreg = ins.mAddress;
else
yreg = -1;
}
else if (ins.mType == ASMIT_LDX)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
xreg = ins.mAddress;
else
xreg = -1;
}
else if (ins.mType == ASMIT_LDA)
{
if (ins.mMode == ASMIM_ZERO_PAGE)
areg = ins.mAddress;
else
areg = -1;
}
else if (ins.mType == ASMIT_TAX)
xreg = areg;
else if (ins.mType == ASMIT_TAY)
yreg = areg;
else if (ins.mType == ASMIT_JSR)
xreg = yreg = areg = false;
else if (ins.ChangesAccu())
areg = -1;
else if (ins.ChangesXReg())
xreg = -1;
else if (ins.ChangesYReg())
yreg = -1;
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
{
if (ins.mAddress == areg)
areg = -1;
if (ins.mAddress == xreg)
xreg = -1;
if (ins.mAddress == yreg)
yreg = -1;
}
}
}
CheckLive();
if (mTrueJump && mTrueJump->OptimizeXYPairUsage())
changed = true;
if (mFalseJump && mFalseJump->OptimizeXYPairUsage())
changed = true;
}
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;
bool vol = mIns[at + 1].mFlags & NCIF_VOLATILE;
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;
else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
return false;
else if (vol && (mIns[i].mFlags & NCIF_VOLATILE))
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;
bool vol = mIns[at + 1].mFlags & NCIF_VOLATILE;
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;
else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
return false;
else if (vol && (mIns[i].mFlags & NCIF_VOLATILE))
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;
else if (mIns[at].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at].mAddress) || mIns[i].ChangesZeroPage(mIns[at].mAddress + 1)))
return false;
else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
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)
{
used = 0;
changed = 0;
flags = 0;
for (int i = start; i < end; i++)
{
flags |= mIns[i].mFlags;
if (mIns[i].RequiresCarry() && !(changed & LIVE_CPU_REG_C))
used |= LIVE_CPU_REG_C;
if (mIns[i].RequiresXReg() && !(changed & LIVE_CPU_REG_X))
used |= LIVE_CPU_REG_X;
if (mIns[i].RequiresYReg() && !(changed & LIVE_CPU_REG_Y))
used |= LIVE_CPU_REG_Y;
if (mIns[i].ChangesCarry())
changed |= LIVE_CPU_REG_C;
if (mIns[i].ChangesXReg())
changed |= LIVE_CPU_REG_X;
if (mIns[i].ChangesYReg())
changed |= LIVE_CPU_REG_Y;
}
}
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;
uint32 flagsFront, flagsBack;
BuildUseChangeSets(start, mid, usedFront, changedFront, flagsFront);
BuildUseChangeSets(mid, end, usedBack, changedBack, flagsBack);
if (flagsFront & flagsBack & NCIF_VOLATILE)
return false;
if (usedFront & changedBack)
return false;
if (usedBack & changedFront)
return false;
if (mIns[end - 1].mLive & changedFront)
return false;
return true;
}
bool NativeCodeBasicBlock::MoveAccuTrainDown(int end, int start)
{
int i = end;
while (i > 0)
{
i--;
for (int j = end + 1; j < start; j++)
{
if (mIns[j].MayBeChangedOnAddress(mIns[i], true) || mIns[i].MayBeChangedOnAddress(mIns[j], true))
return false;
}
if (mIns[i].mType == ASMIT_LDA)
{
if (mIns[i].RequiresCarry() || (mIns[i].mLive & LIVE_CPU_REG_C))
{
if (i > 0 && (mIns[i - 1].mType == ASMIT_CLC || mIns[i - 1].mType == ASMIT_SEC))
i--;
}
if (!CanExchangeSegments(i, end + 1, start))
return false;
int live = mIns[i].mLive;
if (mIns[i].RequiresXReg())
live |= LIVE_CPU_REG_X;
if (mIns[i].RequiresYReg())
live |= LIVE_CPU_REG_Y;
for (int j = end + 1; j < start; j++)
mIns[j].mLive |= live;
for (int j = end; j >= i; j--)
{
NativeCodeInstruction ins = mIns[j];
ins.mLive |= mIns[start - 1].mLive;
mIns.Insert(start, ins);
}
mIns.Remove(i, end - i + 1);
return true;
}
if (mIns[i].mType == ASMIT_JSR)
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveAccuTrainsDown(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int apos[256];
for(int i=0; i<256; i++)
apos[i] = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
apos[mIns[i].mAddress] = i;
}
else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && apos[mIns[i + 1].mAddress] >= 0 && HasAsmInstructionMode(mIns[i + 1].mType, mIns[i].mMode))
{
int addr = mIns[i + 1].mAddress;
if (MoveAccuTrainDown(apos[addr], i))
{
if (mIns[i].RequiresXReg())
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].RequiresYReg())
mIns[i].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].CopyMode(mIns[i]);
mIns[i] = NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr);
changed = true;
for (int j = 0; j < 256; j++)
apos[j] = -1;
}
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && apos[mIns[i].mAddress] >= 0)
{
int addr = mIns[i].mAddress;
if (MoveAccuTrainDown(apos[addr], i))
{
if (mIns[i].RequiresXReg())
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].RequiresYReg())
mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
for (int j = 0; j < 256; j++)
apos[j] = -1;
}
}
else if (i + 2 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].IsCommutative() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && apos[mIns[i + 2].mAddress] >= 0 && HasAsmInstructionMode(mIns[i + 2].mType, mIns[i].mMode))
{
int addr = mIns[i + 2].mAddress;
if (MoveAccuTrainDown(apos[addr], i))
{
if (mIns[i].RequiresXReg())
{
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
}
if (mIns[i].RequiresYReg())
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
}
mIns[i + 2].CopyMode(mIns[i]);
mIns[i] = NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr);
changed = true;
for (int j = 0; j < 256; j++)
apos[j] = -1;
}
}
else if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
apos[mIns[i].mAddress] = -1;
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
apos[mIns[i].mAddress] = -1;
apos[mIns[i].mAddress + 1] = -1;
}
else if (mIns[i].mType == ASMIT_JSR)
{
for (int j = 0; j < 256; j++)
{
if (apos[j] >= 0 && mIns[i].ReferencesZeroPage(j))
apos[j] = -1;
}
}
}
CheckLive();
if (mTrueJump && mTrueJump->MoveAccuTrainsDown())
changed = true;
if (mFalseJump && mFalseJump->MoveAccuTrainsDown())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::MoveAccuTrainUp(int at, int end)
{
CheckLive();
bool needXY = (mIns[end - 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) != 0;
int addr = mIns[at].mAddress;
if (mIns[at].mLive & LIVE_CPU_REG_C)
at--;
int i = at;
while (i > 0)
{
i--;
if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
if (mIns[i].mType == ASMIT_LDA)
i++;
if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
return false;
int live = mIns[i].mLive;
for (int j = i; j < at; j++)
mIns[j].mLive |= mIns[end - 1].mLive;
for (int j = at; j < end; j++)
{
NativeCodeInstruction ins(mIns[j]);
ins.mLive |= live;
mIns.Remove(j);
i++;
mIns.Insert(i, ins);
}
CheckLive();
return true;
}
if (mIns[i].mType == ASMIT_JSR)
{
if (needXY)
return false;
}
for (int j = at; j < end; j++)
{
if (mIns[j].RequiresXReg() && mIns[i].ChangesXReg() || mIns[j].ChangesXReg() && mIns[i].RequiresXReg())
return false;
if (mIns[j].RequiresYReg() && mIns[i].ChangesYReg() || mIns[j].ChangesYReg() && mIns[i].RequiresYReg())
return false;
if (mIns[j].MayBeChangedOnAddress(mIns[i], true) || mIns[i].MayBeChangedOnAddress(mIns[j], true))
return false;
if (mIns[i].mType == ASMIT_JSR && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesAddress() && mIns[i].ReferencesZeroPage(mIns[j].mAddress))
return false;
}
}
return false;
}
bool NativeCodeBasicBlock::MoveAccuTrainsUp(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
FastNumberSet wzero(256);
int i = 0;
while (i < mIns.Size())
{
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
wzero -= mIns[i].mAddress;
else
wzero += mIns[i].mAddress;
i++;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && wzero[mIns[i].mAddress] &&
(!(mIns[i].mLive & LIVE_CPU_REG_C) || i > 0 && (mIns[i-1].mType == ASMIT_CLC || mIns[i-1].mType == ASMIT_SEC)))
{
int j = i;
while (j < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && mIns[j].mType != ASMIT_JSR)
j++;
if (j < mIns.Size() && mIns[j].mType != ASMIT_JSR)
{
j++;
if (MoveAccuTrainUp(i, j))
{
i = j + 1;
changed = true;
}
else
i++;
}
else
i++;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
wzero += mIns[i].mAddress;
i++;
}
else if (mIns[i].mType == ASMIT_JSR)
{
for (int j = 0; j < 256; j++)
{
if (wzero[j] && mIns[i].ChangesZeroPage(j))
wzero -= j;
}
#if 0
for (int j = 0; j < 4; j++)
{
wzero -= BC_REG_ACCU + j;
wzero -= BC_REG_WORK + j;
}
if (!(mIns[i].mFlags & NCIF_RUNTIME) || (mIns[i].mFlags & NCIF_FEXEC))
{
wzero -= BC_REG_ADDR;
wzero -= BC_REG_ADDR + 1;
}
// wzero.Clear();
#endif
i++;
}
else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
{
wzero -= mIns[i].mAddress;
i++;
}
else
i++;
}
CheckLive();
if (mTrueJump && mTrueJump->MoveAccuTrainsUp())
changed = true;
if (mFalseJump && mFalseJump->MoveAccuTrainsUp())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::AlternateXYUsage(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int start = 0;
CheckLive();
int predYPos = -1, predXPos = -1, currYPos = -1, currXPos = -1, predYEnd = -1, predXEnd = -1;
for (int start = 0; start < mIns.Size(); start++)
{
const NativeCodeInstruction& ins(mIns[start]);
if (ins.mType == ASMIT_LDY)
{
if ((ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE) && predYPos >= 0 && ins.SameEffectiveAddress(mIns[predYPos]) && !(ins.mFlags & NCIF_VOLATILE))
{
if (CanReplaceYRegWithXReg(predYEnd, start))
{
if (ReplaceYRegWithXReg(predYEnd, start))
changed = true;
}
}
else
{
if (currYPos >= 0)
{
predYPos = currYPos;
predYEnd = start;
}
if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE)
currYPos = start;
else
currYPos = -1;
}
}
else if (ins.mType == ASMIT_LDX)
{
if ((ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE) && predXPos >= 0 && ins.SameEffectiveAddress(mIns[predXPos]) && !(ins.mFlags & NCIF_VOLATILE))
{
if (CanReplaceXRegWithYReg(predXEnd, start))
{
if (ReplaceXRegWithYReg(predXEnd, start))
changed = true;
}
}
else
{
if (currXPos >= 0)
{
predXPos = currXPos;
predXEnd = start;
}
if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE)
currXPos = start;
else
currXPos = -1;
}
}
else if (ins.mType == ASMIT_JSR)
{
currYPos = predYPos = -1;
currXPos = predXPos = -1;
}
else if (ins.ChangesXReg())
{
currXPos = -1;
}
else if (ins.ChangesYReg())
{
currYPos = -1;
}
else
{
if (predYPos >= 0 && mIns[predYPos].MayBeChangedOnAddress(ins))
predYPos = -1;
if (predXPos >= 0 && mIns[predXPos].MayBeChangedOnAddress(ins))
predXPos = -1;
if (currYPos >= 0 && mIns[currYPos].MayBeChangedOnAddress(ins))
currYPos = -1;
if (currXPos >= 0 && mIns[currXPos].MayBeChangedOnAddress(ins))
currYPos = -1;
}
}
CheckLive();
if (mTrueJump && mTrueJump->AlternateXYUsage())
changed = true;
if (mFalseJump && mFalseJump->AlternateXYUsage())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::SimplifyLoopEnd(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && !mFalseJump && mTrueJump->mLoopHead)
{
if (mTrueJump->mIns.Size() == 1 && mTrueJump->mFalseJump && mTrueJump->mTrueJump != mTrueJump)
{
mIns.Push(mTrueJump->mIns[0]);
mBranch = mTrueJump->mBranch;
mTrueJump->RemEntryBlock(this);
mFalseJump = mTrueJump->mFalseJump;
mTrueJump = mTrueJump->mTrueJump;
mTrueJump->AddEntryBlock(this);
mFalseJump->AddEntryBlock(this);
changed = true;
}
}
if (mTrueJump && mTrueJump->SimplifyLoopEnd(proc))
changed = true;
if (mFalseJump && mFalseJump->SimplifyLoopEnd(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CanHoistStore(const NativeCodeInstruction& ains) const
{
for (int i = 0; i < mIns.Size(); i++)
{
if (ains.MayBeSameAddress(mIns[i]))
return false;
if (ains.mType == ASMIT_STY && mIns[i].ChangesYReg() ||
ains.mType == ASMIT_STX && mIns[i].ChangesXReg())
return false;
}
return true;
}
bool NativeCodeBasicBlock::CanBytepassLoad(const NativeCodeInstruction& ains, int from) const
{
for (int i = from; i < mIns.Size(); i++)
{
if (ains.MayBeChangedOnAddress(mIns[i]))
return false;
if (ains.mType == ASMIT_LDY && mIns[i].ReferencesYReg() ||
ains.mType == ASMIT_LDX && mIns[i].ReferencesXReg())
return false;
}
return true;
}
bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{
if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 && mTrueJump->mTrueJump->mNumEntries == 2)
{
NativeCodeBasicBlock* mblock = mTrueJump->mTrueJump;
if (mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mTrueJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mType == ASMIT_AND && !(mTrueJump->mIns[0].mAddress & ~mFalseJump->mIns[0].mAddress))
{
mTrueJump->mTrueJump->mIns.Insert(0, mFalseJump->mIns[0]);
mFalseJump->mIns.SetSize(0, true);
changed = true;
}
else if (mTrueJump->mIns[0].mType == ASMIT_AND && mFalseJump->mIns[0].mType == ASMIT_LDA && !(mFalseJump->mIns[0].mAddress & ~mTrueJump->mIns[0].mAddress))
{
mTrueJump->mTrueJump->mIns.Insert(0, mTrueJump->mIns[0]);
mTrueJump->mIns.SetSize(0, true);
changed = true;
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && mTrueJump->mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
{
int sz = mIns.Size() - 1;
while (sz >= 0 && !mIns[sz].ReferencesYReg())
sz--;
if (sz >= 0 && mIns[sz].mType == ASMIT_LDY && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
{
if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz]))
{
if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
{
mExitRequiredRegs += mIns[sz].mAddress;
mTrueJump->mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
mTrueJump->mExitRequiredRegs += mIns[sz].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[sz].mAddress;
mFalseJump->mExitRequiredRegs += mIns[sz].mAddress;
}
mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDY, mIns[sz]));
changed = true;
}
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mTrueJump->mEntryRequiredRegs[CPU_REG_X])
{
int sz = mIns.Size() - 1;
while (sz >= 0 && !mIns[sz].ReferencesXReg())
sz--;
if (sz >= 0 && mIns[sz].mType == ASMIT_LDX && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
{
if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz]))
{
if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
{
mExitRequiredRegs += mIns[sz].mAddress;
mTrueJump->mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
mTrueJump->mExitRequiredRegs += mIns[sz].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[sz].mAddress;
mFalseJump->mExitRequiredRegs += mIns[sz].mAddress;
}
mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDX, mIns[sz]));
changed = true;
}
}
}
if (mblock->mIns.Size() > 0 && mblock->mIns[0].mType == ASMIT_STX && (mblock->mIns[0].mMode == ASMIM_ZERO_PAGE || mblock->mIns[0].mMode == ASMIM_ABSOLUTE) && !(mblock->mIns[0].mLive & LIVE_CPU_REG_X) &&
mTrueJump->CanHoistStore(mblock->mIns[0]) && mFalseJump->CanHoistStore(mblock->mIns[0]))
{
if (mblock->mIns[0].mMode == ASMIM_ZERO_PAGE)
{
mExitRequiredRegs += mblock->mIns[0].mAddress;
mTrueJump->mEntryRequiredRegs += mblock->mIns[0].mAddress;
mTrueJump->mExitRequiredRegs += mblock->mIns[0].mAddress;
mFalseJump->mEntryRequiredRegs += mblock->mIns[0].mAddress;
mFalseJump->mExitRequiredRegs += mblock->mIns[0].mAddress;
mblock->mEntryRequiredRegs += mblock->mIns[0].mAddress;
}
mIns.Push(mblock->mIns[0]);
mblock->mIns.Remove(0);
mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
changed = true;
}
}
#if 1
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && mTrueJump->mNumEntries == 1)
{
int sz = mIns.Size() - 1;
while (sz >= 0 && !mIns[sz].ReferencesYReg())
sz--;
if (sz >= 0 && mIns[sz].mType == ASMIT_LDY && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
{
int i = sz + 1;
while (i < mIns.Size() && !mIns[sz].MayBeChangedOnAddress(mIns[i]))
i++;
if (i == mIns.Size())
{
mIns[sz].mLive |= mIns[mIns.Size() - 1].mLive;
if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
{
mExitRequiredRegs += mIns[sz].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
}
mTrueJump->mIns.Insert(0, mIns[sz]);
mIns.Remove(sz);
changed = true;
}
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && mTrueJump->mNumEntries == 1)
{
int sz = mIns.Size() - 1;
while (sz >= 0 && !mIns[sz].ReferencesXReg())
sz--;
if (sz >= 0 && mIns[sz].mType == ASMIT_LDX && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
{
int i = sz + 1;
while (i < mIns.Size() && !mIns[sz].MayBeChangedOnAddress(mIns[i]))
i++;
if (i == mIns.Size())
{
mIns[sz].mLive |= mIns[mIns.Size() - 1].mLive;
if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
{
mExitRequiredRegs += mIns[sz].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
}
mTrueJump->mIns.Insert(0, mIns[sz]);
mIns.Remove(sz);
changed = true;
}
}
}
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
{
NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr;
if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)
{
cblock = mTrueJump;
eblock = mFalseJump;
}
if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump && mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 2)
{
cblock = mFalseJump;
eblock = mTrueJump;
}
if (cblock && cblock->mIns.Size() > 0 && eblock->mIns.Size() > 0)
{
int cs = cblock->mIns.Size();
if (cblock->mIns[0].mType == ASMIT_LDA && eblock->mIns[0].mType == ASMIT_LDA && cblock->mIns[cs - 1].mType == ASMIT_STA &&
cblock->mIns[0].SameEffectiveAddress(eblock->mIns[0]) &&
cblock->mIns[0].SameEffectiveAddress(cblock->mIns[cs - 1]))
{
cblock->mIns[cs - 1].mLive |= LIVE_CPU_REG_A;
eblock->mIns[0].mLive |= cblock->mIns[0].mLive;
eblock->mIns[0].mLive |= LIVE_CPU_REG_C;
mIns.Push(eblock->mIns[0]);
eblock->mIns.Remove(0);
cblock->mIns.Remove(0);
eblock->mEntryRequiredRegs += CPU_REG_A;
cblock->mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
cblock->mExitRequiredRegs += CPU_REG_A;
changed = true;
}
}
}
}
#endif
if (mTrueJump && mTrueJump->SimplifyDiamond(proc))
changed = true;
if (mFalseJump && mFalseJump->SimplifyDiamond(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Split16BitLoopCount(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
#if 1
int sz = mIns.Size();
if (sz >= 8 && mBranch == ASMIT_BNE)
{
if (mIns[sz - 8].mType == ASMIT_CLC &&
mIns[sz - 7].mType == ASMIT_LDA &&
mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0xff &&
mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 7]) &&
mIns[sz - 4].mType == ASMIT_LDA &&
mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0xff &&
mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 7]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 2].mMode) &&
!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
changed = true;
NativeCodeBasicBlock* pblock = nullptr;
if (mEntryBlocks.Size() == 2)
{
if (mEntryBlocks[0] == this)
pblock = mEntryBlocks[1];
else if (mEntryBlocks[1] == this)
pblock = mEntryBlocks[0];
}
bool preinc = false;
if (pblock && !pblock->mFalseJump && mTrueJump == this && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE && !mFalseJump->mEntryRequiredRegs[mIns[sz - 7].mAddress] && !mEntryRequiredRegs[CPU_REG_A])
{
int i = 0;
while (i < sz - 8 && !mIns[i].ReferencesZeroPage(mIns[sz - 7].mAddress))
i++;
if (i == sz - 8)
preinc = true;
}
NativeCodeInstruction ilow(mIns[sz - 7]);
NativeCodeInstruction ihigh(mIns[sz - 4]);
mIns.SetSize(sz - 8);
if (preinc)
{
NativeCodeBasicBlock* dblock = proc->AllocateBlock();
NativeCodeBasicBlock* zblock = proc->AllocateBlock();
zblock->mTrueJump = this;
dblock->mTrueJump = this;
dblock->mFalseJump = mFalseJump;
dblock->mBranch = ASMIT_BNE;
mFalseJump = dblock;
pblock->mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_LDA, ilow));
pblock->mBranch = ASMIT_BEQ;
pblock->mFalseJump = zblock;
zblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_INC, ihigh));
mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_DEC, ilow));
dblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_DEC, ihigh));
}
else
{
NativeCodeBasicBlock* hblock = proc->AllocateBlock();
NativeCodeBasicBlock* dblock = proc->AllocateBlock();
NativeCodeBasicBlock* zblock = proc->AllocateBlock();
zblock->mTrueJump = mTrueJump;
zblock->mFalseJump = mFalseJump;
zblock->mBranch = ASMIT_BNE;
dblock->mTrueJump = mTrueJump;
dblock->mFalseJump = zblock;
dblock->mBranch = ASMIT_BNE;
hblock->mTrueJump = dblock;
hblock->mBranch = ASMIT_JMP;
mTrueJump = dblock;
mFalseJump = hblock;
mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_LDA, ilow));
hblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_DEC, ihigh));
dblock->mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_DEC, ilow));
zblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_LDA, ihigh));
}
}
}
#endif
if (mTrueJump && mTrueJump->Split16BitLoopCount(proc))
changed = true;
if (mFalseJump && mFalseJump->Split16BitLoopCount(proc))
changed = true;
}
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;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mNumEntries == 2)
{
NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr, * bblock = nullptr;
if (mEntryBlocks[0]->mFalseJump)
{
eblock = mEntryBlocks[0];
bblock = mEntryBlocks[1];
}
else if (mEntryBlocks[1]->mFalseJump)
{
eblock = mEntryBlocks[1];
bblock = mEntryBlocks[0];
}
if (eblock && eblock != this && !bblock->mFalseJump)
{
if (eblock->mFalseJump == this)
cblock = eblock->mTrueJump;
else
cblock = eblock->mFalseJump;
int i = eblock->mIns.Size() - 1;
while (i >= 0 && !eblock->mIns[i].ChangesXReg())
i--;
if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDX && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
{
int addr = eblock->mIns[i].mAddress;
int j = 0;
while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ChangesZeroPage(addr))
j++;
if (j < mIns.Size())
{
if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
{
bblock->mIns.Push(mIns[j]);
bblock->mExitRequiredRegs += addr;
mEntryRequiredRegs += addr;
mIns.Remove(j);
changed = true;
}
}
}
i = eblock->mIns.Size() - 1;
while (i >= 0 && !eblock->mIns[i].ChangesYReg())
i--;
if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDY && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
{
int addr = eblock->mIns[i].mAddress;
int j = 0;
while (j < mIns.Size() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesZeroPage(addr))
j++;
if (j < mIns.Size())
{
if (mIns[j].mType == ASMIT_STY && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
{
bblock->mIns.Push(mIns[j]);
bblock->mExitRequiredRegs += addr;
mEntryRequiredRegs += addr;
mIns.Remove(j);
changed = true;
}
}
}
i = eblock->mIns.Size() - 1;
while (i >= 0 && !eblock->mIns[i].ChangesAccu())
i--;
if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDA && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
{
int addr = eblock->mIns[i].mAddress;
int j = 0;
while (j < mIns.Size() && !mIns[j].ReferencesAccu() && !mIns[j].ChangesZeroPage(addr))
j++;
if (j < mIns.Size())
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
{
bblock->mIns.Push(mIns[j]);
bblock->mExitRequiredRegs += addr;
mEntryRequiredRegs += addr;
mIns.Remove(j);
changed = true;
}
}
}
#if 0
int esz = eblock->mIns.Size();
if (mIns.Size() > 0 && esz >= 2 &&
mIns[0].mType == ASMIT_LDX &&
eblock->mIns[esz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(eblock->mIns[esz - 2]) &&
eblock->mIns[esz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, eblock->mIns[esz - 1].mMode) &&
!(eblock->mIns[esz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
{
printf("Doopsie\n");
bblock->mIns.Push(mIns[0]);
bblock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mIns.Remove(0);
eblock->mExitRequiredRegs += CPU_REG_X;
eblock->mIns[esz - 2].mType = ASMIT_LDX; eblock->mIns[esz - 2].mLive |= LIVE_CPU_REG_X;
eblock->mIns[esz - 1].mType = ASMIT_CPX; eblock->mIns[esz - 1].mLive |= LIVE_CPU_REG_X;
changed = true;
}
#endif
}
}
if (mTrueJump && mTrueJump->LoopRegisterWrapAround())
changed = true;
if (mFalseJump && mFalseJump->LoopRegisterWrapAround())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::EliminateDeadLoops(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mNumEntries == 2 && mFalseJump)
{
NativeCodeBasicBlock* eblock = nullptr;
if (mTrueJump == this)
eblock = mFalseJump;
else if (mFalseJump == this)
eblock = mTrueJump;
if (eblock)
{
if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INX || mIns[0].mType == ASMIT_DEX) && mIns[1].mType == ASMIT_CPX)
{
if (!(eblock->mEntryRequiredRegs[CPU_REG_X]))
{
mLoopHead = false;
mTrueJump = eblock;
mBranch = ASMIT_JMP;
mEntryBlocks.RemoveAll(this);
mFalseJump = nullptr;
mNumEntries--;
changed = true;
}
}
else if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INY || mIns[0].mType == ASMIT_DEY) && mIns[1].mType == ASMIT_CPY)
{
if (!(eblock->mEntryRequiredRegs[CPU_REG_Y]))
{
mLoopHead = false;
mTrueJump = eblock;
mBranch = ASMIT_JMP;
mEntryBlocks.RemoveAll(this);
mFalseJump = nullptr;
mNumEntries--;
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->EliminateDeadLoops())
changed = true;
if (mFalseJump && mFalseJump->EliminateDeadLoops())
changed = true;
}
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::SinglePathStoreForward(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mFalseJump)
{
NumberSet touched(NUM_REGS);
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_A])
{
if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_X])
{
if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_Y])
{
if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, mIns[i]));
for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (mIns[i].ChangesAccu()) touched += CPU_REG_A;
if (mIns[i].ChangesXReg()) touched += CPU_REG_X;
if (mIns[i].ChangesYReg()) touched += CPU_REG_Y;
if (mIns[i].mMode == ASMIM_ZERO_PAGE) touched += mIns[i].mAddress;
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
touched += mIns[i].mAddress;
touched += mIns[i].mAddress + 1;
}
if (mIns[i].mType == ASMIT_JSR)
break;
}
}
if (mTrueJump && mTrueJump->SinglePathStoreForward())
changed = true;
if (mFalseJump && mFalseJump->SinglePathStoreForward())
changed = true;
}
return changed;
}
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)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mTrueJump->mTrueJump && !mFalseJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 0)
{
int sz = mIns.Size();
if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mTrueJump->mIns[0].mLive & LIVE_MEM))
{
if (mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mTrueJump->mIns[0].mAddress)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
for (int i = 1; i < mTrueJump->mIns.Size(); i++)
lblock->mIns.Push(mTrueJump->mIns[i]);
mTrueJump->mIns.SetSize(1);
mTrueJump->mTrueJump->RemEntryBlock(mTrueJump);
mTrueJump->mTrueJump->AddEntryBlock(lblock);
if (mTrueJump->mFalseJump)
{
mTrueJump->mFalseJump->RemEntryBlock(mTrueJump);
mTrueJump->mFalseJump->AddEntryBlock(lblock);
}
lblock->mTrueJump = mTrueJump->mTrueJump;
lblock->mFalseJump = mTrueJump->mFalseJump;
lblock->mBranch = mTrueJump->mBranch;
lblock->mNumEntries = 2;
lblock->mEntryBlocks.Push(this);
lblock->mEntryBlocks.Push(mTrueJump);
lblock->mEntryProvidedRegs = mTrueJump->mEntryRequiredRegs;
lblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;
lblock->mExitRequiredRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->RemEntryBlock(this);
mTrueJump->mFalseJump = nullptr;
mTrueJump->mTrueJump = lblock;
mTrueJump->mBranch = ASMIT_JMP;
mTrueJump = lblock;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->CrossBlockStoreLoadBypass(proc))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockStoreLoadBypass(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::SimpleInlineCalls(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_JSR)
{
if (mIns[i].mLinkerObject && mIns[i].mLinkerObject->mNativeProc)
{
NativeCodeProcedure* proc = mIns[i].mLinkerObject->mNativeProc;
if (proc->mSimpleInline)
{
NativeCodeBasicBlock* sins = proc->mEntryBlock->mTrueJump;
mIns.Remove(i);
for(int j=0; j<sins->mIns.Size(); j++)
mIns.Insert(i + j, sins->mIns[j]);
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->SimpleInlineCalls())
changed = true;
if (mFalseJump && mFalseJump->SimpleInlineCalls())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Expand16BitLoopBranch(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
{
int sz = mIns.Size();
if (sz >= 1 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY))
{
if (mTrueJump->mTrueJump->mLoopHead && IsDominatedBy(mTrueJump->mTrueJump) ||
mLoopHead && !mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == this)
{
NativeCodeBasicBlock* tblock = mTrueJump->mTrueJump;
NativeCodeBasicBlock* nblock = mProc->AllocateBlock();
nblock->Close(mIns[sz - 1].mIns, mFalseJump, mTrueJump->mFalseJump, ASMIT_BEQ);
mBranch = ASMIT_BCC;
mFalseJump->RemEntryBlock(this);
mFalseJump->AddEntryBlock(nblock);
mTrueJump->RemEntryBlock(this);
tblock->AddEntryBlock(this);
mFalseJump = nblock;
mTrueJump = tblock;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->Expand16BitLoopBranch())
changed = true;
if (mFalseJump && mFalseJump->Expand16BitLoopBranch())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int carry = -1;
if (mEntryRegisterDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
carry = mEntryRegisterDataSet.mRegs[CPU_REG_C].mValue;
for (int i = 0; i < mIns.Size(); i++)
{
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TXA));
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCC;
eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TXA));
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TYA));
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCC;
eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TYA));
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
break;
}
#if 1
if (i + 4 == mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
!(mIns[i + 3].mLive & LIVE_CPU_REG_A) &&
mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_C] &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
{
mIns[i + 3].mType = ASMIT_INC;
mIns[i + 3].mLive |= 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;
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BNE;
else
mBranch = ASMIT_BEQ;
changed = true;
break;
}
else if (i + 4 == mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
!(mIns[i + 3].mLive & LIVE_CPU_REG_A) &&
mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_C] &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
{
mIns[i + 3].mType = ASMIT_INC;
mIns[i + 3].mLive |= 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;
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BNE;
else
mBranch = ASMIT_BEQ;
changed = true;
break;
}
#endif
#if 1
if (i + 5 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
mIns[i + 5].mType == ASMIT_TAX && mIns[i + 5].mMode == ASMIM_IMPLIED && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
changed = true;
NativeCodeBasicBlock* mblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 6; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0));
mIns[i + 1].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X;
mTrueJump = mblock;
mFalseJump = rblock;
mBranch = ASMIT_BMI;
mblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0xff));
mblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
}
#endif
#if 1
if (i + 6 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
mIns[i + 6].mType == ASMIT_ROL && mIns[i + 6].mMode == ASMIM_IMPLIED)
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 7; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 0].mType = ASMIT_ASL;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#if 1
if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
{
changed = true;
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 4].mAddress));
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 5; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 0].mType = ASMIT_AND;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0x80;
mTrueJump = rblock;
mFalseJump = neblock;
mBranch = ASMIT_BEQ;
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
mIns[i + 6].mType == ASMIT_ROL && mIns[i + 6].mMode == ASMIM_IMPLIED)
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 7; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i].mIns, ASMIT_ASL));
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
}
#endif
#if 1
if (i + 6 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
if (mIns[i + 6].mLive & LIVE_CPU_REG_A)
fblock->mIns.Push(mIns[i + 4]);
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (carry == 0 &&
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
mIns[i + 3].mType == ASMIT_LDA &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 5]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 5].mMode) &&
!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
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_INC; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;
for (int j = i + 6; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 5]);
mIns.SetSize(i + 3);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 3].mMode) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
fblock->mIns.Push(mIns[i + 1]);
fblock->mIns[0].mType = ASMIT_DEC;
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_DEC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_TAX &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_INX; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
fblock->mIns.Push(mIns[i + 4]);
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & LIVE_CPU_REG_X) &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
fblock->mIns.Push(mIns[i + 4]);
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & LIVE_CPU_REG_Y) &&
mIns[i + 4].mType == ASMIT_TXA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_TAX &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
fblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA));
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
mIns.SetSize(i + 4);
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
if (mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_TAY &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_INY; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
fblock->mIns.Push(mIns[i + 4]);
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
break;
}
}
#endif
#if 1
if (i + 5 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_EOR && mIns[i + 5].mMode == ASMIM_IMMEDIATE)
{
uint8 veq = mIns[i + 4].mAddress ^ mIns[i + 5].mAddress, vne = mIns[i + 5].mAddress;
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 6; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BNE;
if (veq != 0)
eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 4 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED &&
mIns[i + 3].mType == ASMIT_TAY &&
mIns[i + 4].mType == ASMIT_TXA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
const InterInstruction* iins = mIns[i].mIns;
for (int j = i + 5; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
mTrueJump = iblock;
mFalseJump = rblock;
mBranch = ASMIT_BCS;
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
iblock->Close(iins, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 3 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED)
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 4; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BNE;
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 4 < mIns.Size() &&
(mIns[i + 0].mType == ASMIT_CPX || mIns[i + 0].mType == ASMIT_CPY) && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x01 &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_AND && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
{
uint8 veq = mIns[i + 3].mAddress ^ mIns[i + 4].mAddress, vne = mIns[i + 4].mAddress;
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 5; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
if (mIns[i + 0].mType == ASMIT_CPX)
mIns[i + 0].mType = ASMIT_TXA;
else if (mIns[i + 0].mType == ASMIT_CPY)
mIns[i + 0].mType = ASMIT_TYA;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BNE;
if (veq != 0)
eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 4 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
{
uint8 veq = mIns[i + 4].mAddress, vne = 0;
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 5; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BNE;
if (veq != 0)
eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 4 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff)
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* neblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
for (int j = i + 5; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mTrueJump = neblock;
mFalseJump = eblock;
mBranch = ASMIT_BNE;
neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
break;
}
#endif
#if 1
if (i + 12 < mIns.Size())
{
// Check for sign extending
if (mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff)
{
// Extended byte is saved
if (mIns[i + 5].mType == ASMIT_STA || mIns[i + 5].mType == ASMIT_TAX || mIns[i + 5].mType == ASMIT_TAY)
{
// There is an addition direct after it
if (mIns[i + 6].mType == ASMIT_LDA && mIns[i + 7].mType == ASMIT_CLC && mIns[i + 8].mType == ASMIT_ADC && mIns[i + 9].mType == ASMIT_STA &&
mIns[i + 11].mType == ASMIT_ADC && mIns[i + 12].mType == ASMIT_STA && !(mIns[i + 12].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
// Uses the sign extended source
if (mIns[i + 6].SameEffectiveAddress(mIns[i + 0]) || mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
{
// Using the result of the sign extension for the upper byte add
if (mIns[i + 5].mType == ASMIT_TAX && mIns[i + 10].mType == ASMIT_TXA && !(mIns[i + 10].mLive & LIVE_CPU_REG_X) ||
mIns[i + 5].mType == ASMIT_TAY && mIns[i + 10].mType == ASMIT_TYA && !(mIns[i + 10].mLive & LIVE_CPU_REG_Y) ||
mIns[i + 5].mType == ASMIT_STA && mIns[i + 10].mType == ASMIT_LDA && mIns[i + 5].SameEffectiveAddress(mIns[i + 10]) && !(mIns[i + 10].mLive & LIVE_MEM))
{
// Can change to inc
if (mIns[i + 11].SameEffectiveAddress(mIns[i + 12]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 11].mMode))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* dblock = proc->AllocateBlock();
NativeCodeBasicBlock* ablock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
dblock->mIns.Push(mIns[i + 11]);
dblock->mIns[0].mType = ASMIT_DEC;
dblock->mTrueJump = ablock;
dblock->mBranch = ASMIT_JMP;
ablock->mIns.Push(mIns[i + 7]);
ablock->mIns.Push(mIns[i + 8]);
ablock->mIns.Push(mIns[i + 9]);
if (mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
{
ablock->mIns[1].CopyMode(mIns[i + 6]);
}
ablock->mBranch = ASMIT_BCC;
ablock->mTrueJump = fblock;
ablock->mFalseJump = iblock;
iblock->mIns.Push(mIns[i + 11]);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = ablock;
mFalseJump = dblock;
mBranch = ASMIT_BPL;
for (int j = i + 13; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.SetSize(i + 1);
break;
}
else if (mIns[i + 5].mType == ASMIT_TAX && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 11].mMode) && HasAsmInstructionMode(ASMIT_STX, mIns[i + 12].mMode))
{
// Can't do direct inc, so fallback to x register
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* dblock = proc->AllocateBlock();
NativeCodeBasicBlock* ablock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
dblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
dblock->mTrueJump = ablock;
dblock->mBranch = ASMIT_JMP;
ablock->mIns.Push(mIns[i + 7]);
ablock->mIns.Push(mIns[i + 8]);
ablock->mIns.Push(mIns[i + 9]);
if (mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
{
ablock->mIns[1].CopyMode(mIns[i + 6]);
}
ablock->mBranch = ASMIT_BCC;
ablock->mTrueJump = fblock;
ablock->mFalseJump = iblock;
iblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = ablock;
mFalseJump = dblock;
mBranch = ASMIT_BPL;
fblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i + 12]));
for (int j = i + 13; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i + 11]));
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns.SetSize(i + 2);
break;
}
}
}
}
}
}
}
#endif
if (i + 2 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock * iblock = proc->AllocateBlock();
NativeCodeBasicBlock * fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 2]);
mIns.SetSize(i);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_ADC &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 2]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 2]);
mIns.SetSize(i);
iblock->mIns[0].mType = ASMIT_INC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 2]);
mIns.SetSize(i);
iblock->mIns[0].mType = ASMIT_DEC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCS;
break;
}
else if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
for (int j = i + 2; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
fblock->mIns[0].mType = ASMIT_STY;
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
for (int j = i + 2; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
fblock->mIns[0].mType = ASMIT_STX;
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAY &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
const InterInstruction* iins(mIns[i].mIns);
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCC;
break;
}
else if (mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
changed = true;
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
NativeCodeBasicBlock* fblock = proc->AllocateBlock();
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
for (int j = i + 3; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 2]);
mIns.SetSize(i);
iblock->mIns[0].mType = ASMIT_DEC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BCS;
break;
}
}
if (mIns[i].mType == ASMIT_CLC)
carry = 0;
else if (mIns[i].mType == ASMIT_SEC)
carry = 0;
else if (mIns[i].ChangesCarry())
carry = -1;
}
#if 1
if (mIns.Size() >= 4 && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs.Size() > 0)
{
int sz = mIns.Size();
if (mIns[sz - 4].mType == ASMIT_TYA &&
mIns[sz - 3].mType == ASMIT_CLC &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
mIns[sz - 1].mType == ASMIT_TAY && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
{
mIns[sz - 4].mType = ASMIT_INY; mIns[sz - 4].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BNE;
else
mBranch = ASMIT_BEQ;
mIns.SetSize(sz - 3);
changed = true;
}
}
#endif
if (mIns.Size() >= 2)
{
int sz = mIns.Size();
if (mIns[sz - 2].mType == ASMIT_EOR && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
{
changed = true;
int addr = mIns[sz - 1].mAddress ^ 0x80;
const InterInstruction* iins(mIns[sz - 1].mIns);
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CMP, ASMIM_IMMEDIATE, addr));
mIns.SetSize(sz - 2);
mIns.Push(NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0x00));
iblock->mTrueJump = mTrueJump;
iblock->mFalseJump = mFalseJump;
iblock->mBranch = mBranch;
if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BPL;
if (addr & 0x80)
mFalseJump = iblock;
else
mTrueJump = iblock;
}
else
{
mBranch = ASMIT_BMI;
if (addr & 0x80)
mTrueJump = iblock;
else
mFalseJump = iblock;
}
}
}
if (mIns.Size() >= 1 && mExitRequiredRegs.Size() > 0)
{
int sz = mIns.Size();
if (mIns[sz - 1].mType == ASMIT_CMP && mBranch == ASMIT_BNE)
{
if (mTrueJump->mIns.Size() == 1 && mTrueJump->mBranch == ASMIT_BCC && mTrueJump->mFalseJump == mFalseJump)
{
if (mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !mFalseJump->mEntryRequiredRegs[mTrueJump->mIns[0].mAddress])
{
if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE)
{
mIns.Insert(sz - 1, mTrueJump->mIns[0]);
mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
}
else
mIns.Push(mTrueJump->mIns[0]);
mExitRequiredRegs += mTrueJump->mIns[0].mAddress;
mTrueJump->mEntryBlocks.RemoveAll(this);
mTrueJump->mNumEntries--;
mBranch = ASMIT_BCC;
mTrueJump = mTrueJump->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
}
}
}
if (mExitRequiredRegs.Size() > 0 && mIns.Size() >= 3 && mFalseJump && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
{
int sz = mIns.Size();
if (mIns[sz - 3].mType == ASMIT_STA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_CMP, mIns[sz - 2].mMode) &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 3].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
changed = true;
NativeCodeBasicBlock* cblock = proc->AllocateBlock();
cblock->Close(mBranchIns, mTrueJump, mFalseJump, mBranch);
mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
mIns[sz - 2].mType = ASMIT_CMP; mIns[sz - 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_C;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
mExitRequiredRegs += CPU_REG_Z;
if (mBranch == ASMIT_BCC)
{
mTrueJump = mFalseJump;
mFalseJump = cblock;
cblock->mBranch = ASMIT_BNE;
}
else
{
mFalseJump = mTrueJump;
mTrueJump = cblock;
cblock->mBranch = ASMIT_BEQ;
}
}
}
if (mIns.Size() >= 2 && !mFalseJump && mTrueJump && mTrueJump->mTrueJump && mTrueJump->mIns.Size() > 0)
{
int sz = mIns.Size();
if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 1].mType == ASMIT_ADC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 &&
mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
NativeCodeBasicBlock * tblock = mTrueJump->SplitAt(1);
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.RemoveAll(this);
NativeCodeBasicBlock* iblock = proc->AllocateBlock();
iblock->Close(mBranchIns, tblock, nullptr, ASMIT_JMP);
iblock->mIns.Push(NativeCodeInstruction(mIns[sz - 2].mIns, ASMIT_INC, mIns[sz - 2]));
mIns.SetSize(sz - 2);
mBranch = ASMIT_BCC;
mTrueJump = tblock;
mFalseJump = iblock;
tblock->mNumEntries += 2;
tblock->mEntryBlocks.Push(this);
tblock->mEntryBlocks.Push(iblock);
iblock->mNumEntries = 1;
iblock->mEntryBlocks.Push(this);
changed = true;
}
}
if (mIns.Size() >= 3 && mFalseJump && mBranch == ASMIT_BCC && mExitRequiredRegs.Size())
{
int sz = mIns.Size();
if (mIns[sz - 3].mType == ASMIT_LDA &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 3]) &&
HasAsmInstructionMode(ASMIT_INC, mIns[sz - 1].mMode) &&
!(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_C])
{
NativeCodeBasicBlock* tblock = this->SplitAt(sz - 3);
tblock->mBranch = ASMIT_BNE;
tblock->mIns[0].mType = ASMIT_INC;
tblock->mIns.SetSize(1);
mBranch = ASMIT_BCC;
mFalseJump = tblock;
mTrueJump = tblock->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
else if (mIns[sz - 3].mType == ASMIT_TXA &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_TAX &&
!(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_C])
{
NativeCodeBasicBlock* tblock = this->SplitAt(sz - 3);
tblock->mBranch = ASMIT_BNE;
tblock->mIns[0].mType = ASMIT_INX;
tblock->mIns[0].mMode = ASMIM_IMPLIED;
tblock->mIns[0].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
tblock->mIns.SetSize(1);
mBranch = ASMIT_BCC;
mFalseJump = tblock;
mTrueJump = tblock->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
}
if (mIns.Size() >= 3 && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
{
int sz = mIns.Size();
if ((mIns[sz - 3].mType == ASMIT_INC || mIns[sz - 3].mType == ASMIT_DEC) &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 3]) &&
mIns[sz - 1].mType == ASMIT_ORA &&
!(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
mIns[sz - 3].mLive |= LIVE_CPU_REG_Z;
NativeCodeBasicBlock* tblock = this->SplitAt(sz - 2);
if (tblock->mBranch == ASMIT_BEQ)
mTrueJump = tblock->mFalseJump;
else
mTrueJump = tblock->mTrueJump;
mBranch = ASMIT_BNE;
mFalseJump = tblock;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
}
if (mIns.Size() >= 8 && mFalseJump && (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ))
{
int sz = mIns.Size();
if (mIns[sz - 8].mType == ASMIT_LDA &&
mIns[sz - 7].mType == ASMIT_CLC &&
mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0xff &&
mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 8]) &&
mIns[sz - 4].mType == ASMIT_LDA &&
mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0xff &&
mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 5]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 2].mMode) &&
!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
changed = true;
NativeCodeBasicBlock* eblock, * neblock;
if (mBranch == ASMIT_BEQ)
{
eblock = mTrueJump;
neblock = mFalseJump;
}
else
{
eblock = mFalseJump;
neblock = mTrueJump;
}
NativeCodeBasicBlock* hblock = proc->AllocateBlock();
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* oblock = proc->AllocateBlock();
mBranch = ASMIT_BNE;
mTrueJump = lblock;
mFalseJump = hblock;
hblock->mBranch = ASMIT_JMP;
hblock->mTrueJump = lblock;
lblock->mBranch = ASMIT_BNE;
lblock->mTrueJump = neblock;
lblock->mFalseJump = oblock;
oblock->mBranch = ASMIT_BNE;
oblock->mTrueJump = neblock;
oblock->mFalseJump = eblock;
const InterInstruction* iins(mIns[sz - 4].mIns);
hblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEC, mIns[sz - 4]));
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEC, mIns[sz - 5]));
oblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDA, mIns[sz - 4]));
mIns[sz - 8].mLive |= LIVE_CPU_REG_Z;
mIns.SetSize(sz - 7);
#if 0
fblock->mTrueJump = mTrueJump;
fblock->mFalseJump = mFalseJump;
fblock->mBranch = mBranch;
fblock->mIns.Push(mIns[i + 1]);
fblock->mIns[0].mType = ASMIT_DEC;
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
for (int j = i + 7; j < mIns.Size(); j++)
fblock->mIns.Push(mIns[j]);
iblock->mIns.Push(mIns[i + 6]);
mIns.SetSize(i + 4);
iblock->mIns[0].mType = ASMIT_DEC;
iblock->mTrueJump = fblock;
iblock->mBranch = ASMIT_JMP;
mTrueJump = fblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
#endif
}
}
if (mIns.Size() >= 2 && mFalseJump && mBranch == ASMIT_BMI)
{
int sz = mIns.Size();
if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
{
if (mExitRequiredRegs[CPU_REG_Z])
{
if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BNE)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
else if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BEQ)
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
else if (!mExitRequiredRegs[CPU_REG_A])
{
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 2);
changed = true;
}
}
}
#if 1
if (mIns.Size() >= 1 && mFalseJump)
{
int sz = mIns.Size();
if (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY)
{
if (mBranch == ASMIT_BEQ)
{
if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
{
if (mFalseJump->mIns.Size() == 0)
{
if (mFalseJump->mBranch == ASMIT_BCC)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
else if (mFalseJump->mBranch == ASMIT_BCS)
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
if (mTrueJump->mIns.Size() == 0)
{
if (mTrueJump->mBranch == ASMIT_BCC)
{
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
else if (mTrueJump->mBranch == ASMIT_BCS)
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
}
}
if (mFalseJump->mNumEntries == 1/* && mTrueJump->mNumEntries == 2*/ && mFalseJump->mIns.Size() == 0)
{
if (mFalseJump->mBranch == ASMIT_BCC)
{
if (mFalseJump->mFalseJump == mTrueJump)
{
mBranch = ASMIT_BCS;
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
}
else if (mFalseJump->mBranch == ASMIT_BCS)
{
if (mFalseJump->mTrueJump == mTrueJump)
{
mBranch = ASMIT_BCS;
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
}
}
else if (mBranch == ASMIT_BNE)
{
if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
{
if (mFalseJump->mIns.Size() == 0)
{
if (mFalseJump->mBranch == ASMIT_BCC)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
else if (mFalseJump->mBranch == ASMIT_BCS)
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
if (mTrueJump->mIns.Size() == 0)
{
if (mTrueJump->mBranch == ASMIT_BCC)
{
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
else if (mTrueJump->mBranch == ASMIT_BCS)
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
}
}
if (mTrueJump->mNumEntries == 1/* && mFalseJump->mNumEntries == 2*/ && mTrueJump->mIns.Size() == 0)
{
if (mTrueJump->mBranch == ASMIT_BCC)
{
if (mTrueJump->mFalseJump == mFalseJump)
{
mBranch = ASMIT_BCC;
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
}
else if (mTrueJump->mBranch == ASMIT_BCS)
{
if (mTrueJump->mTrueJump == mFalseJump)
{
mBranch = ASMIT_BCC;
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
}
}
}
}
}
#endif
// Simple diamond split
if (mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
{
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
{
if (mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1)
{
if (mTrueJump->mIns[0].mType == ASMIT_AND && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
mFalseJump->mIns[0].mType == ASMIT_ORA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
(mTrueJump->mIns[0].mAddress ^ mFalseJump->mIns[0].mAddress) == 0xff)
{
mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mIns.SetSize(0);
changed = true;
}
else if (mTrueJump->mIns[0].mType == ASMIT_ORA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
mFalseJump->mIns[0].mType == ASMIT_AND && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
(mTrueJump->mIns[0].mAddress ^ mFalseJump->mIns[0].mAddress) == 0xff)
{
mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mIns.SetSize(0);
changed = true;
}
}
}
}
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 (mFalseJump && mIns.Size() >= 8 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
{
int sz = mIns.Size();
if (mIns[sz - 8].mType == ASMIT_SEC &&
mIns[sz - 7].mType == ASMIT_LDA &&
mIns[sz - 6].mType == ASMIT_SBC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0x01 &&
mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 7]) &&
mIns[sz - 4].mType == ASMIT_LDA &&
mIns[sz - 3].mType == ASMIT_SBC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 &&
mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 7]) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 1].mMode) &&
!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
changed = true;
NativeCodeBasicBlock* hiblock = proc->AllocateBlock();
NativeCodeBasicBlock* loblock = proc->AllocateBlock();
NativeCodeBasicBlock* orblock = proc->AllocateBlock();
NativeCodeBasicBlock* eqblock, * neblock;
if (mBranch == ASMIT_BEQ)
{
eqblock = mTrueJump;
neblock = mFalseJump;
}
else
{
neblock = mTrueJump;
eqblock = mFalseJump;
}
hiblock->mBranch = ASMIT_JMP;
hiblock->mTrueJump = loblock;
loblock->mBranch = ASMIT_BNE;
loblock->mTrueJump = neblock;
loblock->mFalseJump = orblock;
orblock->mBranch = ASMIT_BNE;
orblock->mTrueJump = neblock;
orblock->mFalseJump = eqblock;
mBranch = ASMIT_BNE;
mTrueJump = loblock;
mFalseJump = hiblock;
hiblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_DEC, mIns[sz - 4]));
loblock->mIns.Push(NativeCodeInstruction(mIns[sz - 7].mIns, ASMIT_DEC, mIns[sz - 7]));
orblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_LDA, mIns[sz - 4]));
mIns[sz - 8].mType = ASMIT_NOP;
mIns.SetSize(sz - 6);
}
}
if (mTrueJump && mTrueJump->ExpandADCToBranch(proc))
changed = true;
if (mFalseJump && mFalseJump->ExpandADCToBranch(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ReduceLocalXPressure(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int start = 0;
while (start < mIns.Size())
{
const NativeCodeInstruction& ins(mIns[start]);
if ((ins.mType == ASMIT_LDX || ins.mType == ASMIT_TAX) && ins.mMode != ASMIM_INDIRECT_Y && ins.mMode != ASMIM_ABSOLUTE_Y && !(ins.mLive & LIVE_CPU_REG_Y))
{
int end = start + 1;
while (end < mIns.Size())
{
const NativeCodeInstruction& eins(mIns[end]);
if (eins.mType == ASMIT_LDX || eins.mType == ASMIT_TAX)
{
ReplaceXRegWithYReg(start, end);
changed = true;
break;
}
else if (eins.ChangesYReg() || (eins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(eins.mType, ASMIM_ABSOLUTE_Y)))
{
break;
}
else if (!(eins.mLive & LIVE_CPU_REG_X))
{
end++;
ReplaceXRegWithYReg(start, end);
changed = true;
break;
}
end++;
}
start = end;
}
else
start++;
}
if (mTrueJump && mTrueJump->ReduceLocalXPressure())
changed = true;
if (mFalseJump && mFalseJump->ReduceLocalXPressure())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CombineZPPair(int at, int r0, int r1, bool use0, bool use1, bool & used1)
{
bool changed = false;
int i = at;
while (i < mIns.Size() && !use0 && !use1)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (ins.ChangesAddress())
{
if (ins.mAddress == r0)
use1 = true;
else if (ins.mAddress == r1)
use0 = true;
}
else if (!(ins.mLive & LIVE_MEM))
{
if (ins.mAddress == r0)
use1 = true;
else if (ins.mAddress == r1)
use0 = true;
}
}
else
{
if (ins.ReferencesZeroPage(r0))
use0 = true;
if (ins.ReferencesZeroPage(r1))
use1 = true;
}
i++;
}
if (use0 && use1)
return false;
if (!use0 && !use1)
{
if (!mExitRequiredRegs[r0])
use1 = true;
else if (!mExitRequiredRegs[r1])
use0 = true;
else
return false;
}
bool valid0 = true, valid1 = true;
used1 = use1;
i = at;
while (i < mIns.Size() && valid0 && valid1)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (ins.ChangesAddress())
{
if (ins.mAddress == r0)
valid0 = false;
else if (ins.mAddress == r1)
valid1 = false;
}
else
{
if (use1)
{
if (ins.mAddress == r0)
{
ins.mAddress = r1;
changed = true;
}
else if (ins.mAddress == r1)
ins.mLive |= LIVE_MEM;
}
else if (use0)
{
if (ins.mAddress == r1)
{
ins.mAddress = r0;
changed = true;
}
else if (ins.mAddress == r0)
ins.mLive |= LIVE_MEM;
}
}
}
else
{
if (ins.ChangesZeroPage(r0))
valid0 = false;
if (ins.ChangesZeroPage(r1))
valid1 = false;
}
i++;
}
return changed;
}
bool NativeCodeBasicBlock::RemoveDoubleZPStore(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
bool swap;
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
{
if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
{
if (swap)
{
int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
}
changed = true;
}
}
else if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
{
if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
{
if (swap)
{
int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
}
changed = true;
}
}
else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
{
if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
{
if (swap)
{
int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
}
changed = true;
}
}
}
if (mTrueJump && mTrueJump->RemoveDoubleZPStore())
changed = true;
if (mFalseJump && mFalseJump->RemoveDoubleZPStore())
changed = true;
}
return changed;
}
struct ValueNumbers
{
int zvalues[256], avalue, xvalue, yvalue;
int ivalue = 0;
void Reset(void)
{
for (int i = 0; i < 256; i++)
zvalues[i] = ivalue++;
avalue = ivalue++;
xvalue = ivalue++;
yvalue = ivalue++;
}
};
bool NativeCodeBasicBlock::LocalZeroPageValueNumbering(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
ValueNumbers vn;
vn.Reset();
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins = mIns[i];
if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.avalue == vn.zvalues[ins.mAddress])
{
if (ins.mLive & LIVE_CPU_REG_Z)
{
ins.mType = ASMIT_ORA;
ins.mMode = ASMIM_IMMEDIATE;
ins.mAddress = 0;
changed = true;
}
else
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
}
else
vn.avalue = vn.zvalues[ins.mAddress];
}
else if (ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.xvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.xvalue = vn.zvalues[ins.mAddress];
}
else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.yvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.yvalue = vn.zvalues[ins.mAddress];
}
else if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.avalue == vn.zvalues[ins.mAddress])
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.zvalues[ins.mAddress] = vn.avalue;
}
else if (ins.mType == ASMIT_STX && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.xvalue == vn.zvalues[ins.mAddress])
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.zvalues[ins.mAddress] = vn.xvalue;
}
else if (ins.mType == ASMIT_STY && ins.mMode == ASMIM_ZERO_PAGE)
{
if (vn.yvalue == vn.zvalues[ins.mAddress])
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.zvalues[ins.mAddress] = vn.yvalue;
}
else if (ins.mType == ASMIT_TAX)
{
if (vn.avalue == vn.xvalue && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.xvalue = vn.avalue;
}
else if (ins.mType == ASMIT_TAY)
{
if (vn.avalue == vn.yvalue && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.yvalue = vn.avalue;
}
else if (ins.mType == ASMIT_TXA)
{
if (vn.xvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.avalue = vn.xvalue;
}
else if (ins.mType == ASMIT_TYA)
{
if (vn.yvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else
vn.avalue = vn.yvalue;
}
else if (ins.mType == ASMIT_JSR)
vn.Reset();
else
{
if (ins.mMode == ASMIM_INDIRECT_Y && !(ins.mLive & LIVE_MEM))
{
int i = 0;
while (i < 255 && (i == ins.mAddress || vn.zvalues[i] != vn.zvalues[ins.mAddress] || vn.zvalues[i + 1] != vn.zvalues[ins.mAddress + 1]))
i++;
if (i < 255)
{
ins.mAddress = i;
}
}
if (ins.ChangesAccu())
vn.avalue = vn.ivalue++;
if (ins.ChangesXReg())
vn.xvalue = vn.ivalue++;
if (ins.ChangesYReg())
vn.yvalue = vn.ivalue++;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
vn.zvalues[ins.mAddress] = vn.ivalue++;
}
}
if (mTrueJump && mTrueJump->LocalZeroPageValueNumbering())
changed = true;
if (mFalseJump && mFalseJump->LocalZeroPageValueNumbering())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::LocalRegisterXYMap(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
int xregs[256], yregs[256];
for (int i = 0; i < 256; i++)
xregs[i] = yregs[i] = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && (mIns[i].mMode != ASMIM_ZERO_PAGE || (xregs[mIns[i].mAddress] < 0 && xregs[mIns[i].mAddress] < 0) || (mIns[i + 1].mLive & LIVE_MEM)))
{
if (mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
if (xregs[mIns[i + 1].mAddress] >= 0 && !(mIns[i + 1].mLive & LIVE_MEM))
{
int addr = mIns[i + 1].mAddress;
mIns[i + 1].CopyMode(mIns[i]);
if (mIns[i + 1].RequiresYReg())
mIns[i].mLive |= LIVE_CPU_REG_Y;
else if (mIns[i + 1].RequiresXReg())
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i].mMode = ASMIM_ZERO_PAGE;
mIns[i].mAddress = addr;
}
else if (yregs[mIns[i + 1].mAddress] >= 0 && !(mIns[i + 1].mLive & LIVE_MEM))
{
int addr = mIns[i + 1].mAddress;
mIns[i + 1].CopyMode(mIns[i]);
if (mIns[i + 1].RequiresYReg())
mIns[i].mLive |= LIVE_CPU_REG_Y;
else if (mIns[i + 1].RequiresXReg())
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i].mMode = ASMIM_ZERO_PAGE;
mIns[i].mAddress = addr;
}
}
}
CheckLive();
const NativeCodeInstruction& ins(mIns[i]);
if (ins.ChangesXReg())
{
for (int i = 0; i < 256; i++)
xregs[i] = -1;
}
if (ins.ChangesYReg())
{
for (int i = 0; i < 256; i++)
yregs[i] = -1;
}
if (ins.mMode == ASMIM_ZERO_PAGE)
{
switch (ins.mType)
{
case ASMIT_STA:
#if 0
if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4 ||
ins.mAddress >= BC_REG_WORK && ins.mAddress < BC_REG_WORK + 4)
{
}
else
#endif
{
if (!(ins.mLive & LIVE_CPU_REG_X))
{
if (xregs[ins.mAddress] < 0)
xregs[ins.mAddress] = i;
}
if (!(ins.mLive & LIVE_CPU_REG_Y))
{
if (yregs[ins.mAddress] < 0)
yregs[ins.mAddress] = i;
}
}
break;
case ASMIT_LDA:
if (xregs[ins.mAddress] >= 0 && !(ins.mLive & LIVE_MEM))
{
changed = true;
for (int j = xregs[ins.mAddress]; j <= i; j++)
{
NativeCodeInstruction& rins(mIns[j]);
if (rins.mMode == ASMIM_ZERO_PAGE && rins.mAddress == ins.mAddress)
{
switch (rins.mType)
{
case ASMIT_STA:
rins.mType = ASMIT_TAX;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDA:
rins.mType = ASMIT_TXA;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_INC:
rins.mType = ASMIT_INX;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_DEC:
rins.mType = ASMIT_DEX;
rins.mMode = ASMIM_IMPLIED;
break;
}
}
rins.mLive |= LIVE_CPU_REG_X;
}
CheckLive();
for (int i = 0; i < 256; i++)
xregs[i] = -1;
}
else if (yregs[ins.mAddress] >= 0 && !(ins.mLive & LIVE_MEM))
{
changed = true;
for (int j = yregs[ins.mAddress]; j <= i; j++)
{
NativeCodeInstruction& rins(mIns[j]);
if (rins.mMode == ASMIM_ZERO_PAGE && rins.mAddress == ins.mAddress)
{
switch (rins.mType)
{
case ASMIT_STA:
rins.mType = ASMIT_TAY;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDA:
rins.mType = ASMIT_TYA;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_INC:
rins.mType = ASMIT_INY;
rins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_DEC:
rins.mType = ASMIT_DEY;
rins.mMode = ASMIM_IMPLIED;
break;
}
}
rins.mLive |= LIVE_CPU_REG_Y;
}
CheckLive();
for (int i = 0; i < 256; i++)
yregs[i] = -1;
}
break;
case ASMIT_INC:
case ASMIT_DEC:
break;
default:
xregs[ins.mAddress + 0] = -1;
yregs[ins.mAddress + 0] = -1;
break;
}
}
else if (ins.mMode == ASMIM_INDIRECT_Y)
{
xregs[ins.mAddress + 0] = -1;
xregs[ins.mAddress + 1] = -1;
yregs[ins.mAddress + 0] = -1;
yregs[ins.mAddress + 1] = -1;
}
else if (ins.mType == ASMIT_JSR)
{
for (int i = 0; i < 4; i++)
{
xregs[BC_REG_ACCU + i] = -1;
yregs[BC_REG_ACCU + i] = -1;
xregs[BC_REG_WORK + i] = -1;
yregs[BC_REG_WORK + i] = -1;
}
}
}
CheckLive();
if (mTrueJump && mTrueJump->LocalRegisterXYMap())
changed = true;
if (mFalseJump && mFalseJump->LocalRegisterXYMap())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::LoopRegisterXYMap(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mEntryBlocks.Size() > 1)
{
NativeCodeBasicBlock* pblock = nullptr;
ExpandingArray<NativeCodeBasicBlock*> lblocks, pblocks, eblocks;
bool addprefix = false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
if (b == this || b->IsDominatedBy(this))
lblocks.Push(b);
else
{
if (b->mFalseJump)
addprefix = true;
pblocks.Push(b);
}
}
if (lblocks.Size() > 0)
{
if (pblocks.Size() > 1 || addprefix)
{
pblock = mProc->AllocateBlock();
pblock->mEntryRequiredRegs = mEntryRequiredRegs;
pblock->mExitRequiredRegs = mEntryRequiredRegs;
pblock->Close(pblocks[0]->mBranchIns, this, nullptr, ASMIT_JMP);
AddEntryBlock(pblock);
for (int i = 0; i < pblocks.Size(); i++)
{
NativeCodeBasicBlock* b = pblocks[i];
if (this == b->mTrueJump)
{
b->mTrueJump = pblock;
RemEntryBlock(b);
pblock->AddEntryBlock(b);
}
if (this == b->mFalseJump)
{
b->mFalseJump = pblock;
RemEntryBlock(b);
pblock->AddEntryBlock(b);
}
}
}
else if (pblocks.Size() == 1)
pblock = pblocks[0];
if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
{
mProc->ResetPatched();
mPatched = true;
if (!lblocks.Contains(this))
lblocks.Push(this);
for (int i = 0; i < lblocks.Size(); i++)
lblocks[i]->mPatched = true;
pblock->mPatched = true;
int i = 0;
while (i < lblocks.Size())
{
NativeCodeBasicBlock* block = lblocks[i];
for (int j = 0; j < block->mEntryBlocks.Size(); j++)
{
NativeCodeBasicBlock* cblock = block->mEntryBlocks[j];
if (!cblock->mPatched)
{
cblock->mPatched = true;
lblocks.Push(cblock);
}
}
i++;
}
bool inner = true;
NativeCodeBasicBlock* eblock = nullptr;
i = 0;
while (i < lblocks.Size())
{
NativeCodeBasicBlock* b = lblocks[i];
if (b->mLoopHead && b != this)
{
inner = false;
break;
}
if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
{
NativeCodeBasicBlock* eblock = lblocks.Contains(b->mFalseJump) ? b->mTrueJump : b->mFalseJump;
if (eblock->mEntryBlocks.Size() > 1)
{
int k = 0;
while (k < eblock->mEntryBlocks.Size() && lblocks.Contains(eblock->mEntryBlocks[k]))
k++;
if (k != eblock->mEntryBlocks.Size())
{
NativeCodeBasicBlock* eb = mProc->AllocateBlock();
eb->mEntryRequiredRegs = eblock->mEntryRequiredRegs;
eb->mExitRequiredRegs = eblock->mEntryRequiredRegs;
eb->Close(eblock->mBranchIns, eblock, nullptr, ASMIT_JMP);
eb->AddEntryBlock(b);
eblock->AddEntryBlock(eb);
eblock->RemEntryBlock(b);
if (b->mFalseJump == eblock)
b->mFalseJump = eb;
else
b->mTrueJump = eb;
eblocks.Push(eb);
}
else
eblocks.Push(eblock);
}
else
eblocks.Push(eblock);
}
i++;
}
if (inner && eblocks.Size() > 0)
{
bool xfree = !mEntryRequiredRegs[CPU_REG_X], yfree = !mEntryRequiredRegs[CPU_REG_Y];
if (xfree || yfree)
{
int iregs[256];
for (int i = 0; i < 256; i++)
iregs[i] = 0;
for (int i = 0; i < lblocks.Size(); i++)
{
NativeCodeBasicBlock* b(lblocks[i]);
for (int j = 0; j < b->mIns.Size(); j++)
{
const NativeCodeInstruction& ins(b->mIns[j]);
if (ins.ReferencesXReg() || ins.ChangesXReg())
xfree = false;
if (ins.ReferencesYReg() || ins.ChangesYReg())
yfree = false;
if (ins.mMode == ASMIM_INDIRECT_Y)
{
iregs[ins.mAddress + 0] = -1;
iregs[ins.mAddress + 1] = -1;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && iregs[ins.mAddress] >= 0)
{
if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
iregs[ins.mAddress] += 5;
else if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA)
iregs[ins.mAddress] += 3;
else if (ins.IsCommutative() && j > 0 && b->mIns[j - 1].mType == ASMIT_LDA && (b->mIns[j - 1].mMode == ASMIM_IMMEDIATE || b->mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
iregs[ins.mAddress] += 3;
else
iregs[ins.mAddress] = -1;
}
}
}
if (xfree || yfree)
{
int mini = 0;
int mina = 3;
for (int i = 1; i < 256; i++)
{
if (iregs[i] > mina)
{
mina = iregs[i];
mini = i;
}
}
if (mini > 0)
{
if (xfree)
{
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mini));
if (pblock->mExitRequiredRegs[CPU_REG_Z])
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
pblock->mExitRequiredRegs += CPU_REG_X;
for (int i = 0; i < eblocks.Size(); i++)
{
eblocks[i]->mIns.Insert(0, NativeCodeInstruction(pblock->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, mini));
eblocks[i]->mEntryRequiredRegs += CPU_REG_X;
}
}
else
{
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_LDY, ASMIM_ZERO_PAGE, mini));
if (pblock->mExitRequiredRegs[CPU_REG_Z])
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
pblock->mExitRequiredRegs += CPU_REG_Y;
for (int i = 0; i < eblocks.Size(); i++)
{
eblocks[i]->mIns.Insert(0, NativeCodeInstruction(pblock->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, mini));
eblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
}
}
for (int i = 0; i < lblocks.Size(); i++)
{
NativeCodeBasicBlock* b(lblocks[i]);
if (xfree)
{
b->mEntryRequiredRegs += CPU_REG_X;
b->mExitRequiredRegs += CPU_REG_X;
}
else
{
b->mEntryRequiredRegs += CPU_REG_Y;
b->mExitRequiredRegs += CPU_REG_Y;
}
for (int j = 0; j < b->mIns.Size(); j++)
{
NativeCodeInstruction& ins(b->mIns[j]);
if (xfree)
ins.mLive |= LIVE_CPU_REG_X;
else
ins.mLive |= LIVE_CPU_REG_Y;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == mini)
{
if (ins.IsCommutative())
{
ins.CopyMode(b->mIns[j - 1]);
if (xfree)
b->mIns[j - 1].mType = ASMIT_TXA;
else
b->mIns[j - 1].mType = ASMIT_TYA;
b->mIns[j - 1].mMode = ASMIM_IMPLIED;
}
else
{
switch (ins.mType)
{
case ASMIT_INC:
if (xfree)
ins.mType = ASMIT_INX;
else
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_DEC:
if (xfree)
ins.mType = ASMIT_DEX;
else
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_LDA:
if (xfree)
ins.mType = ASMIT_TXA;
else
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_STA:
if (xfree)
ins.mType = ASMIT_TAX;
else
ins.mType = ASMIT_TAY;
ins.mMode = ASMIM_IMPLIED;
break;
}
}
}
}
}
changed = true;
}
}
}
}
}
}
}
if (mTrueJump && mTrueJump->LoopRegisterXYMap()) changed = true;
if (mFalseJump && mFalseJump->LoopRegisterXYMap()) changed = true;
}
return changed;
}
void NativeCodeBasicBlock::GlobalRegisterXYCheck(int* xregs, int* yregs)
{
if (!mVisited)
{
mVisited = true;
int yreg = -1;
int xreg = -1;
int iinc = mLoopHead ? 2 : 1;
for (int i = 0; i < mIns.Size(); i++)
{
const NativeCodeInstruction& ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE)
{
switch (ins.mType)
{
case ASMIT_LDA:
if (yregs[ins.mAddress] >= 0)
yregs[ins.mAddress] += iinc;
if (xregs[ins.mAddress] >= 0)
xregs[ins.mAddress] += iinc;
break;
case ASMIT_LDY:
if (yregs[ins.mAddress] >= 0)
{
yregs[ins.mAddress] += 2 * iinc;
yreg = ins.mAddress;
}
for (int i = 1; i < 256; i++)
if (i != ins.mAddress)
yregs[i] = -1;
xregs[ins.mAddress] = -1;
break;
case ASMIT_LDX:
if (xregs[ins.mAddress] >= 0)
{
xregs[ins.mAddress] += 2 * iinc;
xreg = ins.mAddress;
}
for (int i = 1; i < 256; i++)
if (i != ins.mAddress)
xregs[i] = -1;
yregs[ins.mAddress] = -1;
break;
case ASMIT_STA:
if (yreg == ins.mAddress)
yreg = -1;
if (xreg == ins.mAddress)
xreg = -1;
if (ins.mLive & LIVE_CPU_REG_Z)
{
xregs[ins.mAddress + 0] = -1;
yregs[ins.mAddress + 0] = -1;
}
else
{
if (yregs[ins.mAddress] >= 0)
yregs[ins.mAddress] += iinc;
if (xregs[ins.mAddress] >= 0)
xregs[ins.mAddress] += iinc;
}
break;
case ASMIT_INC:
case ASMIT_DEC:
if (yreg == ins.mAddress)
yreg = -1;
if (xreg == ins.mAddress)
xreg = -1;
if (yregs[ins.mAddress] >= 0)
yregs[ins.mAddress] += 3 * iinc;
if (xregs[ins.mAddress] >= 0)
xregs[ins.mAddress] += 3 * iinc;
break;
default:
xregs[ins.mAddress + 0] = -1;
yregs[ins.mAddress + 0] = -1;
break;
}
}
else if (ins.mMode == ASMIM_INDIRECT_Y)
{
for (int i = 1; i < 256; i++)
if (i != yreg)
yregs[i] = -1;
xregs[ins.mAddress + 0] = -1;
xregs[ins.mAddress + 1] = -1;
yregs[ins.mAddress + 0] = -1;
yregs[ins.mAddress + 1] = -1;
}
else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y)
{
}
else
{
if (ins.RequiresXReg())
{
for (int i = 1; i < 256; i++)
if (i != xreg)
xregs[i] = -1;
}
if (ins.RequiresYReg())
{
for (int i = 1; i < 256; i++)
if (i != yreg)
yregs[i] = -1;
}
if (ins.ChangesXReg())
xregs[0] = -1;
if (ins.ChangesYReg())
yregs[0] = -1;
}
}
if (xregs[0] >= 0 || yregs[0] >= 0)
{
if (mTrueJump)
mTrueJump->GlobalRegisterXYCheck(xregs, yregs);
if (mFalseJump)
mFalseJump->GlobalRegisterXYCheck(xregs, yregs);
}
}
}
bool NativeCodeBasicBlock::RemapZeroPage(const uint8* remap)
{
bool modified = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
int addr;
switch (mIns[i].mMode)
{
case ASMIM_ZERO_PAGE:
case ASMIM_INDIRECT_Y:
addr = remap[mIns[i].mAddress];
if (addr != mIns[i].mAddress)
{
mIns[i].mAddress = addr;
modified = true;
}
break;
case ASMIM_ABSOLUTE:
if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
{
LinkerObject* lo = mIns[i].mLinkerObject;
for (int j = 0; j < lo->mNumTemporaries; j++)
{
addr = remap[lo->mTemporaries[j]];
if (addr != lo->mTemporaries[j])
{
lo->mTemporaries[j] = addr;
modified = true;
}
}
if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
mIns[i].mParam = remap[mIns[i].mParam];
}
break;
}
}
if (mTrueJump && mTrueJump->RemapZeroPage(remap))
modified = true;
if (mFalseJump && mFalseJump->RemapZeroPage(remap))
modified = true;
}
return modified;
}
bool NativeCodeBasicBlock::SameTail(const NativeCodeInstruction& ins) const
{
if (mIns.Size() > 0)
return mIns[mIns.Size() - 1].IsSame(ins);
else
return false;
}
bool NativeCodeBasicBlock::HasTailSTAX16(int& addr, int& index) const
{
int sz = mIns.Size();
if (sz >= 4)
{
sz -= 4;
if (mIns[sz + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[sz + 0].mMode) &&
mIns[sz + 1].mType == ASMIT_STA && mIns[sz + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[sz + 2].mType == ASMIT_LDA &&
mIns[sz + 3].mType == ASMIT_STA && mIns[sz + 3].mMode == ASMIM_ZERO_PAGE && mIns[sz + 3].mAddress == mIns[sz + 1].mAddress + 1 &&
!mIns[sz + 1].SameEffectiveAddress(mIns[sz + 2]))
{
addr = mIns[sz + 1].mAddress;
index = sz;
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::HasTailSTA(int& addr, int& index) const
{
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesAccu())
return false;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
index = i;
addr = mIns[i].mAddress;
i++;
while (i < mIns.Size())
{
if (mIns[i].ReferencesZeroPage(addr))
return false;
i++;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::HasTailSTX(int& addr, int& index) const
{
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesXReg())
return false;
if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
index = i;
addr = mIns[i].mAddress;
i++;
while (i < mIns.Size())
{
if (mIns[i].ReferencesZeroPage(addr))
return false;
i++;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::HasTailSTY(int& addr, int& index) const
{
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesYReg())
return false;
if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
index = i;
addr = mIns[i].mAddress;
i++;
while (i < mIns.Size())
{
if (mIns[i].ReferencesZeroPage(addr))
return false;
i++;
}
return true;
}
}
return false;
}
void NativeCodeBasicBlock::AddEntryBlock(NativeCodeBasicBlock* block)
{
assert(mEntryBlocks.Size() == mNumEntries);
int i = mEntryBlocks.IndexOf(block);
assert(i < 0);
mEntryBlocks.Push(block);
mNumEntries++;
}
void NativeCodeBasicBlock::RemEntryBlock(NativeCodeBasicBlock* block)
{
assert(mEntryBlocks.Size() == mNumEntries);
int i = mEntryBlocks.IndexOf(block);
assert(i >= 0);
mEntryBlocks.Remove(i);
mNumEntries--;
}
NativeCodeBasicBlock * NativeCodeBasicBlock::SplitMatchingTails(NativeCodeProcedure* proc)
{
NativeCodeBasicBlock* nblock = nullptr;
for (int i = 0; i < mEntryBlocks.Size() - 1; i++)
{
NativeCodeBasicBlock* bi(mEntryBlocks[i]);
if (bi->mBranch == ASMIT_JMP && bi->mIns.Size() > 0)
{
for (int j = i + 1; j < mEntryBlocks.Size(); j++)
{
NativeCodeBasicBlock* bj(mEntryBlocks[j]);
if (bj->mBranch == ASMIT_JMP && bj->mIns.Size() > 0)
{
if (bi->mIns[bi->mIns.Size() - 1].IsSame(bj->mIns[bj->mIns.Size() - 1])/* &&
bi->mIns[bi->mIns.Size() - 2].IsSame(bj->mIns[bj->mIns.Size() - 2])*/)
{
if (!nblock)
{
nblock = proc->AllocateBlock();
nblock->mBranch = ASMIT_JMP;
nblock->mVisited = false;
nblock->mTrueJump = this;
nblock->mEntryBlocks.Push(bi);
nblock->mNumEntries++;
nblock->mEntryRequiredRegs = mEntryRequiredRegs;
nblock->mExitRequiredRegs = mEntryRequiredRegs;
bi->mTrueJump = nblock;
mEntryBlocks[i] = nullptr;
mNumEntries--;
}
nblock->mEntryBlocks.Push(bj);
nblock->mNumEntries++;
bj->mTrueJump = nblock;
mEntryBlocks[j] = nullptr;
mNumEntries--;
}
}
}
if (nblock)
{
int i = 0;
while (i < mEntryBlocks.Size())
{
if (mEntryBlocks[i])
i++;
else
mEntryBlocks.Remove(i);
}
mEntryBlocks.Push(nblock);
mNumEntries++;
return nblock;
}
}
}
return nullptr;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::AddDominatorBlock(NativeCodeProcedure* proc, NativeCodeBasicBlock* pblock)
{
if (pblock->mFalseJump)
{
NativeCodeBasicBlock* tblock = proc->AllocateBlock();
tblock->mBranch = ASMIT_JMP;
tblock->mTrueJump = this;
tblock->mEntryBlocks.Push(pblock);
mEntryBlocks[mEntryBlocks.IndexOf(pblock)] = tblock;
tblock->mEntryRequiredRegs = mEntryRequiredRegs;
tblock->mExitRequiredRegs = mEntryRequiredRegs;
if (pblock->mTrueJump == this)
pblock->mTrueJump = tblock;
if (pblock->mFalseJump == this)
pblock->mFalseJump = tblock;
return tblock;
}
else
return pblock;
}
static bool ReferencedOnPath(const NativeCodeBasicBlock* block, int start, int end, int address)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ReferencesZeroPage(address))
return true;
return false;
}
static bool ChangedOnPath(const NativeCodeBasicBlock* block, int start, int end, int address)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ChangesZeroPage(address))
return true;
return false;
}
static bool ChangesAccuOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ChangesAccu())
return true;
return false;
}
static bool ReferencedsRegOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ReferencesYReg())
return true;
return false;
}
void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins)
{
mIns.Insert(0, ins);
if (mEntryRequiredRegs[CPU_REG_A])
mIns[0].mLive |= LIVE_CPU_REG_A;
if (mEntryRequiredRegs[CPU_REG_X])
mIns[0].mLive |= LIVE_CPU_REG_X;
if (mEntryRequiredRegs[CPU_REG_Y])
mIns[0].mLive |= LIVE_CPU_REG_Y;
if (mEntryRequiredRegs[CPU_REG_C])
mIns[0].mLive |= LIVE_CPU_REG_C;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.UsesAddress())
mEntryRequiredRegs += ins.mAddress;
}
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::ShortcutORACascade(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (mTrueJump && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
{
NativeCodeBasicBlock* block;
if (mBranch == ASMIT_BEQ)
block = mFalseJump;
else
block = mTrueJump;
int sz = mIns.Size();
if (sz > 0 && (block->mBranch == ASMIT_BEQ || block->mBranch == ASMIT_BNE))
{
NativeCodeBasicBlock* nblock;
if (block->mBranch == ASMIT_BEQ)
nblock = block->mFalseJump;
else
nblock = block->mTrueJump;
if (!nblock->mEntryRequiredRegs[CPU_REG_A])
{
if (mIns[sz - 1].ChangesAccuAndFlag())
{
int j = 0;
while (j < block->mIns.Size() && block->mIns[j].mType == ASMIT_ORA)
j++;
if (j == block->mIns.Size())
{
block->RemEntryBlock(this);
nblock->AddEntryBlock(this);
if (mBranch == ASMIT_BEQ)
mFalseJump = nblock;
else
mTrueJump = nblock;
changed = true;
}
}
else if (mIns[sz - 1].IsShiftOrInc() && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
{
if (!block->ChangesZeroPage(mIns[sz - 1].mAddress))
{
int j = block->mIns.Size();
while (j > 0 && block->mIns[j - 1].mType == ASMIT_ORA)
j--;
if (j > 0 && (block->mIns[j - 1].mType == ASMIT_LDA || block->mIns[j - 1].mType == ASMIT_TXA || block->mIns[j - 1].mType == ASMIT_TYA))
j--;
if (j == 0)
{
while (j < block->mIns.Size() && !block->mIns[j].SameEffectiveAddress(mIns[sz - 1]))
j++;
if (j < block->mIns.Size())
{
NativeCodeBasicBlock* nblock;
if (block->mBranch == ASMIT_BEQ)
nblock = block->mFalseJump;
else
nblock = block->mTrueJump;
block->RemEntryBlock(this);
nblock->AddEntryBlock(this);
if (mBranch == ASMIT_BEQ)
mFalseJump = nblock;
else
mTrueJump = nblock;
changed = true;
}
}
}
}
}
}
}
if (mTrueJump && mTrueJump->ShortcutORACascade())
changed = true;
if (mFalseJump && mFalseJump->ShortcutORACascade())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PropagateSinglePath(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
#if 1
if (mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{
mTempRegs.Reset(mTrueJump->mEntryRequiredRegs.Size());
for (int i = mIns.Size() - 1; i >= 0; i--)
{
NativeCodeInstruction ins(mIns[i]);
if (ins.mMode == ASMIM_ZERO_PAGE)
{
int addr = ins.mAddress;
if (!mTempRegs[addr])
{
if (ins.IsShiftOrInc() && !(ins.ChangesCarry() && (ins.mLive & LIVE_CPU_REG_C)) && !(ins.mLive & LIVE_CPU_REG_Z))
{
if (mTrueJump->mEntryRequiredRegs[addr] && !mFalseJump->mEntryRequiredRegs[addr] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && !mTrueJump->mEntryRequiredRegs[CPU_REG_C] ||
mFalseJump->mEntryRequiredRegs[addr] && !mTrueJump->mEntryRequiredRegs[addr] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
{
if (mTrueJump->mEntryRequiredRegs[addr])
mTrueJump->PrependInstruction(mIns[i]);
else
mFalseJump->PrependInstruction(mIns[i]);
mIns.Remove(i);
}
}
else
mTempRegs += addr;
}
}
else if (ins.mMode == ASMIM_INDIRECT_Y)
{
mTempRegs += ins.mAddress;
mTempRegs += ins.mAddress + 1;
}
else if (ins.mType == ASMIT_JSR)
break;
}
}
#endif
#if 1
if (mTrueJump && mFalseJump && mTrueJump->mEntryProvidedRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] ||
mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
int i = mIns.Size();
while (i > 0 && !mIns[i - 1].ReferencesAccu())
i--;
if (i > 0 && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_ORA || mIns[i - 1].mType == ASMIT_AND || mIns[i - 1].mType == ASMIT_EOR) && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
{
if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
mExitRequiredRegs += mIns[i - 1].mAddress;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->PrependInstruction(mIns[i - 1]);
else
mFalseJump->PrependInstruction(mIns[i - 1]);
mIns.Remove(i - 1);
changed = true;
}
}
int sz = mIns.Size();
if (sz > 1 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 2].IsShiftOrInc() && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 2]))
{
mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_CPU_REG_Z;
if (mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
mExitRequiredRegs += mIns[sz - 1].mAddress;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->PrependInstruction(mIns[sz - 1]);
else
mFalseJump->PrependInstruction(mIns[sz - 1]);
mIns.Remove(sz - 1);
changed = true;
}
else if (sz > 1 && mIns[sz - 1].mType == ASMIT_ASL && mIns[sz - 1].mMode == ASMIM_IMPLIED && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C] && mIns[sz - 2].ChangesAccuAndFlag())
{
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BPL;
else
mBranch = ASMIT_BMI;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->PrependInstruction(mIns[sz - 1]);
else
mFalseJump->PrependInstruction(mIns[sz - 1]);
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns.Remove(sz - 1);
changed = true;
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z]||
mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
int i = mIns.Size();
while (i > 0 && !mIns[i - 1].ReferencesXReg())
i--;
if (i > 0 && mIns[i - 1].mType == ASMIT_LDX && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
{
if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
mExitRequiredRegs += mIns[i - 1].mAddress;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_X])
mTrueJump->PrependInstruction(mIns[i - 1]);
else
mFalseJump->PrependInstruction(mIns[i - 1]);
mIns.Remove(i - 1);
changed = true;
}
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] ||
mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
int i = mIns.Size();
while (i > 0 && !mIns[i - 1].ReferencesYReg())
i--;
if (i > 0 && mIns[i - 1].mType == ASMIT_LDY && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
{
if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
mExitRequiredRegs += mIns[i - 1].mAddress;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
mTrueJump->PrependInstruction(mIns[i - 1]);
else
mFalseJump->PrependInstruction(mIns[i - 1]);
mIns.Remove(i - 1);
changed = true;
}
}
else if (i > 0 && mIns[i - 1].mType == ASMIT_TAY && !(mIns[i - 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)) && !ChangesAccuOnPath(this, i, mIns.Size()))
{
mExitRequiredRegs += CPU_REG_A;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
{
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->PrependInstruction(mIns[i - 1]);
}
else
{
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mFalseJump->PrependInstruction(mIns[i - 1]);
}
mIns.Remove(i - 1);
changed = true;
}
}
if (mTrueJump->mNumEntries == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TAX && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
int sz = mIns.Size();
if (sz >= 2 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 2].mMode) && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode))
{
mIns[sz - 2].mType = ASMIT_LDX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X;
mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mTrueJump->mIns[0].mType = ASMIT_NOP;
changed = true;
}
}
}
#endif
if (mTrueJump && mFalseJump && mExitRequiredRegs.Size())
{
uint32 live = 0;
if (mExitRequiredRegs[CPU_REG_X])
live |= LIVE_CPU_REG_X;
if (mExitRequiredRegs[CPU_REG_Y])
live |= LIVE_CPU_REG_Y;
if (mExitRequiredRegs[CPU_REG_C])
live |= LIVE_CPU_REG_C;
int i = 0;
while (i < mIns.Size())
{
#if 1
if (!mExitRequiredRegs[CPU_REG_A] &&
i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
if (!ReferencedOnPath(this, i + 2, mIns.Size(), mIns[i + 1].mAddress) &&
!ChangedOnPath(this, i + 2, mIns.Size(), mIns[i + 0].mAddress))
{
if (mTrueJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
!mFalseJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
{
for (int j = 0; j < 2; j++)
{
mIns[i + j].mLive |= live;
mTrueJump->mIns.Insert(j, mIns[i + j]);
}
mIns.Remove(i + 1);
changed = true;
continue;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
!mTrueJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
for (int j = 0; j < 2; j++)
{
mIns[i + j].mLive |= live;
mFalseJump->mIns.Insert(j, mIns[i + j]);
}
mIns.Remove(i + 1);
changed = true;
continue;
}
}
}
#endif
#if 1
if (!mExitRequiredRegs[CPU_REG_A] &&
i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 3].mAddress) &&
!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 6].mAddress) &&
!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 1].mAddress) &&
!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 2].mAddress) &&
!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 4].mAddress))
{
if (mTrueJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && mTrueJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mFalseJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mTrueJump->mEntryRequiredRegs[CPU_REG_C] &&
mTrueJump->mNumEntries == 1)
{
mTrueJump->mEntryRequiredRegs += mIns[i + 1].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[i + 2].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[i + 4].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[i + 5].mAddress;
for (int j = 0; j < 7; j++)
{
mIns[i].mLive |= live;
mTrueJump->mIns.Insert(j, mIns[i]);
mIns.Remove(i);
}
changed = true;
continue;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && mFalseJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mTrueJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mFalseJump->mEntryRequiredRegs[CPU_REG_C] &&
mFalseJump->mNumEntries == 1)
{
mFalseJump->mEntryRequiredRegs += mIns[i + 1].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[i + 2].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[i + 4].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[i + 5].mAddress;
for (int j = 0; j < 7; j++)
{
mIns[i].mLive |= live;
mFalseJump->mIns.Insert(j, mIns[i]);
mIns.Remove(i);
}
changed = true;
continue;
}
}
}
#endif
#if 1
if (!mExitRequiredRegs[CPU_REG_A] &&
i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 3].mAddress) &&
!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 6].mAddress) &&
!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 1].mAddress) &&
!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 4].mAddress))
{
if (mTrueJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && mTrueJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mFalseJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mTrueJump->mEntryRequiredRegs[CPU_REG_C] &&
mTrueJump->mNumEntries == 1)
{
mTrueJump->mEntryRequiredRegs += mIns[i + 1].mAddress;
mTrueJump->mEntryRequiredRegs += mIns[i + 4].mAddress;
for (int j = 0; j < 7; j++)
{
mIns[i].mLive |= live;
mTrueJump->mIns.Insert(j, mIns[i]);
mIns.Remove(i);
}
changed = true;
continue;
}
else if (mFalseJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && mFalseJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mTrueJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
!mFalseJump->mEntryRequiredRegs[CPU_REG_C] &&
mFalseJump->mNumEntries == 1)
{
mFalseJump->mEntryRequiredRegs += mIns[i + 1].mAddress;
mFalseJump->mEntryRequiredRegs += mIns[i + 4].mAddress;
for (int j = 0; j < 7; j++)
{
mIns[i].mLive |= live;
mFalseJump->mIns.Insert(j, mIns[i]);
mIns.Remove(i);
}
changed = true;
continue;
}
}
}
#endif
i++;
}
}
if (mTrueJump && mTrueJump->PropagateSinglePath())
changed = true;
if (mFalseJump && mFalseJump->PropagateSinglePath())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Is16BitAddSubImmediate(int at, int& sreg, int& dreg, int& offset) const
{
if (mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress == mIns[at + 3].mAddress + 1 &&
!(mIns[at + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
sreg = mIns[at + 1].mAddress;
dreg = mIns[at + 3].mAddress;
offset = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
return true;
}
return false;
}
bool NativeCodeBasicBlock::CanForward16BitAddSubImmediate(int sreg, int dreg, int offset, int& index) const
{
int i = mIns.Size() - 1;
while (i >= 6)
{
int asreg, adreg, aoffset;
if (Is16BitAddSubImmediate(i - 6, asreg, adreg, aoffset) && asreg == sreg && adreg == dreg && aoffset == offset)
{
index = i - 6;
return true;
}
if (mIns[i].ReferencesZeroPage(dreg) || mIns[i].ReferencesZeroPage(dreg + 1) || mIns[i].ChangesZeroPage(sreg) || mIns[i].ChangesZeroPage(sreg + 1))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::CanForwardLoadStore(const NativeCodeInstruction& lins, const NativeCodeInstruction& sins, int& index) const
{
int i = mIns.Size() - 1;
while (i > 0)
{
if (lins.MayBeChangedOnAddress(mIns[i]))
return false;
if (mIns[i].MayBeSameAddress(sins))
{
index = i - 1;
if (mIns[i].mType == ASMIT_STA && mIns[i - 1].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_A) ||
mIns[i].mType == ASMIT_STX && mIns[i - 1].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_X) ||
mIns[i].mType == ASMIT_STY && mIns[i - 1].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
{
if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && mIns[i].SameEffectiveAddress(sins) && mIns[i - 1].SameEffectiveAddress(lins))
return true;
}
return false;
}
if (mIns[i].mType == ASMIT_JSR)
return false;
if (sins.MayBeChangedOnAddress(mIns[i]) || mIns[i].MayBeChangedOnAddress(sins))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::CanForwardZPMove(int saddr, int daddr, int & index) const
{
int i = mIns.Size() - 1;
while (i > 0)
{
if (mIns[i].ChangesZeroPage(saddr))
return false;
if (mIns[i].ChangesZeroPage(daddr))
{
index = i - 1;
return
(mIns[i].mType == ASMIT_STA && mIns[i - 1].mType == ASMIT_LDA && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == saddr && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
(mIns[i].mType == ASMIT_STX && mIns[i - 1].mType == ASMIT_LDX && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == saddr && !(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)));
}
if (mIns[i].ReferencesZeroPage(daddr))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::CheckShortcutPointerAddForward(int at)
{
int i = at + 6;
while (i < mIns.Size())
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress)
{
if (!(mIns[i].mLive & LIVE_MEM))
{
mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
mIns[at + 5].mAddress = mIns[at + 4].mAddress; mIns[at + 4].mLive |= LIVE_MEM;
for (int j = at + 6; j <= i; j++)
{
if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 1].mAddress)
mIns[j].mAddress = mIns[at + 0].mAddress;
}
return true;
}
}
else if (mIns[i].ChangesZeroPage(mIns[at + 0].mAddress) ||
mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress) ||
mIns[i].ReferencesZeroPage(mIns[at + 4].mAddress) ||
mIns[i].ReferencesZeroPage(mIns[at + 5].mAddress))
return false;
i++;
}
return false;
}
bool NativeCodeBasicBlock::ShortcutPointerAddForward(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 6 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress + 1 && !(mIns[i + 4].mLive & LIVE_MEM) &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
{
if (CheckShortcutPointerAddForward(i))
changed = true;
}
}
if (mTrueJump && mTrueJump->ShortcutPointerAddForward())
changed = true;
if (mFalseJump && mFalseJump->ShortcutPointerAddForward())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::MoveIndirectLoadZeroStoreDown(int at)
{
int yval = mIns[at].mAddress;
for (int i = at + 3; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at + 2].mAddress)
{
if (mIns[i].mLive & LIVE_CPU_REG_Y)
return false;
mIns.Insert(i, mIns[at]);
mIns.Insert(i + 1, mIns[at + 1]);
mIns[i + 2].mType = ASMIT_STA;
mIns[i].mLive |= mIns[i + 2].mLive;
mIns[i + 1].mLive |= mIns[i + 2].mLive;
mIns.Remove(at + 1, 2);
return true;
}
if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1) || mIns[i].ReferencesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[i].mType == ASMIT_JSR)
return false;
if (mIns[i].ChangesAddress())
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress)
{
if (yval == -1 || yval == mIns[at].mAddress)
return false;
}
else if (mIns[at + 1].MayBeChangedOnAddress(mIns[i]))
return false;
}
if (mIns[i].ChangesYReg())
{
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
yval = mIns[i].mAddress;
else if (mIns[i].mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (mIns[i].mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else
yval = -1;
}
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadZeroStoreIndirectUp(int at)
{
int i = at - 1;
while (i >= 0 && !(mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress))
i--;
if (i >= 0 && mIns[i].mType == ASMIT_STA && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y)))
{
int yval = -1;
for (int j = i + 1; j < at; j++)
{
if (mIns[j].mType == ASMIT_JSR)
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1))
return false;
if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress)
{
if (yval == -1 || yval == mIns[at + 1].mAddress)
return false;
}
else if (mIns[j].MayBeSameAddress(mIns[at + 2]))
return false;
if (mIns[j].ChangesYReg())
{
if (mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE)
yval = mIns[j].mAddress;
else if (mIns[j].mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (mIns[j].mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else
yval = -1;
}
}
NativeCodeInstruction i0 = mIns[at + 1], i1 = mIns[at + 2];
mIns.Remove(at + 1, 2);
mIns.Insert(i + 1, i0);
mIns.Insert(i + 2, i1);
mIns[i].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= mIns[i].mLive;
mIns[i + 2].mLive |= mIns[i].mLive;
return true;
}
return false;
}
bool NativeCodeBasicBlock::ShortcutIndirectLoadStore(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
mIns[i + 2].mAddress != mIns[i + 1].mAddress && mIns[i + 2].mAddress != mIns[i + 1].mAddress + 1)
{
if (MoveIndirectLoadZeroStoreDown(i))
changed = true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (MoveLoadZeroStoreIndirectUp(i))
changed = true;
}
}
if (mTrueJump && mTrueJump->ShortcutIndirectLoadStore())
changed = true;
if (mFalseJump && mFalseJump->ShortcutIndirectLoadStore())
changed = true;
}
return changed;
}
#if 0
static int NativeCodeExpressionID;
struct NativeCodeExpression
{
int mIndex;
AsmInsType mType;
NativeCodeInstruction * mIns;
int mLeft, mRight;
int mReg;
NativeCodeExpression(AsmInsType type, NativeCodeInstruction* ins)
: mIndex(NativeCodeExpressionID++), mType(type), mIns(ins), mLeft(-1), mRight(-1), mReg(-1)
{
}
NativeCodeExpression(AsmInsType type, int left, int right)
: mIndex(NativeCodeExpressionID++), mType(type), mIns(nullptr), mLeft(left), mRight(right), mReg(reg)
{
}
};
struct NativeCodeExpressions
{
ExpandingArray<NativeCodeExpression> mExps;
void KillReg(int reg);
void KillYReg(void);
void KillXReg(void);
void KillAddr(const NativeCodeInstruction& ins);
int AddLoad(const NativeCodeInstruction& ins);
};
void NativeCodeExpressions::KillReg(int reg)
{
int i = 0;
while (i < mExps.Size())
{
if (mExps[i].mReg == reg)
mExps.Remove(i);
else if (mExps[i].mIns)
{
if (reg == CPU_REG_Y && mExps[i].mIns->RequiresYReg())
mExps.Remove(i);
else if (reg == CPU_REG_X && mExps[i].mIns->RequiresXReg())
mExps.Remove(i);
else if (mExps[i].mIns->ReferencesZeroPage(reg))
mExps.Remove(i);
else
i++;
}
else
i++;
}
}
void NativeCodeExpressions::KillYReg(void)
{
int i = 0;
while (i < mExps.Size())
{
if (mExps[i].mIns && mExps[i].mIns->RequiresYReg())
mExps.Remove(i);
else
i++;
}
}
void NativeCodeExpressions::KillAddr(const NativeCodeInstruction& ins)
{
int i = 0;
while (i < mExps.Size())
{
if (mExps[i].mIns && mExps[i].mIns->MayBeChangedOnAddress(ins))
mExps.Remove(i);
else
i++;
}
}
int NativeCodeExpressions::AddLoad(const NativeCodeInstruction& ins)
{
int i = 0;
while (i < mExps.Size() && !(mExps[i].mType == ASMIT_LDA && mExps[i].mIns->SameAddress(ins))
i++;
if (i < mExps.Size())
return mExps[i].mIndex;
else
{
NativeCodeExpressions e(ASMIT_LDA, &ins);
mExps.Push(e);
return e.mIndex;
}
}
bool NativeCodeBasicBlock::CommonSubExpressionElimination(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
NativeCodeExpressions exps;
int aexp = -1, xexp = -1, yexp = -1;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
switch (ins.mType)
{
case ASMIT_LDA:
aexp = exps.AddLoad(ins);
break;
case ASMIT_LDX:
aexp = exps.AddLoad(ins);
break;
case ASMIT_LDY:
aexp = exps.AddLoad(ins);
break;
}
}
if (mTrueJump && mTrueJump->CommonSubExpressionElimination())
changed = true;
if (mFalseJump && mFalseJump->CommonSubExpressionElimination())
changed = true;
}
return changed;
}
#endif
bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock* nblock, const NativeCodeBasicBlock* fblock) const
{
if (mExitRequiredRegs[CPU_REG_X])
return false;
if (mTrueJump && mTrueJump != nblock && mTrueJump != fblock && mTrueJump->mEntryRequiredRegs[addr])
return false;
if (mFalseJump && mFalseJump != nblock && mFalseJump != fblock && mFalseJump->mEntryRequiredRegs[addr])
return false;
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesXReg())
return false;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return true;
if (mIns[i].ReferencesZeroPage(addr) || mIns[i].RequiresXReg())
return false;
}
if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->CanChangeTailZPStoreToX(addr, this);
else
return false;
}
void NativeCodeBasicBlock::ChangeTailZPStoreToX(int addr)
{
mExitRequiredRegs += CPU_REG_X;
int i = mIns.Size();
while (i > 0)
{
i--;
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
mIns[i].mType = ASMIT_TAX;
mIns[i].mMode = ASMIM_IMPLIED;
return;
}
}
if (mEntryBlocks.Size() == 1)
{
mEntryBlocks[0]->ChangeTailZPStoreToX(addr);
return;
}
assert(false);
}
bool NativeCodeBasicBlock::CanChangeTailZPStoreToY(int addr, const NativeCodeBasicBlock* nblock, const NativeCodeBasicBlock* fblock) const
{
if (mExitRequiredRegs[CPU_REG_Y])
return false;
if (mTrueJump && mTrueJump != nblock && mTrueJump != fblock && mTrueJump->mEntryRequiredRegs[addr])
return false;
if (mFalseJump && mFalseJump != nblock && mFalseJump != fblock && mFalseJump->mEntryRequiredRegs[addr])
return false;
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesYReg())
return false;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return true;
if (mIns[i].ReferencesZeroPage(addr) || mIns[i].RequiresYReg())
return false;
}
if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->CanChangeTailZPStoreToY(addr, this);
else
return false;
}
void NativeCodeBasicBlock::ChangeTailZPStoreToY(int addr)
{
mExitRequiredRegs += CPU_REG_Y;
int i = mIns.Size();
while (i > 0)
{
i--;
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
return;
}
}
if (mEntryBlocks.Size() == 1)
{
mEntryBlocks[0]->ChangeTailZPStoreToY(addr);
return;
}
assert(false);
}
bool NativeCodeBasicBlock::IsExitYRegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
int i = mIns.Size() - 1;
while (i >= 0)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_LDY))
{
if (addr == mIns[i].mAddress)
{
block = this;
index = i;
return true;
}
return false;
}
else if (mIns[i].ChangesYReg())
return false;
else if (mIns[i].ChangesZeroPage(addr))
return false;
i--;
}
if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->IsExitYRegZP(addr, index, block);
return false;
}
bool NativeCodeBasicBlock::IsExitXRegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
int i = mIns.Size() - 1;
while (i >= 0)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_LDX))
{
if (addr == mIns[i].mAddress)
{
block = this;
index = i;
return true;
}
return false;
}
else if (mIns[i].ChangesXReg())
return false;
else if (mIns[i].ChangesZeroPage(addr))
return false;
i--;
}
if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->IsExitXRegZP(addr, index, block);
return false;
}
bool NativeCodeBasicBlock::IsExitARegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
int i = mIns.Size() - 1;
while (i >= 0)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA))
{
if (addr == mIns[i].mAddress)
{
block = this;
index = i;
return true;
}
return false;
}
else if (mIns[i].ChangesAccu())
return false;
else if (mIns[i].ChangesZeroPage(addr))
return false;
i--;
}
if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->IsExitARegZP(addr, index, block);
return false;
}
void NativeCodeBasicBlock::MarkLiveBlockChain(int index, NativeCodeBasicBlock* block, uint32 live, uint32 reg)
{
mExitRequiredRegs += reg;
if (this == block)
{
for (int i = index; i < mIns.Size(); i++)
mIns[i].mLive |= live;
}
else
{
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= live;
mEntryRequiredRegs += reg;
mEntryBlocks[0]->MarkLiveBlockChain(index, block, live, reg);
}
}
bool NativeCodeBasicBlock::CanJoinEntryLoadStoreZP(int saddr, int daddr)
{
mChecked = true;
// Avoid moving code into loops
if (mLoopHead && (mTrueJump == this || mFalseJump == this))
return false;
if (mFalseJump && mExitRequiredRegs[daddr])
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction & ins = mIns[at];
if (ins.ReferencesZeroPage(daddr))
return false;
if (ins.ChangesZeroPage(saddr))
{
if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY)
return true;
else
return false;
}
at--;
}
if (!mLoopHead && mEntryBlocks.Size() > 0 && daddr >= BC_REG_FPARAMS && daddr < BC_REG_FPARAMS_END)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (!mEntryBlocks[i]->CanJoinEntryLoadStoreZP(saddr, daddr))
return false;
}
return true;
}
return false;
}
bool NativeCodeBasicBlock::DoJoinEntryLoadStoreZP(int saddr, int daddr)
{
if (!mChecked)
return true;
mChecked = false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins = mIns[at];
if (ins.ChangesZeroPage(saddr))
{
if (ins.mType == ASMIT_STA)
{
ins.mLive |= LIVE_CPU_REG_A;
mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STA, ASMIM_ZERO_PAGE, daddr));
mExitRequiredRegs += daddr;
return true;
}
else if (ins.mType == ASMIT_STX)
{
ins.mLive |= LIVE_CPU_REG_X;
mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STX, ASMIM_ZERO_PAGE, daddr));
mExitRequiredRegs += daddr;
return true;
}
else if (ins.mType == ASMIT_STY)
{
ins.mLive |= LIVE_CPU_REG_Y;
mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STY, ASMIM_ZERO_PAGE, daddr));
mExitRequiredRegs += daddr;
return true;
}
}
at--;
}
if (!mLoopHead)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (!mEntryBlocks[i]->DoJoinEntryLoadStoreZP(saddr, daddr))
return false;
}
mEntryRequiredRegs += daddr;
mExitRequiredRegs += daddr;
return true;
}
return false;
}
bool NativeCodeBasicBlock::JoinEntryLoadStoreZP(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (!mLoopHead && mEntryBlocks.Size() < 64 && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
{
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) ||
mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
int saddr = mIns[i].mAddress, daddr = mIns[i + 1].mAddress;
if (!ReferencesZeroPage(saddr, 0, i) && !ReferencesZeroPage(daddr, 0, i))
{
int n = 0;
uint64 mask = 0;
for (int j = 0; j < mEntryBlocks.Size(); j++)
{
if (mEntryBlocks[j]->CanJoinEntryLoadStoreZP(saddr, daddr))
{
mask |= 1ull << j;
n++;
}
}
if (n == mEntryBlocks.Size())
{
for (int j = 0; j < mEntryBlocks.Size(); j++)
{
mEntryBlocks[j]->DoJoinEntryLoadStoreZP(saddr, daddr);
mEntryBlocks[j]->mExitRequiredRegs += daddr;
}
mEntryRequiredRegs += daddr;
changed = true;
mIns.Remove(i, 2);
i--;
}
else if (n >= 2)
{
NativeCodeBasicBlock* xblock = mProc->AllocateBlock();
int j = mEntryBlocks.Size();
while (j > 0)
{
j--;
NativeCodeBasicBlock* eb = mEntryBlocks[j];
if (mask & (1ull << j))
{
eb->DoJoinEntryLoadStoreZP(saddr, daddr);
eb->mExitRequiredRegs += daddr;
}
else
{
if (eb->mTrueJump == this)
eb->mTrueJump = xblock;
if (eb->mFalseJump == this)
eb->mFalseJump = xblock;
mEntryBlocks.Remove(j);
xblock->mEntryBlocks.Push(eb);
xblock->mNumEntries++;
}
}
xblock->mEntryRequiredRegs = mEntryRequiredRegs;
xblock->mExitRequiredRegs = mEntryRequiredRegs;
xblock->mExitRequiredRegs += daddr;
if (!mEntryRequiredRegs[CPU_REG_A])
{
xblock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
xblock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
else
{
xblock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
xblock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
xblock->Close(mIns[i].mIns, this, nullptr, ASMIT_JMP);
mEntryBlocks.Push(xblock);
mNumEntries++;
mEntryRequiredRegs += daddr;
changed = true;
mIns.Remove(i, 2);
i--;
}
}
}
}
}
if (mTrueJump && mTrueJump->JoinEntryLoadStoreZP())
changed = true;
if (mFalseJump && mFalseJump->JoinEntryLoadStoreZP())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool loops)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (mTrueJump) mTrueJump->CheckLive();
if (mFalseJump) mFalseJump->CheckLive();
#if 1
if (mEntryBlocks.Size() > 1)
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mBranch == ASMIT_JMP)
i++;
if (i == mEntryBlocks.Size())
{
NativeCodeBasicBlock* eb = mEntryBlocks[0];
if (mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && !mEntryRequiredRegs[CPU_REG_C])
{
for (int i = eb->mIns.Size() - 7; i >= 0; i--)
{
int sreg, dreg, offset;
if (eb->Is16BitAddSubImmediate(i, sreg, dreg, offset))
{
int j = 0;
while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForward16BitAddSubImmediate(sreg, dreg, offset, mEntryBlocks[j]->mTemp))
j++;
if (j == mEntryBlocks.Size())
{
for (int k = 0; k < 7; k++)
mIns.Insert(k, eb->mIns[i + k]);
for (int j = 0; j < mEntryBlocks.Size(); j++)
mEntryBlocks[j]->mIns.Remove(mEntryBlocks[j]->mTemp, 7);
if (mEntryRequiredRegs[CPU_REG_A])
{
mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_TAX));
for (int i = 1; i < 8; i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns.Insert(8, NativeCodeInstruction(mIns[0].mIns, ASMIT_TXA));
}
changed = true;
}
}
}
}
if (changed)
CheckLive();
while (eb->mIns.Size() > 0)
{
int addr, index, taddr, tindex;
if (!mEntryRequiredRegs[CPU_REG_X] && eb->HasTailSTAX16(addr, index))
{
i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTAX16(taddr, tindex) && taddr == addr)
i++;
if (i == mEntryBlocks.Size())
{
mEntryRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_X;
mIns.Insert(0, eb->mIns[index + 3]);
mIns.Insert(0, eb->mIns[index + 1]);
mIns[0].mType = ASMIT_STX;
mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
mIns[1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
b->HasTailSTAX16(taddr, tindex);
b->mExitRequiredRegs += CPU_REG_A;
b->mExitRequiredRegs += CPU_REG_X;
assert(b->mIns[tindex].mMode != ASMIM_ABSOLUTE_X);
b->mIns[tindex + 0].mType = ASMIT_LDX;
for (int j = tindex; j < b->mIns.Size(); j++)
b->mIns[j].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
b->mIns.Remove(tindex + 3);
b->mIns.Remove(tindex + 1);
}
changed = true;
}
}
NativeCodeInstruction& ins(eb->mIns[eb->mIns.Size() - 1]);
i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->SameTail(ins))
i++;
if (i == mEntryBlocks.Size())
{
if (ins.RequiresAccu())
mEntryRequiredRegs += CPU_REG_A;
if (ins.RequiresYReg())
mEntryRequiredRegs += CPU_REG_Y;
if (ins.RequiresXReg())
mEntryRequiredRegs += CPU_REG_X;
if (ins.ChangesZFlag())
mEntryRequiredRegs -= CPU_REG_Z;
if (ins.ChangesCarry())
mEntryRequiredRegs -= CPU_REG_C;
if (ins.RequiresCarry())
mEntryRequiredRegs += CPU_REG_C;
mIns.Insert(0, ins);
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
if (ins.RequiresAccu())
b->mExitRequiredRegs += CPU_REG_A;
if (ins.RequiresYReg())
b->mExitRequiredRegs += CPU_REG_Y;
if (ins.RequiresXReg())
b->mExitRequiredRegs += CPU_REG_X;
if (ins.ChangesZFlag())
b->mExitRequiredRegs -= CPU_REG_Z;
if (ins.ChangesCarry())
b->mExitRequiredRegs -= CPU_REG_C;
if (ins.RequiresCarry())
b->mExitRequiredRegs += CPU_REG_C;
b->mIns.SetSize(b->mIns.Size() - 1);
}
changed = true;
}
else
{
if (eb->HasTailSTA(addr, index))
{
i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTA(taddr, tindex) && taddr == addr)
i++;
if (i == mEntryBlocks.Size())
{
mEntryRequiredRegs += CPU_REG_A;
mIns.Insert(0, eb->mIns[index]);
mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
b->HasTailSTA(taddr, tindex);
b->mExitRequiredRegs += CPU_REG_A;
for (int j = tindex + 1; j < b->mIns.Size(); j++)
b->mIns[j].mLive |= LIVE_CPU_REG_A;
b->mIns.Remove(tindex);
}
changed = true;
}
}
if (eb->HasTailSTX(addr, index))
{
i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTX(taddr, tindex) && taddr == addr)
i++;
if (i == mEntryBlocks.Size())
{
mEntryRequiredRegs += CPU_REG_X;
mIns.Insert(0, eb->mIns[index]);
mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
b->HasTailSTX(taddr, tindex);
b->mExitRequiredRegs += CPU_REG_X;
for (int j = tindex + 1; j < b->mIns.Size(); j++)
b->mIns[j].mLive |= LIVE_CPU_REG_X;
b->mIns.Remove(tindex);
}
changed = true;
}
}
if (eb->HasTailSTY(addr, index))
{
i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTY(taddr, tindex) && taddr == addr)
i++;
if (i == mEntryBlocks.Size())
{
mEntryRequiredRegs += CPU_REG_Y;
mIns.Insert(0, eb->mIns[index]);
mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
b->HasTailSTY(taddr, tindex);
b->mExitRequiredRegs += CPU_REG_Y;
for (int j = tindex + 1; j < b->mIns.Size(); j++)
b->mIns[j].mLive |= LIVE_CPU_REG_Y;
b->mIns.Remove(tindex);
}
changed = true;
}
}
break;
}
}
if (changed)
CheckLive();
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
{
for (int i = eb->mIns.Size() - 1; i > 0; i--)
{
if (eb->mIns[i - 1].mType == ASMIT_LDA && eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && eb->mIns[i - 0].mType == ASMIT_STA && eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE ||
eb->mIns[i - 1].mType == ASMIT_LDX && eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && eb->mIns[i - 0].mType == ASMIT_STX && eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE)
{
int saddr = eb->mIns[i - 1].mAddress, daddr = eb->mIns[i - 0].mAddress;
int j = 0;
while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForwardZPMove(saddr, daddr, mEntryBlocks[j]->mTemp))
j++;
if (j == mEntryBlocks.Size())
{
const InterInstruction* iins(eb->mIns[i].mIns);
if (!mEntryRequiredRegs[CPU_REG_A])
{
mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDA, ASMIM_ZERO_PAGE, saddr));
mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, daddr));
changed = true;
}
else if (!mEntryRequiredRegs[CPU_REG_X])
{
mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, saddr));
mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, daddr));
changed = true;
}
}
}
}
if (changed)
CheckLive();
}
#if 1
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X] || !mEntryRequiredRegs[CPU_REG_Y]))
{
for (int i = eb->mIns.Size() - 1; i > 0; i--)
{
if ((eb->mIns[i - 1].mType == ASMIT_LDA && eb->mIns[i - 0].mType == ASMIT_STA ||
eb->mIns[i - 1].mType == ASMIT_LDX && eb->mIns[i - 0].mType == ASMIT_STX ||
eb->mIns[i - 1].mType == ASMIT_LDY && eb->mIns[i - 0].mType == ASMIT_STY) &&
(eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE || eb->mIns[i - 1].mMode == ASMIM_ABSOLUTE) &&
(eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE || eb->mIns[i - 0].mMode == ASMIM_ABSOLUTE))
{
int j = 0;
while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForwardLoadStore(eb->mIns[i - 1], eb->mIns[i - 0], mEntryBlocks[j]->mTemp))
j++;
if (j == mEntryBlocks.Size())
{
const InterInstruction* iins(eb->mIns[i].mIns);
if (!mEntryRequiredRegs[CPU_REG_A])
{
mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDA, eb->mIns[i - 1]));
mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STA, eb->mIns[i]));
changed = true;
}
else if (!mEntryRequiredRegs[CPU_REG_X])
{
mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDX, eb->mIns[i - 1]));
mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STX, eb->mIns[i]));
changed = true;
}
else if (!mEntryRequiredRegs[CPU_REG_Y])
{
mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDY, eb->mIns[i - 1]));
mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STY, eb->mIns[i]));
changed = true;
}
for (int j = 0; j < mEntryBlocks.Size(); j++)
mEntryBlocks[j]->mIns.Remove(mEntryBlocks[j]->mTemp, 2);
}
}
}
if (changed)
CheckLive();
}
#endif
}
if (mEntryBlocks.Size() >= 1)
{
NativeCodeBasicBlock* eb = mEntryBlocks[0];
if (eb->mIns.Size())
{
NativeCodeInstruction& ins(eb->mIns[eb->mIns.Size() - 1]);
if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE &&
(eb->mBranch == ASMIT_JMP ||
eb->mTrueJump == this && eb->mFalseJump && !eb->mFalseJump->mEntryRequiredRegs[ins.mAddress] ||
eb->mFalseJump == this && eb->mTrueJump && !eb->mTrueJump->mEntryRequiredRegs[ins.mAddress]))
{
int i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().IsSame(ins) &&
(mEntryBlocks[i]->mBranch == ASMIT_JMP ||
mEntryBlocks[i]->mTrueJump == this && mEntryBlocks[i]->mFalseJump && !mEntryBlocks[i]->mFalseJump->mEntryRequiredRegs[ins.mAddress] ||
mEntryBlocks[i]->mFalseJump == this && mEntryBlocks[i]->mTrueJump && !mEntryBlocks[i]->mTrueJump->mEntryRequiredRegs[ins.mAddress]))
i++;
if (i == mEntryBlocks.Size())
{
mEntryRequiredRegs += CPU_REG_A;
mEntryRequiredRegs -= ins.mAddress;
mIns.Insert(0, ins);
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* meb = mEntryBlocks[i];
meb->mExitRequiredRegs += CPU_REG_A;
meb->mIns.SetSize(meb->mIns.Size() - 1);
}
changed = true;
}
}
}
}
CheckLive();
if (mEntryBlocks.Size() > 2)
{
NativeCodeBasicBlock* nblock = SplitMatchingTails(proc);
if (nblock)
{
if (nblock->JoinTailCodeSequences(proc, loops))
changed = true;
}
}
}
#endif
#if 1
if (mEntryBlocks.Size() == 1)
{
NativeCodeBasicBlock* eblock = mEntryBlocks[0];
if (mIns.Size() > 0 && eblock->mIns.Size() > 0)
{
int sz = eblock->mIns.Size();
if (mIns[0].mType == ASMIT_ORA && mIns[0].mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == 0)
{
if (eblock->mIns.Last().ChangesAccuAndFlag() ||
sz >= 2 && !eblock->mIns.Last().ChangesZFlag() && eblock->mIns[sz - 2].ChangesAccuAndFlag())
{
eblock->mExitRequiredRegs += CPU_REG_Z;
mEntryRequiredRegs += CPU_REG_Z;
mIns.Remove(0);
changed = true;
}
}
}
}
#endif
#if 1
if (mTrueJump && mFalseJump && mTrueJump->mTrueJump && !mTrueJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump &&
mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)
{
// TAX, SHL -> .... LDX --> TXA
// \------------->
//
int nins = mIns.Size(), tins = mTrueJump->mIns.Size(), fins = mFalseJump->mIns.Size();
if (nins > 1 && tins > 0 && fins > 0 && mFalseJump->mIns[0].mType == ASMIT_TXA &&
mIns[nins - 2].mType == ASMIT_TAX && !mIns[nins - 1].ChangesAccu() && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
{
mTrueJump->mIns.Push(NativeCodeInstruction(mFalseJump->mIns[0].mIns, ASMIT_TXA));
mFalseJump->mIns[0].mType = ASMIT_NOP; mFalseJump->mIns[0].mMode = ASMIM_IMPLIED;
mIns[nins - 1].mLive |= LIVE_CPU_REG_A;
mIns[nins - 2].mLive |= LIVE_CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->mExitRequiredRegs += CPU_REG_A;
changed = true;
}
}
#endif
CheckLive();
if (mTrueJump && mFalseJump)
{
int addr, index;
if (HasTailSTX(addr, index))
{
if (mTrueJump->mEntryRequiredRegs[addr] && !mFalseJump->mEntryRequiredRegs[addr] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mEntryProvidedRegs += CPU_REG_X;
for (int i = index; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[index].mLive |= mIns[mIns.Size() - 1].mLive;
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mTrueJump->mIns.Insert(0, mIns[index]);
mIns.Remove(index);
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
else if (mFalseJump->mEntryRequiredRegs[addr] && !mTrueJump->mEntryRequiredRegs[addr] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mEntryProvidedRegs += CPU_REG_X;
for (int i = index; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[index].mLive |= mIns[mIns.Size() - 1].mLive;
mExitRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mIns.Insert(0, mIns[index]);
mIns.Remove(index);
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
}
}
#if 1
if (mTrueJump && mFalseJump && mIns.Size() >= 2)
{
int nins = mIns.Size();
if (mIns[nins - 2].mType == ASMIT_LDA && mIns[nins - 2].mMode == ASMIM_IMMEDIATE &&
mIns[nins - 1].mType == ASMIT_CMP && mIns[nins - 1].mMode == ASMIM_ZERO_PAGE && (mIns[nins - 1].mLive & LIVE_MEM) && !(mIns[nins - 1].mLive & LIVE_CPU_REG_A) &&
!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
int im = mIns[nins - 2].mAddress;
mIns[nins - 2].CopyMode(mIns[nins - 1]);
mIns[nins - 2].mLive |= LIVE_MEM;
mIns[nins - 1].mMode = ASMIM_IMMEDIATE;
mIns[nins - 1].mFlags = NCIF_LOWER | NCIF_UPPER;
if (mBranch == ASMIT_BCC)
{
if (im == 255)
{
mIns[nins - 1].mType = ASMIT_SEC;
mIns[nins - 1].mMode = ASMIM_IMPLIED;
}
else
{
mIns[nins - 1].mAddress = im + 1;
mBranch = ASMIT_BCS;
}
}
else if (mBranch == ASMIT_BCS)
{
if (im == 255)
{
mIns[nins - 1].mType = ASMIT_SEC;
mIns[nins - 1].mMode = ASMIM_IMPLIED;
}
else
{
mIns[nins - 1].mAddress = im + 1;
mBranch = ASMIT_BCC;
}
}
else
mIns[nins - 1].mAddress = im;
changed = true;
}
}
#endif
CheckLive();
if (mTrueJump && mFalseJump)
{
if (mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 && !mExitRequiredRegs[CPU_REG_Z] && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
{
if (!mTrueJump->mIns[0].ChangesCarry() && mTrueJump->mIns[0].IsSame(mFalseJump->mIns[0]))
{
int live = mTrueJump->mIns[0].mLive | mFalseJump->mIns[0].mLive;
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C | live;
mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mIns.Remove(0);
mFalseJump->mIns.Remove(0);
if (live & LIVE_CPU_REG_A)
{
mExitRequiredRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
}
if (live & LIVE_CPU_REG_X)
{
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
}
if (live & LIVE_CPU_REG_Y)
{
mExitRequiredRegs += CPU_REG_Y;
mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
}
if (live & LIVE_CPU_REG_Z)
{
mExitRequiredRegs += CPU_REG_Z;
mTrueJump->mEntryRequiredRegs += CPU_REG_Z;
mFalseJump->mEntryRequiredRegs += CPU_REG_Z;
}
changed = true;
CheckLive();
}
}
}
if (mTrueJump) mTrueJump->CheckLive();
if (mFalseJump) mFalseJump->CheckLive();
#if 1
if (loops && mIns.Size() >= 1 && mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock* pblock = mEntryBlocks[0], * lblock = mEntryBlocks[1];
int ps = pblock->mIns.Size(), ls = lblock->mIns.Size();
if (ls >= 2)
{
if (mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_A))
{
if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
lblock->mIns[ls - 1].mType == ASMIT_CMP && !(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A))
{
lblock->mIns[ls - 2].mType = ASMIT_LDY; lblock->mIns[ls - 2].mLive |= LIVE_CPU_REG_Y;
lblock->mIns[ls - 1].mType = ASMIT_CPY; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_Y;
pblock = AddDominatorBlock(proc, pblock);
pblock->mIns.Push(mIns[0]);
mIns.Remove(0);
lblock->mExitRequiredRegs += CPU_REG_Y;
pblock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
changed = true;
}
else if (lblock->mIns[ls - 1].mType == ASMIT_LDA && lblock->mIns[ls - 1].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 1].mAddress == mIns[0].mAddress &&
!(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A))
{
lblock->mIns[ls - 1].mType = ASMIT_LDY; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_Y;
pblock = AddDominatorBlock(proc, pblock);
pblock->mIns.Push(mIns[0]);
mIns.Remove(0);
lblock->mExitRequiredRegs += CPU_REG_Y;
pblock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
changed = true;
}
}
else if (mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_A))
{
if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
lblock->mIns[ls - 1].mType == ASMIT_CMP && !(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A))
{
lblock->mIns[ls - 2].mType = ASMIT_LDX; lblock->mIns[ls - 2].mLive |= LIVE_CPU_REG_X;
lblock->mIns[ls - 1].mType = ASMIT_CPX; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_X;
pblock = AddDominatorBlock(proc, pblock);
pblock->mIns.Push(mIns[0]);
mIns.Remove(0);
lblock->mExitRequiredRegs += CPU_REG_X;
pblock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
changed = true;
}
}
else if (mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE)
{
if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
lblock->mIns[ls - 1].mType == ASMIT_CMP)
{
pblock = AddDominatorBlock(proc, pblock);
pblock->mIns.Push(mIns[0]);
mIns.Remove(0);
lblock->mExitRequiredRegs += CPU_REG_A;
pblock->mExitRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_A;
changed = true;
}
}
if (!changed && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
{
if (lblock->mIns[ls - 2].mType == ASMIT_STY && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress && lblock->mIns[ls - 1].mType == ASMIT_CPY)
{
pblock = AddDominatorBlock(proc, pblock);
pblock->mIns.Push(mIns[0]);
mIns.Remove(0);
pblock->mExitRequiredRegs += CPU_REG_Y;
lblock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
}
}
}
}
#endif
#if 1
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mEntryBlocks.Size() > 1 && !(mIns[0].mLive & LIVE_MEM))
{
if (mEntryRequiredRegs.Size() > 0 && !mEntryRequiredRegs[CPU_REG_X])
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanChangeTailZPStoreToX(mIns[0].mAddress, this))
i++;
if (i == mEntryBlocks.Size())
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
mEntryBlocks[i]->ChangeTailZPStoreToX(mIns[0].mAddress);
mEntryRequiredRegs += CPU_REG_X;
mIns[0].mType = ASMIT_TXA;
mIns[0].mMode = ASMIM_IMPLIED;
changed = true;
CheckLive();
}
}
if (!changed && mEntryRequiredRegs.Size() > 0 && !mEntryRequiredRegs[CPU_REG_Y])
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanChangeTailZPStoreToY(mIns[0].mAddress, this))
i++;
if (i == mEntryBlocks.Size())
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
mEntryBlocks[i]->ChangeTailZPStoreToY(mIns[0].mAddress);
mEntryRequiredRegs += CPU_REG_Y;
mIns[0].mType = ASMIT_TYA;
mIns[0].mMode = ASMIM_IMPLIED;
changed = true;
CheckLive();
}
}
}
if (mIns.Size() >= 1 && mTrueJump && !mFalseJump && mTrueJump->mIns.Size() > 0)
{
int sz = mIns.Size();
if (mIns[sz - 1].mType == ASMIT_STA && mTrueJump->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mTrueJump->mIns[0]))
{
int i = 0;
while (i < mTrueJump->mEntryBlocks.Size() && !mTrueJump->mEntryBlocks[i]->mFalseJump)
i++;
if (i == mTrueJump->mEntryBlocks.Size())
{
bool zlive = mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z;
for (int j = 0; j < mTrueJump->mEntryBlocks.Size(); j++)
{
if (mTrueJump->mEntryBlocks[j] != this)
{
mTrueJump->mEntryBlocks[j]->mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_A;
}
if (zlive)
{
mTrueJump->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Z;
int k = mTrueJump->mEntryBlocks[j]->mIns.Size();
while (k > 0)
{
k--;
if (mTrueJump->mEntryBlocks[j]->mIns[k].ChangesZFlag())
{
if (mTrueJump->mEntryBlocks[j]->mIns[k].ChangesAccuAndFlag())
mTrueJump->mEntryBlocks[j]->mIns[k].mLive |= LIVE_CPU_REG_Z;
else
mTrueJump->mEntryBlocks[j]->mIns.Insert(k + 1, NativeCodeInstruction(mTrueJump->mIns[0].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
break;
}
mTrueJump->mEntryBlocks[j]->mIns[k].mLive |= LIVE_CPU_REG_Z;
}
}
}
mExitRequiredRegs += CPU_REG_A;
if (zlive)
mExitRequiredRegs += CPU_REG_Z;
mTrueJump->mIns.Remove(0);
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
if (mTrueJump->mIns.Size() > 0 && (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z))
mTrueJump->mEntryRequiredRegs += CPU_REG_Z;
changed = true;
CheckLive();
}
}
}
#endif
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mMode & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && mEntryBlocks.Size() == 2)
{
if (!mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump && mEntryBlocks[0]->mIns.Size() > 0 && mEntryBlocks[1]->mIns.Size() > 0)
{
if (mEntryBlocks[0]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[0]->mIns.Last().SameEffectiveAddress(mIns[0]))
{
mEntryBlocks[1]->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));
mIns.Remove(0);
changed = true;
}
else if (mEntryBlocks[1]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[1]->mIns.Last().SameEffectiveAddress(mIns[0]))
{
mEntryBlocks[0]->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));
mIns.Remove(0);
changed = true;
}
}
}
#if 1
if (mFalseJump && mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 &&
mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mTrueJump->mIns[0].mLive & LIVE_MEM) &&
mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mFalseJump->mIns[0].mLive & LIVE_MEM) &&
mTrueJump->mIns[0].mAddress == mFalseJump->mIns[0].mAddress)
{
if (mExitRequiredRegs.Size() > 0 && !mExitRequiredRegs[CPU_REG_X])
{
if (CanChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress, mTrueJump, mFalseJump))
{
ChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress);
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryProvidedRegs += CPU_REG_X;
mFalseJump->mEntryProvidedRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
mTrueJump->mIns[0].mType = ASMIT_TXA;
mTrueJump->mIns[0].mMode = ASMIM_IMPLIED;
mFalseJump->mIns[0].mType = ASMIT_TXA;
mFalseJump->mIns[0].mMode = ASMIM_IMPLIED;
changed = true;
CheckLive();
}
}
}
#endif
CheckLive();
#if 1
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mEntryRegA)
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mEntryBlocks[i]->mIns.Last().mMode) && !mEntryBlocks[i]->mFalseJump)
i++;
if (i == mEntryBlocks.Size())
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
int sz = b->mIns.Size();
b->mIns[sz - 1].mType = ASMIT_LDX;
b->mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
b->mExitRequiredRegs += CPU_REG_X;
changed = true;
}
mEntryRequiredRegs += CPU_REG_X;
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
}
}
#endif
#if 1
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAY && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mEntryRegA)
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mEntryBlocks[i]->mIns.Last().mMode) && !mEntryBlocks[i]->mFalseJump)
i++;
if (i == mEntryBlocks.Size())
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
int sz = b->mIns.Size();
b->mIns[sz - 1].mType = ASMIT_LDY;
b->mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
b->mExitRequiredRegs += CPU_REG_Y;
changed = true;
}
mEntryRequiredRegs += CPU_REG_Y;
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
}
}
#endif
#if 1
if (mIns.Size() >= 1 && mIns[0].mMode == ASMIM_ABSOLUTE_X && !(mIns[0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
int i = 0;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDX && mEntryBlocks[i]->mIns.Last().mMode == ASMIM_IMMEDIATE && !mEntryBlocks[i]->mFalseJump)
i++;
if (i == mEntryBlocks.Size())
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
int sz = b->mIns.Size();
int index = b->mIns[sz - 1].mAddress;
b->mIns[sz - 1] = mIns[0];
b->mIns[sz - 1].mMode = ASMIM_ABSOLUTE;
b->mIns[sz - 1].mAddress += index;
changed = true;
}
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
}
}
#endif
#if 1
if (mIns.Size() >= 1 && mIns.Last().mType == ASMIT_STA && mIns.Last().mMode == ASMIM_ZERO_PAGE && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{
const NativeCodeInstruction& ins(mIns.Last());
if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
{
mTrueJump->mIns.Insert(0, ins);
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C;
mIns.Remove(mIns.Size() - 1);
mExitRequiredRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->CheckLive();
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
{
mFalseJump->mIns.Insert(0, ins);
mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
mIns.Remove(mIns.Size() - 1);
mExitRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mFalseJump->CheckLive();
changed = true;
}
}
#endif
if (mIns.Size() >= 1 && mBranch == ASMIT_BNE && (mIns.Last().mType == ASMIT_INC || mIns.Last().mType == ASMIT_DEC) && mIns.Last().mMode == ASMIM_ZERO_PAGE)
{
NativeCodeBasicBlock* b = mTrueJump;
if (b->mIns.Size() == 2 && !b->mExitRequiredRegs[CPU_REG_A])
{
if ((b->mIns[0].mType == ASMIT_LDA || b->mIns[0].mType == ASMIT_TXA || b->mIns[0].mType == ASMIT_TYA) &&
b->mIns[1].mType == ASMIT_ORA && b->mIns[1].SameEffectiveAddress(mIns.Last()))
{
if (b->mBranch == ASMIT_BEQ)
{
b->mNumEntries--;
b->mEntryBlocks.RemoveAll(this);
mTrueJump = b->mFalseJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
else if (b->mBranch == ASMIT_BNE)
{
b->mNumEntries--;
b->mEntryBlocks.RemoveAll(this);
mTrueJump = b->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
}
}
}
#if 1
if (mIns.Size() >= 2 && mFalseJump)
{
int ns = mIns.Size();
if ((mIns[ns - 2].mType == ASMIT_INY || mIns[ns - 2].mType == ASMIT_DEY) && mIns[ns - 1].mType == ASMIT_TYA)
{
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
}
else if ((mIns[ns - 2].mType == ASMIT_INX || mIns[ns - 2].mType == ASMIT_DEX) && mIns[ns - 1].mType == ASMIT_TXA)
{
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
}
}
#endif
#if 1
if (mIns.Size() >= 2 && mFalseJump)
{
int ns = mIns.Size();
if (mIns[ns - 2].mType == ASMIT_LDA && mIns[ns - 1].mType == ASMIT_CMP && mIns[ns - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[ns - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].SameEffectiveAddress(mIns[ns - 1]) ||
mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[ns - 1]))
{
NativeCodeInstruction ins = mIns[ns - 1];
mIns[ns - 1].CopyMode(mIns[ns - 2]);
mIns[ns - 2].CopyMode(ins);
if (mIns[ns - 1].RequiresXReg())
mIns[ns - 2].mLive |= LIVE_CPU_REG_X;
if (mIns[ns - 1].RequiresYReg())
mIns[ns - 2].mLive |= LIVE_CPU_REG_Y;
changed = true;
}
}
}
#endif
if (mIns.Size() >= 2 && mNumEntries == 1)
{
if (mIns[0].mType == ASMIT_TYA && mIns[1].IsShift() && mIns[1].mMode == ASMIM_IMPLIED)
{
NativeCodeBasicBlock* block = mEntryBlocks[0];
int ns = block->mIns.Size();
if (ns >= 2 && block->mIns[ns - 2].mType == ASMIT_TAY && block->mIns[ns - 1].IsSame(mIns[1]))
{
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
changed = true;
}
}
}
if (mIns.Size() >= 1 && mNumEntries == 1)
{
if (mIns[0].IsShift() && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_MEM))
{
NativeCodeBasicBlock* block = mEntryBlocks[0];
int ns = block->mIns.Size();
if (ns >= 2 &&
block->mIns[ns - 2].mType == ASMIT_STA && block->mIns[ns - 2].SameEffectiveAddress(mIns[0]) &&
block->mIns[ns - 1].mType == mIns[0].mType && block->mIns[ns - 1].mMode == ASMIM_IMPLIED && !(mIns[0].mLive & LIVE_MEM))
{
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
changed = true;
}
}
}
#if 1
if (mIns.Size() >= 2)
{
int ns = mIns.Size();
const NativeCodeInstruction& ins(mIns[ns - 2]);
if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && mTrueJump && mFalseJump && !mIns[ns-1].UsesZeroPage(ins.mAddress) && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{
if (!mIns[ns - 1].ChangesAccu())
{
if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
{
mIns[ns - 1].mLive |= LIVE_CPU_REG_A;
mTrueJump->mIns.Insert(0, ins);
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C | mIns[ns - 1].mLive;
mIns.Remove(ns - 2);
mExitRequiredRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->CheckLive();
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
{
mIns[ns - 1].mLive |= LIVE_CPU_REG_A;
mFalseJump->mIns.Insert(0, ins);
mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C | mIns[ns - 1].mLive;
mIns.Remove(ns - 2);
mExitRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mFalseJump->CheckLive();
changed = true;
}
}
else if (ns >= 3 && mIns[ns - 3].mType == ASMIT_LDA && mIns[ns - 3].mMode == ASMIM_ZERO_PAGE && !(mIns[ns - 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_A)))
{
if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
{
mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X;
mIns[ns - 2].mType = ASMIT_STX;
mTrueJump->mIns.Insert(0, ins);
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_A;
mIns.Remove(ns - 2);
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mTrueJump->CheckLive();
changed = true;
}
else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
{
mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X;
mIns[ns - 2].mType = ASMIT_STX;
mFalseJump->mIns.Insert(0, ins);
mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
if (mFalseJump->mEntryRequiredRegs[CPU_REG_A])
mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_A;
mIns.Remove(ns - 2);
mExitRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->CheckLive();
changed = true;
}
}
}
CheckLive();
}
#endif
#if 1
if (mLoopHead && mIns.Size() > 0 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mEntryBlocks.Size() == 2 && !(mIns[0].mLive & LIVE_CPU_REG_Z))
{
NativeCodeBasicBlock* dblock = nullptr, * lblock = nullptr;
if (mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump)
{
lblock = mEntryBlocks[0];
dblock = mEntryBlocks[1];
}
else if (mEntryBlocks[1]->mFalseJump && !mEntryBlocks[0]->mFalseJump)
{
lblock = mEntryBlocks[0];
dblock = mEntryBlocks[1];
}
if (lblock && lblock != this)
{
int ls = lblock->mIns.Size();
if (ls > 0 && lblock->mIns[ls - 1].mType == ASMIT_CMP)
ls--;
if (ls > 0 && lblock->mIns[ls - 1].IsSame(mIns[0]))
{
dblock->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_A;
dblock->mExitRequiredRegs += CPU_REG_A;
lblock->mExitRequiredRegs += CPU_REG_A;
changed = true;
}
}
}
#endif
#if 1
if (mTrueJump && mFalseJump && mTrueJump->mLoopHead && mIns.Size() >= 3 && mTrueJump->mNumEntries == 2)
{
int ns = mIns.Size();
if (mIns[ns - 1].mType == ASMIT_CPX && mIns[ns - 2].mType == ASMIT_LDX && mIns[ns - 3].mType == ASMIT_INC && mIns[ns - 2].SameEffectiveAddress(mIns[ns - 3]))
{
NativeCodeBasicBlock* pb = mTrueJump->mEntryBlocks[0] == this ? mTrueJump->mEntryBlocks[1] : mTrueJump->mEntryBlocks[0];
if (pb->mIns.Size() > 0)
{
int ps = pb->mIns.Size();
if (pb->mIns[ps - 1].mType == ASMIT_STX && pb->mIns[ps - 1].SameEffectiveAddress(mIns[ns - 3]))
{
mTrueJump->mIns.Insert(0, pb->mIns[ps - 1]);
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->BuildSingleExit(proc, this);
mFalseJump->mIns.Insert(0, pb->mIns[ps - 1]);
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
pb->mExitProvidedRegs += CPU_REG_X;
mExitProvidedRegs += CPU_REG_Y;
ns = mIns.Size();
mIns[ns - 3] = mIns[ns - 2];
mIns[ns - 2].mType = ASMIT_INX; mIns[ns - 2].mMode = ASMIM_IMPLIED;
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
}
}
else if (mIns[ns - 1].mType == ASMIT_CPY && mIns[ns - 2].mType == ASMIT_LDY && mIns[ns - 3].mType == ASMIT_INC && mIns[ns - 2].SameEffectiveAddress(mIns[ns - 3]))
{
NativeCodeBasicBlock* pb = mTrueJump->mEntryBlocks[0] == this ? mTrueJump->mEntryBlocks[1] : mTrueJump->mEntryBlocks[0];
if (pb->mIns.Size() > 0)
{
int ps = pb->mIns.Size();
if (pb->mIns[ps - 1].mType == ASMIT_STY && pb->mIns[ps - 1].SameEffectiveAddress(mIns[ns - 3]))
{
mTrueJump->mIns.Insert(0, pb->mIns[ps - 1]);
mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
mFalseJump->BuildSingleExit(proc, this);
mFalseJump->mIns.Insert(0, pb->mIns[ps - 1]);
mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
pb->mExitProvidedRegs += CPU_REG_Y;
mExitProvidedRegs += CPU_REG_Y;
ns = mIns.Size();
mIns[ns - 3] = mIns[ns - 2];
mIns[ns - 2].mType = ASMIT_INY; mIns[ns - 2].mMode = ASMIM_IMPLIED;
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
}
}
CheckLive();
}
#endif
#if 1
if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
{
if (mTrueJump->mIns.Size() > mFalseJump->mIns.Size())
{
if (mTrueJump->mTrueJump != mFalseJump)
{
int i = 0, offset = mTrueJump->mIns.Size() - mFalseJump->mIns.Size();
while (i < mFalseJump->mIns.Size() && mFalseJump->mIns[i].IsSame(mTrueJump->mIns[i + offset]))
i++;
if (i == mFalseJump->mIns.Size())
{
if (mTrueJump->mTrueJump)
mTrueJump->mTrueJump->RemEntryBlock(mTrueJump);
mTrueJump->mTrueJump = mFalseJump;
if (mTrueJump->mTrueJump)
mTrueJump->mTrueJump->AddEntryBlock(mTrueJump);
mTrueJump->mIns.SetSize(offset);
changed = true;
}
}
}
else
{
if (mFalseJump->mTrueJump != mTrueJump)
{
int i = 0, offset = mFalseJump->mIns.Size() - mTrueJump->mIns.Size();
while (i < mTrueJump->mIns.Size() && mTrueJump->mIns[i].IsSame(mFalseJump->mIns[i + offset]))
i++;
if (i == mTrueJump->mIns.Size())
{
if (mFalseJump->mTrueJump)
mFalseJump->mTrueJump->RemEntryBlock(mFalseJump);
mFalseJump->mTrueJump = mTrueJump;
if (mFalseJump->mTrueJump)
mFalseJump->mTrueJump->AddEntryBlock(mFalseJump);
mFalseJump->mIns.SetSize(offset);
changed = true;
}
}
}
}
#endif
#if 1
if (mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump && !mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump)
{
int s = mIns.Size(), ts = mTrueJump->mIns.Size();
if (s > 1 && ts > 0)
{
if (mIns[s - 2].mType == ASMIT_STA && mIns[s - 2].mMode == ASMIM_ZERO_PAGE &&
mTrueJump->mIns[ts - 1].mType == ASMIT_STA && mTrueJump->mIns[ts - 1].mMode == ASMIM_ZERO_PAGE && mTrueJump->mIns[ts - 1].mAddress == mIns[s - 2].mAddress)
{
}
}
}
if (mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump)
{
mTrueJump->CheckLive();
mFalseJump->CheckLive();
int s = mIns.Size(), ts = mFalseJump->mIns.Size();
if (s > 1 && ts > 0)
{
if (mIns[s - 2].mType == ASMIT_STA && mIns[s - 2].mMode == ASMIM_ZERO_PAGE &&
mFalseJump->mIns[ts - 1].mType == ASMIT_STA && mFalseJump->mIns[ts - 1].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[ts - 1].mAddress == mIns[s - 2].mAddress &&
mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[0].mAddress == mIns[s - 2].mAddress)
{
if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(ASMIT_LDY, mIns[s - 1].mMode))
{
mIns[s - 1].mType = ASMIT_LDY;
mTrueJump->mIns.Insert(0, mIns[s - 2]);
mIns.Remove(s - 2);
mFalseJump->mIns.Remove(ts - 1);
mFalseJump->mIns.Remove(0);
mExitRequiredRegs += CPU_REG_A;
mFalseJump->mExitRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
else if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)) && HasAsmInstructionMode(ASMIT_LDX, mIns[s - 1].mMode))
{
mIns[s - 1].mType = ASMIT_LDX;
mTrueJump->mIns.Insert(0, mIns[s - 2]);
mIns.Remove(s - 2);
mFalseJump->mIns.Remove(ts - 1);
mFalseJump->mIns.Remove(0);
mExitRequiredRegs += CPU_REG_A;
mFalseJump->mExitRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
changed = true;
mTrueJump->CheckLive();
mFalseJump->CheckLive();
}
}
}
}
#endif
#if 1
if (mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump && mFalseJump->mNumEntries == 1)
{
int s = mIns.Size();
if (s > 0 && mIns[s - 1].mType == ASMIT_CMP && mIns[s - 1].mMode == ASMIM_IMMEDIATE && !(mIns[s - 1].mLive & LIVE_CPU_REG_X))
{
while (mTrueJump->mIns.Size() > 1 && mFalseJump->mIns.Size() > 1 &&
((mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[1].mType == ASMIT_STA && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
(mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[1].mType == ASMIT_STX && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
((mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[1].mType == ASMIT_STA && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
(mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[1].mType == ASMIT_STX && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
mTrueJump->mIns[0].SameEffectiveAddress(mFalseJump->mIns[0]) && mTrueJump->mIns[1].SameEffectiveAddress(mFalseJump->mIns[1]) &&
HasAsmInstructionMode(ASMIT_LDX, mTrueJump->mIns[0].mMode) && HasAsmInstructionMode(ASMIT_STX, mTrueJump->mIns[1].mMode))
{
uint32 live = mIns[s - 1].mLive | LIVE_CPU_REG_A;
if (mIns[s - 1].RequiresYReg())
live |= LIVE_CPU_REG_Y;
if (s >= 2)
live |= mIns[s - 2].mLive;
mTrueJump->mIns[0].mType = ASMIT_LDX;
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_X | live;
mTrueJump->mIns[1].mType = ASMIT_STX;
mTrueJump->mIns[1].mLive |= live;
mIns.Insert(s - 1, mTrueJump->mIns[0]);
mIns.Insert(s, mTrueJump->mIns[1]);
s += 2;
mTrueJump->mIns.Remove(0); mTrueJump->mIns.Remove(0);
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
CheckLive();
mTrueJump->CheckLive();
mFalseJump->CheckLive();
changed = true;
}
}
else if (s > 0 && mIns[s - 1].mType == ASMIT_LDA && !(mIns[s - 1].mLive & LIVE_CPU_REG_X))
{
while (mTrueJump->mIns.Size() > 1 && mFalseJump->mIns.Size() > 1 &&
((mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[1].mType == ASMIT_STA && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
(mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[1].mType == ASMIT_STX && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
((mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[1].mType == ASMIT_STA && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
(mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[1].mType == ASMIT_STX && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
mTrueJump->mIns[0].SameEffectiveAddress(mFalseJump->mIns[0]) && mTrueJump->mIns[1].SameEffectiveAddress(mFalseJump->mIns[1]) &&
HasAsmInstructionMode(ASMIT_LDX, mTrueJump->mIns[0].mMode) && HasAsmInstructionMode(ASMIT_STX, mTrueJump->mIns[1].mMode) &&
!mIns[s - 1].MayBeChangedOnAddress(mTrueJump->mIns[1]))
{
uint32 live = mIns[s - 1].mLive;
if (mIns[s - 1].RequiresYReg())
live |= LIVE_CPU_REG_Y;
if (s >= 2)
live |= mIns[s - 2].mLive;
mTrueJump->mIns[0].mType = ASMIT_LDX;
mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_X | live;
mTrueJump->mIns[1].mType = ASMIT_STX;
mTrueJump->mIns[1].mLive |= live;
mIns.Insert(s - 1, mTrueJump->mIns[0]);
mIns.Insert(s, mTrueJump->mIns[1]);
s += 2;
mTrueJump->mIns.Remove(0); mTrueJump->mIns.Remove(0);
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
CheckLive();
mTrueJump->CheckLive();
mFalseJump->CheckLive();
changed = true;
}
}
}
#endif
if (mEntryBlocks.Size() == 1 && mIns.Size() >= 3)
{
NativeCodeBasicBlock* eblock = mEntryBlocks[0];
int es = eblock->mIns.Size();
while (es > 0 && !eblock->mIns[es - 1].ChangesAccu())
es--;
if (es > 0 && eblock->mIns[es - 1].mType == ASMIT_LDA && (eblock->mIns[es - 1].mMode == ASMIM_ZERO_PAGE || eblock->mIns[es - 1].mMode == ASMIM_ABSOLUTE))
{
int i = es;
es--;
while (i < eblock->mIns.Size() && !eblock->mIns[es].MayBeChangedOnAddress(eblock->mIns[i]))
i++;
if (i == eblock->mIns.Size())
{
if (mIns[2].mType == ASMIT_STA && mIns[2].SameEffectiveAddress(eblock->mIns[es]) && !(mIns[2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[0].mType == ASMIT_SEC && mIns[1].mType == ASMIT_SBC && mIns[1].mMode == ASMIM_IMMEDIATE && mIns[1].mAddress == 1)
{
mIns[0].mType = ASMIT_NOP;
mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
mIns[2].mType = ASMIT_DEC;
changed = true;
}
else if (mIns[0].mType == ASMIT_CLC && mIns[1].mType == ASMIT_ADC && mIns[1].mMode == ASMIM_IMMEDIATE && mIns[1].mAddress == 1)
{
mIns[0].mType = ASMIT_NOP;
mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
mIns[2].mType = ASMIT_INC;
changed = true;
}
}
}
}
}
if (mEntryBlocks.Size() == 1 && mIns.Size() > 0)
{
if (mIns[0].mType == ASMIT_TAY && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
NativeCodeBasicBlock* pblock = mEntryBlocks[0];
if (pblock->mTrueJump && pblock->mFalseJump && pblock->mIns.Size() > 0 && !pblock->mExitRequiredRegs[CPU_REG_Y])
{
if (this == pblock->mTrueJump && !pblock->mFalseJump->mEntryRequiredRegs[CPU_REG_A] ||
this == pblock->mFalseJump && !pblock->mTrueJump->mEntryRequiredRegs[CPU_REG_A])
{
int si = pblock->mIns.Size();
if (pblock->mIns[si - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, pblock->mIns[si - 1].mMode))
si--;
if (si > 0 && pblock->mIns[si - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, pblock->mIns[si - 1].mMode))
{
pblock->mIns[si - 1].mType = ASMIT_LDY;
pblock->mIns[si - 1].mLive |= LIVE_CPU_REG_Y;
if (si != pblock->mIns.Size())
{
pblock->mIns[si].mType = ASMIT_CPY;
pblock->mIns[si].mLive |= LIVE_CPU_REG_Y;
}
pblock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mIns[0].mType = ASMIT_NOP;
changed = true;
}
}
}
}
}
#if 1
if (mEntryBlocks.Size() > 1 && mIns.Size() > 0)
{
if (mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_Z))
{
int ei = 0;
int index;
bool found = false, fail = false;
NativeCodeBasicBlock* block;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitYRegZP(mIns[0].mAddress, index, block))
found = true;
else if (mEntryBlocks[i]->mFalseJump)
fail = true;
}
if (found && !fail)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitYRegZP(mIns[0].mAddress, index, block))
{
mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_Y, CPU_REG_Y);
}
else
{
mEntryBlocks[i]->mIns.Push(mIns[0]);
mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_Y;
}
}
mEntryRequiredRegs += CPU_REG_Y;
mIns.Remove(0);
changed = true;
}
}
else if (mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_Z))
{
int ei = 0;
int index;
bool found = false, fail = false;
NativeCodeBasicBlock* block;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitXRegZP(mIns[0].mAddress, index, block))
found = true;
else if (mEntryBlocks[i]->mFalseJump)
fail = true;
}
if (found && !fail)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitXRegZP(mIns[0].mAddress, index, block))
{
mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_X, CPU_REG_X);
}
else
{
mEntryBlocks[i]->mIns.Push(mIns[0]);
mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_X;
mEntryBlocks[i]->mExitRequiredRegs -= CPU_REG_Z;
}
}
mEntryRequiredRegs -= CPU_REG_Z;
mEntryRequiredRegs += CPU_REG_X;
mIns.Remove(0);
changed = true;
}
}
else if (mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_Z))
{
int ei = 0;
int index;
bool found = false, fail = false;
NativeCodeBasicBlock* block;
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitARegZP(mIns[0].mAddress, index, block))
found = true;
else if (mEntryBlocks[i]->mFalseJump)
fail = true;
}
if (found && !fail)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->IsExitARegZP(mIns[0].mAddress, index, block))
{
mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_A, CPU_REG_A);
}
else
{
mEntryBlocks[i]->mIns.Push(mIns[0]);
mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_A;
}
}
mEntryRequiredRegs += CPU_REG_A;
mIns.Remove(0);
changed = true;
}
}
}
#endif
#if 1
if (mEntryBlocks.Size() > 1 && mIns.Size() > 0)
{
if (mIns[0].mType == ASMIT_STA)
{
int ts;
if ((ts = mEntryBlocks[0]->mIns.Size()) >= 2 &&
mEntryBlocks[0]->mIns[ts - 2].mType == ASMIT_LDA &&
mEntryBlocks[0]->mIns[ts - 2].mMode == ASMIM_ZERO_PAGE &&
mEntryBlocks[0]->mIns[ts - 1].mType == ASMIT_ADC)
{
int addr = mEntryBlocks[0]->mIns[ts - 2].mAddress;
int i = 1;
while (i < mEntryBlocks.Size() &&
(ts = mEntryBlocks[i]->mIns.Size()) >= 2 &&
mEntryBlocks[i]->mIns[ts - 2].mType == ASMIT_LDA &&
mEntryBlocks[i]->mIns[ts - 2].mMode == ASMIM_ZERO_PAGE &&
mEntryBlocks[i]->mIns[ts - 2].mAddress == addr &&
mEntryBlocks[i]->mIns[ts - 1].mType == ASMIT_ADC)
i++;
if (i == mEntryBlocks.Size())
{
ts = mEntryBlocks[0]->mIns.Size();
mIns.Insert(0, NativeCodeInstruction(mEntryBlocks[0]->mIns[ts - 2].mIns, ASMIT_ADC, mEntryBlocks[0]->mIns[ts - 2]));
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
ts = mEntryBlocks[i]->mIns.Size();
mEntryBlocks[i]->mIns[ts - 1].mType = ASMIT_LDA;
mEntryBlocks[i]->mIns[ts - 1].mLive |= LIVE_CPU_REG_C;
mEntryBlocks[i]->mIns[ts - 2].mType = ASMIT_NOP;
mEntryBlocks[i]->mIns[ts - 2].mMode = ASMIM_IMPLIED;
mEntryBlocks[i]->mExitRequiredRegs += addr;
mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_C;
}
mEntryRequiredRegs += addr;
mEntryRequiredRegs += CPU_REG_C;
changed = true;
}
}
}
}
#endif
#if 0
if (mFalseJump && mIns.Size() > 1)
{
int sz = mIns.Size();
if (mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80)
{
if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BPL)
{
if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_AND && mTrueJump->mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock* pblock = mTrueJump->mEntryBlocks[0];
if (pblock == this)
pblock = mTrueJump->mEntryBlocks[1];
if (!pblock->mFalseJump)
{
pblock->mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mIns.Remove(0);
changed = true;
}
}
}
}
}
#endif
if (mFalseJump && !mFalseJump->mFalseJump && mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 2 && mTrueJump->mIns.Size() > 0 && mIns.Size() > 0)
{
int sz = mIns.Size();
if (mTrueJump->mIns[0].mType == ASMIT_TAX && !mFalseJump->ReferencesXReg() && !mFalseJump->ReferencesAccu() && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (mIns[sz - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 1].mMode))
{
mIns[sz - 1].mType = ASMIT_LDX;
mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
mTrueJump->mIns[0].mType = ASMIT_NOP;
mExitRequiredRegs += CPU_REG_X;
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mExitRequiredRegs += CPU_REG_X;
for (int i = 0; i < mFalseJump->mIns.Size(); i++)
mFalseJump->mIns[i].mLive |= LIVE_CPU_REG_X;
changed = true;
}
}
else if (mTrueJump->mIns[0].mType == ASMIT_TAY && !mFalseJump->ReferencesYReg() && !mFalseJump->ReferencesAccu() && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (mIns[sz - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[sz - 1].mMode))
{
mIns[sz - 1].mType = ASMIT_LDY;
mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
mTrueJump->mIns[0].mType = ASMIT_NOP;
mExitRequiredRegs += CPU_REG_Y;
mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
mFalseJump->mExitRequiredRegs += CPU_REG_Y;
for (int i = 0; i < mFalseJump->mIns.Size(); i++)
mFalseJump->mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
}
}
}
if (mEntryBlocks.Size() == 1 && mIns.Size() > 0 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
NativeCodeBasicBlock* pblock = mEntryBlocks[0];
NativeCodeBasicBlock* nblock = pblock->mTrueJump == this ? pblock->mFalseJump : pblock->mTrueJump;
if (!nblock || (!nblock->mEntryRequiredRegs[CPU_REG_A] && !nblock->mEntryRequiredRegs[CPU_REG_X]))
{
int ps = pblock->mIns.Size();
if (ps > 0 && pblock->mIns[ps - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, pblock->mIns[ps - 1].mMode))
{
pblock->mIns[ps - 1].mType = ASMIT_LDX;
pblock->mIns[ps - 1].mLive |= LIVE_CPU_REG_X;
pblock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mIns[0].mType = ASMIT_NOP;
changed = true;
}
}
}
CheckLive();
mProc->CheckBlocks();
if (mTrueJump && mTrueJump->JoinTailCodeSequences(proc, loops))
changed = true;
if (mFalseJump && mFalseJump->JoinTailCodeSequences(proc, loops))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::MayBeMovedBeforeBlock(int at)
{
int i = at;
while (i > 0)
{
i--;
if (!mIns[at].MayBeMovedBefore(mIns[i]))
return false;
}
return true;
}
bool NativeCodeBasicBlock::SafeInjectSequenceFromBack(NativeCodeBasicBlock* block, int start, int end)
{
uint32 changes = 0;
uint32 requires = 0;
for (int i = start; i < end; i++)
{
const NativeCodeInstruction& ins(block->mIns[i]);
if (ins.RequiresAccu() && !(changes & LIVE_CPU_REG_A)) requires |= LIVE_CPU_REG_A;
if (ins.RequiresXReg() && !(changes & LIVE_CPU_REG_X)) requires |= LIVE_CPU_REG_X;
if (ins.RequiresYReg() && !(changes & LIVE_CPU_REG_Y)) requires |= LIVE_CPU_REG_Y;
if (ins.RequiresCarry() && !(changes & LIVE_CPU_REG_C)) requires |= LIVE_CPU_REG_C;
if (ins.ChangesAccu()) changes |= LIVE_CPU_REG_A;
if (ins.ChangesXReg()) changes |= LIVE_CPU_REG_X;
if (ins.ChangesYReg()) changes |= LIVE_CPU_REG_Y;
if (ins.ChangesCarry()) changes |= LIVE_CPU_REG_C;
if (ins.ChangesZFlag()) changes |= LIVE_CPU_REG_Z;
}
uint32 live = 0;
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
live |= LIVE_CPU_REG_C;
if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BMI || mBranch == ASMIT_BPL)
live |= LIVE_CPU_REG_Z;
if (mExitRequiredRegs[CPU_REG_A])
live |= LIVE_CPU_REG_A;
if (mExitRequiredRegs[CPU_REG_X])
live |= LIVE_CPU_REG_X;
if (mExitRequiredRegs[CPU_REG_Y])
live |= LIVE_CPU_REG_Y;
if (mExitRequiredRegs[CPU_REG_C])
live |= LIVE_CPU_REG_C;
int at = mIns.Size();
while (at > 0)
{
if (live & changes)
{
at--;
const NativeCodeInstruction& ins(mIns[at]);
if (ins.ChangesAccu())
{
if (requires & LIVE_CPU_REG_A)
return false;
live &= ~LIVE_CPU_REG_A;
}
if (ins.ChangesXReg())
{
if (requires & LIVE_CPU_REG_X)
return false;
live &= ~LIVE_CPU_REG_X;
}
if (ins.ChangesYReg())
{
if (requires & LIVE_CPU_REG_Y)
return false;
live &= ~LIVE_CPU_REG_Y;
}
if (ins.ChangesCarry())
{
if (requires & LIVE_CPU_REG_C)
return false;
live &= ~LIVE_CPU_REG_C;
}
if (ins.ChangesZFlag()) live &= ~LIVE_CPU_REG_Z;
if (ins.RequiresAccu())
live |= LIVE_CPU_REG_A;
if (ins.RequiresXReg())
live |= LIVE_CPU_REG_X;
if (ins.RequiresYReg())
live |= LIVE_CPU_REG_Y;
if (ins.RequiresCarry())
live |= LIVE_CPU_REG_C;
}
else
{
for (int i = start; i < end; i++)
{
for (int j = at; j < mIns.Size(); j++)
{
if (block->mIns[i].MayBeChangedOnAddress(mIns[j]) || mIns[j].MayBeChangedOnAddress(block->mIns[i]))
return false;
}
}
for (int i = start; i < end; i++)
{
mIns.Insert(at, block->mIns[i]);
mIns[at].mLive |= live;
at++;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::MayBeMovedBeforeBlock(int start, int end)
{
uint32 changes = 0;
uint32 requires = 0;
if (start == 0)
return true;
for (int i = start; i < end; i++)
{
const NativeCodeInstruction& ins(mIns[i]);
if (ins.RequiresAccu() && !(changes & LIVE_CPU_REG_A)) requires |= LIVE_CPU_REG_A;
if (ins.RequiresXReg() && !(changes & LIVE_CPU_REG_X)) requires |= LIVE_CPU_REG_X;
if (ins.RequiresYReg() && !(changes & LIVE_CPU_REG_Y)) requires |= LIVE_CPU_REG_Y;
if (ins.RequiresCarry() && !(changes & LIVE_CPU_REG_C)) requires |= LIVE_CPU_REG_C;
if (ins.ChangesAccu()) changes |= LIVE_CPU_REG_A;
if (ins.ChangesXReg()) changes |= LIVE_CPU_REG_X;
if (ins.ChangesYReg()) changes |= LIVE_CPU_REG_Y;
if (ins.ChangesCarry()) changes |= LIVE_CPU_REG_C;
if (ins.ChangesZFlag()) changes |= LIVE_CPU_REG_Z;
}
for (int i = 0; i < start; i++)
{
const NativeCodeInstruction& ins(mIns[i]);
if (ins.ChangesAccu() && (requires & LIVE_CPU_REG_A))
return false;
if (ins.ChangesXReg() && (requires & LIVE_CPU_REG_X))
return false;
if (ins.ChangesYReg() && (requires & LIVE_CPU_REG_Y))
return false;
if (ins.ChangesCarry() && (requires & LIVE_CPU_REG_C))
return false;
for (int j = start; j < end; j++)
{
if (mIns[i].MayBeChangedOnAddress(mIns[j]) || mIns[j].MayBeChangedOnAddress(mIns[i]) ||
mIns[i].MayReference(mIns[j]) || mIns[j].MayReference(mIns[i]))
return false;
}
}
return true;
}
bool NativeCodeBasicBlock::JoinCommonBranchCodeSequences(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 &&
mTrueJump != this && mFalseJump != this &&
mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
{
int i = 0;
while (i < mTrueJump->mIns.Size())
{
int j = 0;
while (j < mFalseJump->mIns.Size() && !mFalseJump->mIns[j].IsSame(mTrueJump->mIns[i]))
j++;
if (j < mFalseJump->mIns.Size())
{
int n = 0;
while (i + n < mTrueJump->mIns.Size() && j + n < mFalseJump->mIns.Size() &&
mTrueJump->mIns[i + n].IsSame(mFalseJump->mIns[j + n]) &&
((mTrueJump->mIns[i + n].mLive & LIVE_CPU_REG) || (mFalseJump->mIns[j + n].mLive & LIVE_CPU_REG)))
n++;
if (i + n < mTrueJump->mIns.Size() && j + n < mFalseJump->mIns.Size() && mTrueJump->mIns[i + n].IsSame(mFalseJump->mIns[j + n]))
{
if (mTrueJump->MayBeMovedBeforeBlock(i, i + n + 1) && mFalseJump->MayBeMovedBeforeBlock(j, j + n + 1))
{
if (SafeInjectSequenceFromBack(mTrueJump, i, i + n + 1))
{
for (int k = 0; k < i; k++)
mTrueJump->mIns[k].mLive |= mTrueJump->mIns[i].mLive;
for (int k = 0; k < j; k++)
mFalseJump->mIns[k].mLive |= mFalseJump->mIns[j].mLive;
if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_A)
{
mTrueJump->mEntryRequiredRegs += CPU_REG_A;
mFalseJump->mEntryRequiredRegs += CPU_REG_A;
}
if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_X)
{
mTrueJump->mEntryRequiredRegs += CPU_REG_X;
mFalseJump->mEntryRequiredRegs += CPU_REG_X;
}
if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_Y)
{
mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
}
if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_C)
{
mTrueJump->mEntryRequiredRegs += CPU_REG_C;
mFalseJump->mEntryRequiredRegs += CPU_REG_C;
}
mTrueJump->mIns.Remove(i, n + 1);
mFalseJump->mIns.Remove(j, n + 1);
changed = true;
}
else
i++;
}
else
i++;
}
else
i++;
}
else
i++;
}
}
CheckLive();
if (mTrueJump && mTrueJump->JoinCommonBranchCodeSequences())
changed = true;
if (mFalseJump && mFalseJump->JoinCommonBranchCodeSequences())
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::DoCrossBlockAShortcut(int addr)
{
mExitRequiredRegs += CPU_REG_A;
int i = mIns.Size();
while (i > 0)
{
i--;
mIns[i].mLive |= LIVE_CPU_REG_A;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return;
}
}
bool NativeCodeBasicBlock::CanCrossBlockAShortcut(int addr)
{
if (mExitRequiredRegs[CPU_REG_A])
return false;
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesAccu())
return false;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return true;
if (mIns[i].ReferencesZeroPage(addr))
return false;
}
return false;
}
void NativeCodeBasicBlock::DoCrossBlockXShortcut(int addr)
{
mExitRequiredRegs += CPU_REG_X;
int i = mIns.Size();
while (i > 0)
{
i--;
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));
return;
}
}
}
bool NativeCodeBasicBlock::CanCrossBlockXShortcut(int addr)
{
if (mExitRequiredRegs[CPU_REG_X])
return false;
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesXReg())
return false;
if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return true;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr && !(mIns[i].mLive & LIVE_CPU_REG_Z))
return true;
if (mIns[i].ReferencesZeroPage(addr))
return false;
}
return false;
}
void NativeCodeBasicBlock::DoCrossBlockYShortcut(int addr)
{
mExitRequiredRegs += CPU_REG_Y;
int i = mIns.Size();
while (i > 0)
{
i--;
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));
return;
}
}
}
bool NativeCodeBasicBlock::CanCrossBlockYShortcut(int addr)
{
if (mExitRequiredRegs[CPU_REG_Y])
return false;
int i = mIns.Size();
while (i > 0)
{
i--;
if (mIns[i].ChangesYReg())
return false;
if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
return true;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr && !(mIns[i].mLive & LIVE_CPU_REG_Z))
return true;
if (mIns[i].ReferencesZeroPage(addr))
return false;
}
return false;
}
bool NativeCodeBasicBlock::CrossBlockRegisterAlias(bool sameAX, bool sameAY)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mNumEntries > 1)
{
sameAX = false;
sameAY = false;
}
bool direct = false;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
switch (ins.mType)
{
case ASMIT_TAY:
sameAY = true;
break;
case ASMIT_TAX:
sameAX = true;
break;
case ASMIT_TYA:
sameAY = true;
sameAX = false;
direct = true;
break;
case ASMIT_TXA:
sameAY = false;
sameAX = true;
direct = true;
break;
case ASMIT_CMP:
if (!(ins.mLive & LIVE_CPU_REG_A))
{
if (sameAY && (ins.mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(ASMIT_CPY, ins.mMode))
{
ins.mType = ASMIT_CPY;
changed = true;
}
else if (sameAX && (ins.mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(ASMIT_CPX, ins.mMode))
{
ins.mType = ASMIT_CPX;
changed = true;
}
}
break;
case ASMIT_CPX:
if (!direct && !(ins.mLive & LIVE_CPU_REG_X))
{
if (sameAX && (ins.mLive & LIVE_CPU_REG_A))
{
ins.mType = ASMIT_CMP;
changed = true;
}
}
break;
case ASMIT_CPY:
if (!direct && !(ins.mLive & LIVE_CPU_REG_Y))
{
if (sameAY && (ins.mLive & LIVE_CPU_REG_A))
{
ins.mType = ASMIT_CMP;
changed = true;
}
}
break;
default:
if (ins.ChangesAccu())
{
sameAY = false;
sameAX = false;
}
if (ins.ChangesXReg())
sameAX = false;
if (ins.ChangesYReg())
sameAY = false;
break;
}
}
if (mTrueJump && mTrueJump->CrossBlockRegisterAlias(sameAX, sameAY))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockRegisterAlias(sameAX, sameAY))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CrossBlockYAliasProgpagation(const int* yalias)
{
bool changed = false;
if (!mVisited)
{
if (mLoopHead || !yalias)
{
for (int i = 0; i < 256; i++)
mYAlias[i] = -1;
}
else
{
if (mNumEntered == 0)
{
for (int i = 0; i < 256; i++)
mYAlias[i] = yalias[i];
}
else
{
for (int i = 0; i < 256; i++)
if (mYAlias[i] != yalias[i])
mYAlias[i] = -1;
}
mNumEntered++;
if (mNumEntered < mNumEntries)
return false;
}
mVisited = true;
int yoffset = 0;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mType == ASMIT_INY)
yoffset = (yoffset + 1) & 0xff;
else if (ins.mType == ASMIT_DEY)
yoffset = (yoffset - 1) & 0xff;
else if (ins.mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
mYAlias[ins.mAddress] = yoffset;
else if (ins.mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
mYAlias[ins.mAddress] = -1;
else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE)
{
if (mYAlias[ins.mAddress] != -1)
{
int diff = (mYAlias[ins.mAddress] - yoffset) & 0xff;
if (diff == 0x01)
{
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (diff == 0xff)
{
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (diff == 0x00 && !(ins.mLive & LIVE_CPU_REG_Z))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
yoffset = mYAlias[ins.mAddress];
}
else
{
for (int i = 0; i < 256; i++)
mYAlias[i] = -1;
yoffset = 0;
mYAlias[ins.mAddress] = yoffset;
}
}
else if (ins.mType == ASMIT_TAY && i > 0 && (mIns[i - 1].mType == ASMIT_STA || mIns[i - 1].mType == ASMIT_LDA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
{
for (int i = 0; i < 256; i++)
mYAlias[i] = -1;
yoffset = 0;
mYAlias[mIns[i - 1].mAddress] = yoffset;
}
else if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE && mYAlias[ins.mAddress] != -1 && i + 1 < mIns.Size())
{
if (mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
mIns[i + 1].mAddress = (mIns[i + 1].mAddress + mYAlias[ins.mAddress] - yoffset) & 0xff;
changed = true;
}
}
else if (ins.ChangesYReg())
{
for (int i = 0; i < 256; i++)
mYAlias[i] = -1;
yoffset = 0;
}
}
if (yoffset > 0)
{
for (int i = 0; i < 256; i++)
{
if (mYAlias[i] >= 0)
mYAlias[i] = (mYAlias[i] - yoffset) & 0xff;
}
}
if (mTrueJump && mTrueJump->CrossBlockYAliasProgpagation(mYAlias))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockYAliasProgpagation(mYAlias))
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::BypassAccuLoadStoreXY(void)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
if (!(mIns[i].mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && HasAsmInstructionMode(ASMIT_STX, mIns[i + 1].mMode))
{
mIns[i].mType = ASMIT_LDX; mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX;
}
else if (!(mIns[i].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode) && HasAsmInstructionMode(ASMIT_STY, mIns[i + 1].mMode))
{
mIns[i].mType = ASMIT_LDY; mIns[i].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY;
}
}
}
if (mTrueJump) mTrueJump->BypassAccuLoadStoreXY();
if (mFalseJump) mFalseJump->BypassAccuLoadStoreXY();
}
}
bool NativeCodeBasicBlock::CrossBlockXYShortcut(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (!mLoopHead && mEntryBlocks.Size() > 1)
{
CheckLive();
bool xvalid = !mEntryRequiredRegs[CPU_REG_X];
bool yvalid = !mEntryRequiredRegs[CPU_REG_Y];
bool avalid = !mEntryRequiredRegs[CPU_REG_A];
int i = 0;
while (i < mIns.Size() && (xvalid || yvalid || avalid))
{
if (xvalid && mIns[i].ChangesAccu())
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
int k = i;
while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
k--;
if (k == 0)
{
k = 0;
while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockAShortcut(mIns[i].mAddress))
k++;
if (k == mEntryBlocks.Size())
{
for (int k = 0; k < mEntryBlocks.Size(); k++)
mEntryBlocks[k]->DoCrossBlockAShortcut(mIns[i].mAddress);
changed = true;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
mEntryRequiredRegs += CPU_REG_A;
for (int k = 0; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_A;
}
}
}
xvalid = false;
}
if (xvalid && mIns[i].ChangesXReg())
{
if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
int k = i;
while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
k--;
if (k == 0)
{
k = 0;
while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockXShortcut(mIns[i].mAddress))
k++;
if (k == mEntryBlocks.Size())
{
for (int k = 0; k < mEntryBlocks.Size(); k++)
mEntryBlocks[k]->DoCrossBlockXShortcut(mIns[i].mAddress);
changed = true;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
mEntryRequiredRegs += CPU_REG_X;
for (int k = 0; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_X;
}
}
}
xvalid = false;
}
if (yvalid && mIns[i].ChangesYReg())
{
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
int k = i;
while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
k--;
if (k == 0)
{
k = 0;
while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockYShortcut(mIns[i].mAddress))
k++;
if (k == mEntryBlocks.Size())
{
for (int k = 0; k < mEntryBlocks.Size(); k++)
mEntryBlocks[k]->DoCrossBlockYShortcut(mIns[i].mAddress);
changed = true;
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
mEntryRequiredRegs += CPU_REG_Y;
for (int k = 0; k < i; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
}
}
}
yvalid = false;
}
i++;
}
CheckLive();
}
if (mTrueJump && mTrueJump->CrossBlockXYShortcut())
changed = true;
if (mFalseJump && mFalseJump->CrossBlockXYShortcut())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CrossBlockIncToZeroShortcut(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int sz = mIns.Size();
if (mFalseJump && mIns.Size() > 0 && mIns[sz - 1].mType == ASMIT_INC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
{
NativeCodeBasicBlock* eblock = nullptr, * nblock = nullptr;
if (mBranch == ASMIT_BNE)
{
eblock = mFalseJump;
nblock = mTrueJump;
}
else if (mBranch == ASMIT_BEQ)
{
eblock = mTrueJump;
nblock = mFalseJump;
}
if (eblock && !eblock->mFalseJump && eblock->mTrueJump == nblock && !eblock->ChangesZeroPage(mIns[sz - 1].mAddress))
{
if (nblock->mIns.Size() == 2 &&
nblock->mFalseJump &&
(nblock->mIns[0].mType == ASMIT_LDA || nblock->mIns[0].mType == ASMIT_TXA || nblock->mIns[0].mType == ASMIT_TYA) &&
nblock->mIns[1].mType == ASMIT_ORA)
{
if (nblock->mIns[0].SameEffectiveAddress(mIns[sz - 1]) || nblock->mIns[1].SameEffectiveAddress(mIns[sz - 1]))
{
NativeCodeBasicBlock* tblock = nullptr;
if (nblock->mBranch == ASMIT_BNE)
tblock = nblock->mTrueJump;
else if (nblock->mBranch == ASMIT_BEQ)
tblock = nblock->mFalseJump;
if (tblock && !tblock->mEntryRequiredRegs[CPU_REG_A])
{
tblock->AddEntryBlock(this);
nblock->RemEntryBlock(this);
if (mBranch == ASMIT_BNE)
mTrueJump = tblock;
else
mFalseJump = tblock;
changed = true;
}
}
}
}
}
else if (mFalseJump && sz >= 8 &&
mIns[sz - 8].mType == ASMIT_CLC &&
mIns[sz - 7].mType == ASMIT_LDA && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 1 &&
mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].mMode == ASMIM_ZERO_PAGE && mIns[sz - 5].mAddress == mIns[sz - 7].mAddress &&
mIns[sz - 4].mType == ASMIT_LDA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 4].mAddress &&
mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 7].mAddress)
{
NativeCodeBasicBlock* eblock = nullptr, * nblock = nullptr;
if (mBranch == ASMIT_BNE)
{
eblock = mFalseJump;
nblock = mTrueJump;
}
else if (mBranch == ASMIT_BEQ)
{
eblock = mTrueJump;
nblock = mFalseJump;
}
if (nblock && !nblock->mEntryRequiredRegs[CPU_REG_A])
{
NativeCodeBasicBlock* iblock = mProc->AllocateBlock();
iblock->AddEntryBlock(this);
iblock->mIns.Push(mIns[sz - 8]);
iblock->mIns.Push(mIns[sz - 4]);
iblock->mIns.Push(mIns[sz - 6]);
iblock->mIns.Push(mIns[sz - 2]);
iblock->Close(mIns[sz - 1].mIns, nblock, eblock, ASMIT_BNE);
nblock->AddEntryBlock(iblock);
eblock->AddEntryBlock(iblock);
iblock->mIns[2].mLive |= LIVE_CPU_REG_Z;
iblock->mIns[3].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 6].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 5].mLive |= LIVE_CPU_REG_Z;
mIns.SetSize(sz - 4);
mTrueJump = nblock;
mFalseJump = iblock;
mBranch = ASMIT_BNE;
mExitRequiredRegs += CPU_REG_C;
CheckLive();
changed = true;
}
}
if (mTrueJump && mTrueJump->CrossBlockIncToZeroShortcut())
changed = true;
if (mFalseJump && mFalseJump->CrossBlockIncToZeroShortcut())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CrossBlockXYPreservation(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mTrueJump->mTrueJump && !mTrueJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump &&
mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)
{
NativeCodeBasicBlock* tblock = mTrueJump, * fblock = mFalseJump;
if (!mExitRequiredRegs[CPU_REG_Y] && !fblock->mEntryRequiredRegs[CPU_REG_X])
{
int si = mIns.Size() - 1;
while (si >= 0 && !mIns[si].ChangesXReg())
si--;
if (si >= 0 && mIns[si].mType == ASMIT_LDX && mIns[si].mMode == ASMIM_ZERO_PAGE)
{
int addr = mIns[si].mAddress;
int i = si;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(addr))
i++;
if (i == mIns.Size())
{
int fi = 0;
while (fi < fblock->mIns.Size() && !fblock->mIns[fi].ChangesXReg())
fi++;
if (fi < fblock->mIns.Size() && fblock->mIns[fi].mType == ASMIT_LDX && fblock->mIns[fi].mMode == ASMIM_ZERO_PAGE && fblock->mIns[fi].mAddress == addr)
{
i = 0;
while (i < fi && !fblock->mIns[i].ChangesZeroPage(addr))
i++;
if (i == fi)
{
int ti = 0;
while (ti < tblock->mIns.Size() && !tblock->mIns[ti].ChangesXReg())
ti++;
if (ti < tblock->mIns.Size())
{
int i = 0;
while (i < tblock->mIns.Size() && !tblock->mIns[i].ChangesYReg() && !tblock->mIns[i].ChangesZeroPage(addr))
i++;
if (i == tblock->mIns.Size())
{
tblock->ReplaceXRegWithYReg(ti, tblock->mIns.Size());
changed = true;
}
}
}
}
}
}
}
}
if (mTrueJump && mTrueJump->CrossBlockXYPreservation())
changed = true;
if (mFalseJump && mFalseJump->CrossBlockXYPreservation())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::EliminateMicroBlocks(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mIns.Size() > 0 && mIns.Size() <= 2 && mTrueJump && !mFalseJump)
{
if (mIns[0].mType == ASMIT_STA && !(mIns[0].mLive & LIVE_CPU_REG_A))
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* block = mEntryBlocks[i];
int sz = block->mIns.Size();
if (sz > 0 && !block->mFalseJump)
{
if (block->mIns[sz - 1].mType == ASMIT_TYA && HasAsmInstructionMode(ASMIT_STY, mIns[0].mMode))
{
block->mIns[sz - 1] = NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]);
if (mIns.Size() > 1)
block->mIns.Push(mIns[1]);
block->mTrueJump->RemEntryBlock(block);
mTrueJump->AddEntryBlock(block);
block->mTrueJump = mTrueJump;
changed = true;
}
else if (block->mIns[sz - 1].mType == ASMIT_TXA && HasAsmInstructionMode(ASMIT_STX, mIns[0].mMode))
{
block->mIns[sz - 1] = NativeCodeInstruction(mIns[0].mIns, ASMIT_STX, mIns[0]);
if (mIns.Size() > 1)
block->mIns.Push(mIns[1]);
block->mTrueJump->RemEntryBlock(block);
mTrueJump->AddEntryBlock(block);
block->mTrueJump = mTrueJump;
changed = true;
}
}
}
}
}
if (mTrueJump && mTrueJump->EliminateMicroBlocks())
changed = true;
if (mFalseJump && mFalseJump->EliminateMicroBlocks())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::FoldLoopEntry(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mIns.Size() >= 1)
{
int sz = mIns.Size();
if (mIns[sz - 1].mType == ASMIT_LDA)
{
if (mTrueJump->mIns.Size() == 1 && mTrueJump != this)
{
if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[sz - 1]))
{
if (mBranch == mTrueJump->mBranch && mFalseJump == mTrueJump->mFalseJump && mTrueJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mTrueJump->mBranch) && mFalseJump == mTrueJump->mTrueJump && mTrueJump == mTrueJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP;
mIns[sz - 1].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
changed = true;
}
}
}
if (!changed && mFalseJump->mIns.Size() == 1 && mFalseJump != this)
{
if (mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].SameEffectiveAddress(mIns[sz - 1]))
{
if (mBranch == mFalseJump->mBranch && mFalseJump == mFalseJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mFalseJump->mBranch) && mFalseJump == mFalseJump->mTrueJump && mTrueJump == mFalseJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP;
mIns[sz - 1].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
changed = true;
}
}
}
}
}
if (!changed && mTrueJump && mFalseJump && mIns.Size() >= 2)
{
int sz = mIns.Size();
if (mIns[sz - 2].mType == ASMIT_LDA && ((mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE) || (mIns[sz - 1].IsShift() && mIns[sz - 1].mMode == ASMIM_IMPLIED)))
{
if (mTrueJump->mIns.Size() == 2 && mTrueJump != this)
{
if (mTrueJump->mIns[0].IsSame(mIns[sz - 2]) && mTrueJump->mIns[1].IsSame(mIns[sz - 1]))
{
if (mBranch == mTrueJump->mBranch && mFalseJump == mTrueJump->mFalseJump && mTrueJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mTrueJump->mBranch) && mFalseJump == mTrueJump->mTrueJump && mTrueJump == mTrueJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
changed = true;
}
}
}
if (!changed && mFalseJump->mIns.Size() == 2 && mFalseJump != this)
{
if (mFalseJump->mIns[0].IsSame(mIns[sz - 2]) && mFalseJump->mIns[1].IsSame(mIns[sz - 1]))
{
if (mBranch == mFalseJump->mBranch && mFalseJump == mFalseJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mFalseJump->mBranch) && mFalseJump == mFalseJump->mTrueJump && mTrueJump == mFalseJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP;
mIns[sz - 1].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
changed = true;
}
}
}
}
}
if (mTrueJump && mTrueJump->FoldLoopEntry())
changed = true;
if (mFalseJump && mFalseJump->FoldLoopEntry())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::BypassRegisterConditionBlock(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mTrueJump && mFalseJump && mIns.Size() > 0)
{
NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr;
if (mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump)
{
cblock = mTrueJump;
eblock = mFalseJump;
}
else if (mFalseJump->mTrueJump == mTrueJump && !mFalseJump->mFalseJump)
{
cblock = mFalseJump;
eblock = mTrueJump;
}
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)
{
int csz = cblock->mIns.Size() - 1;
if (cblock->mIns[csz].mType == ASMIT_LDA && cblock->mIns[csz].mMode == ASMIM_ZERO_PAGE &&
eblock->mIns[0].mType == ASMIT_STA && eblock->mIns[0].mMode == ASMIM_ZERO_PAGE && eblock->mIns[0].mAddress == cblock->mIns[csz].mAddress && !(eblock->mIns[0].mLive & LIVE_CPU_REG_A))
{
mIns.Push(NativeCodeInstruction(ASMIT_STA, eblock->mIns[0]));
cblock->mIns.Remove(csz);
cblock->mExitRequiredRegs -= CPU_REG_A;
changed = true;
}
}
#endif
if (mExitRequiredRegs[CPU_REG_A])
{
if (!cblock->ReferencesAccu())
{
int i = mIns.Size() - 1;
while (i >= 0 && !mIns[i].ReferencesAccu())
i--;
if (i >= 0 && mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
{
eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, mIns[i]));
mIns.Remove(i);
changed = true;
mExitRequiredRegs -= CPU_REG_A;
}
}
}
else if (!eblock->mEntryRequiredRegs[CPU_REG_A])
{
int i = mIns.Size() - 1;
while (i >= 0 && !mIns[i].ReferencesAccu())
i--;
if (i >= 0 && mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (!ChangesXReg(i + 1))
{
cblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA));
mIns.Remove(i);
changed = true;
mExitRequiredRegs -= CPU_REG_A;
mExitRequiredRegs += CPU_REG_X;
cblock->mEntryRequiredRegs += CPU_REG_X;
}
}
else if (i >= 0 && mIns[i].mType == ASMIT_TYA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (!ChangesYReg(i + 1))
{
cblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA));
mIns.Remove(i);
changed = true;
mExitRequiredRegs -= CPU_REG_A;
mExitRequiredRegs += CPU_REG_Y;
cblock->mEntryRequiredRegs += CPU_REG_Y;
}
}
}
}
if (mExitRequiredRegs[CPU_REG_Y])
{
if (!cblock->ReferencesYReg())
{
int i = mIns.Size() - 1;
while (i >= 0 && !mIns[i].ReferencesYReg())
i--;
if (i >= 0 && mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
{
eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, mIns[i]));
mIns.Remove(i);
changed = true;
mExitRequiredRegs -= CPU_REG_Y;
}
}
}
}
if (mExitRequiredRegs[CPU_REG_X])
{
if (!cblock->ReferencesXReg())
{
int i = mIns.Size() - 1;
while (i >= 0 && !mIns[i].ReferencesXReg())
i--;
if (i >= 0 && mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
{
eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i]));
mIns.Remove(i);
changed = true;
mExitRequiredRegs -= CPU_REG_X;
}
}
}
}
#if 1
CheckLive();
if (eblock->mIns.Size() > 0 && eblock->mIns[0].mType == ASMIT_LDY && eblock->mIns[0].mMode == ASMIM_ZERO_PAGE &&
!(eblock->mIns[0].mLive & LIVE_MEM) && !cblock->ReferencesYReg() && cblock->mIns.Size() > 0 && !mExitRequiredRegs[CPU_REG_Y])
{
NativeCodeInstruction& ins = cblock->mIns[cblock->mIns.Size() - 1];
if ((ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) && ins.SameEffectiveAddress(eblock->mIns[0]) && !ChangedOnPath(cblock, 0, cblock->mIns.Size() - 1, ins.mAddress))
{
int i = mIns.Size();
bool fail = false;
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].ReferencesYReg() || mIns[i - 1].ChangesZeroPage(ins.mAddress))
{
fail = true;
break;
}
i--;
}
if (!fail)
{
mIns.Insert(i, eblock->mIns[0]);
mIns[i].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C;
eblock->mIns.Remove(0);
if (ins.mType == ASMIT_INC)
ins.mType = ASMIT_INY;
else if (ins.mType == ASMIT_DEC)
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
for (i = 0; i < cblock->mIns.Size(); i++)
cblock->mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
cblock->mEntryRequiredRegs += CPU_REG_Y;
cblock->mExitRequiredRegs += CPU_REG_Y;
eblock->mEntryRequiredRegs += CPU_REG_Y;
CheckLive();
}
}
}
#endif
}
}
if (mTrueJump && mTrueJump->BypassRegisterConditionBlock())
changed = true;
if (mFalseJump && mFalseJump->BypassRegisterConditionBlock())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::FindPageStartAddress(int at, int reg, int& addr)
{
int j = at - 2;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_IMMEDIATE &&
mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg + 1)
{
addr = mIns[j + 0].mAddress << 8;
return true;
}
if (mIns[j + 1].mMode == ASMIM_ZERO_PAGE && (mIns[j + 1].mAddress == reg || mIns[j + 1].mAddress == reg + 1) && mIns[j + 1].ChangesAddress())
return false;
if (mIns[j + 1].mType == ASMIT_JSR)
return false;
j--;
}
if (mFromJump)
return mFromJump->FindPageStartAddress(mFromJump->mIns.Size(), reg, addr);
else
return false;
}
bool NativeCodeBasicBlock::FindGlobalAddress(int at, int reg, int& apos)
{
int j = at - 4;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 0].mFlags & NCIF_LOWER) && mIns[j + 0].mLinkerObject &&
mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg &&
mIns[j + 2].mType == ASMIT_LDA && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_UPPER) && mIns[j + 2].mLinkerObject == mIns[j + 0].mLinkerObject &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg + 1)
{
apos = j + 0;
return true;
}
if (mIns[j + 3].mMode == ASMIM_ZERO_PAGE && (mIns[j + 3].mAddress == reg || mIns[j + 3].mAddress == reg + 1) && mIns[j + 3].ChangesAddress())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::FindImmediateStore(int at, int reg, const NativeCodeInstruction*& ains)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_LDA && (mIns[j + 0].mMode == ASMIM_IMMEDIATE || mIns[j + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg)
{
ains = &(mIns[j + 0]);
return true;
}
else if (mIns[j + 1].ChangesZeroPage(reg))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::CheckPatchFailUse(void)
{
if (mPatchStart)
return true;
if (mPatchChecked)
return false;
if (!mPatchFail)
{
mPatchFail = true;
if (mTrueJump && !mTrueJump->CheckPatchFailUse())
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailUse())
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg)
{
if (mPatched && mEntryRequiredRegs[reg])
return false;
if (!mPatchFail)
{
mPatchFail = true;
if (this != block)
{
if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
return false;
}
}
return true;
}
bool NativeCodeBasicBlock::CheckPatchFailRegPair(const NativeCodeBasicBlock* block, int reg)
{
if (mPatched && (mEntryRequiredRegs[reg] || mEntryRequiredRegs[reg + 1]))
return false;
if (!mPatchFail)
{
mPatchFail = true;
if (this != block)
{
if (mTrueJump && !mTrueJump->CheckPatchFailRegPair(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailRegPair(block, reg))
return false;
}
}
return true;
}
bool NativeCodeBasicBlock::CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains, int cycles)
{
if (!mPatched)
{
if (at == 0)
{
mPatched = true;
if (!mEntryRequiredRegs[reg])
{
mPatchFail = true;
// if (mExitRequiredRegs[reg])
{
if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
return false;
}
return true;
}
assert(mNumEntries == mEntryBlocks.Size());
if (mNumEntries > 1)
{
if (mLoopHead)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsDominatedBy(block))
return false;
}
}
if (mPatchFail)
return false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ains.mFlags & ins.mFlags & NCIF_VOLATILE)
return false;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.UsesAddress())
{
if (ins.ChangesAddress())
return false;
if (!HasAsmInstructionMode(ins.mType, ains.mMode))
return false;
if (ins.mLive & LIVE_MEM)
{
cycles--;
if (cycles == 0)
return false;
}
else
{
// if (mExitRequiredRegs[reg])
{
if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
return false;
}
return true;
}
}
else
{
// if (mExitRequiredRegs[reg])
{
if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
return false;
}
return true;
}
}
else if (ins.mType == ASMIT_JSR)
{
if (ains.mMode == ASMIM_ABSOLUTE_X || ains.mMode == ASMIM_ABSOLUTE_Y || ains.mMode == ASMIM_INDIRECT_Y)
return false;
else if (ins.mFlags & NCIF_RUNTIME)
{
if (ins.UsesZeroPage(reg))
return false;
}
else
return false;
}
else if (ains.mMode == ASMIM_ABSOLUTE_X && ins.ChangesXReg())
return false;
else if (ains.mMode == ASMIM_ABSOLUTE_Y && ins.ChangesYReg())
return false;
else if (ains.mMode == ASMIM_INDIRECT_Y && (ins.ChangesYReg() || ins.ChangesZeroPage(ains.mAddress) || ins.ChangesZeroPage(ains.mAddress + 1)))
return false;
else if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress + 1 == reg))
return false;
else if (ins.ChangesZeroPage(reg))
return true;
else if (ains.MayBeChangedOnAddress(ins))
return false;
at++;
}
if (mTrueJump && !mTrueJump->CheckSingleUseGlobalLoad(block, reg, 0, ains, cycles))
return false;
if (mFalseJump && !mFalseJump->CheckSingleUseGlobalLoad(block, reg, 0, ains, cycles))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0 && !mEntryRequiredRegs[reg])
return false;
if (at == 0)
{
if (ains.RequiresXReg())
mEntryRequiredRegs += CPU_REG_X;
if (ains.RequiresYReg())
mEntryRequiredRegs += CPU_REG_Y;
if (ains.mMode == ASMIM_INDIRECT_Y)
{
mEntryRequiredRegs += ains.mAddress;
mEntryRequiredRegs += ains.mAddress + 1;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.UsesAddress())
{
ins.CopyMode(ains);
if (!(ins.mLive & LIVE_MEM))
{
if (ains.mMode == ASMIM_INDIRECT_Y)
ins.mLive |= LIVE_MEM;
return true;
}
changed = true;
}
else
return changed;
}
if (ains.mMode == ASMIM_ABSOLUTE_X)
ins.mLive |= LIVE_CPU_REG_X;
if (ains.mMode == ASMIM_ABSOLUTE_Y || ains.mMode == ASMIM_INDIRECT_Y)
ins.mLive |= LIVE_CPU_REG_Y;
if (ains.mMode == ASMIM_INDIRECT_Y)
ins.mLive |= LIVE_MEM;
at++;
}
if (ains.RequiresXReg())
mExitRequiredRegs += CPU_REG_X;
if (ains.RequiresYReg())
mExitRequiredRegs += CPU_REG_Y;
if (ains.mMode == ASMIM_INDIRECT_Y)
{
mExitRequiredRegs += ains.mAddress;
mExitRequiredRegs += ains.mAddress + 1;
}
if (mTrueJump && mTrueJump->PatchSingleUseGlobalLoad(block, reg, 0, ains))
changed = true;
if (mFalseJump && mFalseJump->PatchSingleUseGlobalLoad(block, reg, 0, ains))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
// Checking only current block as first optimization step
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == yreg))
return false;
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
if (yval != 0)
return false;
else if (!(ins.mLive & LIVE_MEM))
return true;
}
if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_JSR)
{
if (ins.UsesZeroPage(reg) || ins.ChangesZeroPage(yreg))
return false;
yval = -1;
}
else if (ins.ChangesZeroPage(reg) || ins.ChangesZeroPage(yreg))
return false;
else if (ins.ChangesYReg())
yval = -1;
at++;
}
return false;
}
bool NativeCodeBasicBlock::PatchForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
bool changed = false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
bool done = !(ins.mLive & LIVE_MEM);
if (ins.mLive & LIVE_CPU_REG_Y)
mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
mIns.Insert(at, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, yreg));
at++;
changed = true;
if (done)
return changed;
}
at++;
}
return changed;
}
bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval, int ymax)
{
if (!mPatched)
{
if (at == 0)
{
mPatched = true;
if (!mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
{
mPatchFail = true;
if (mTrueJump && !mTrueJump->CheckPatchFailRegPair(block, reg))
return false;
if (mFalseJump && !mFalseJump->CheckPatchFailRegPair(block, reg))
return false;
return true;
}
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsDominatedBy(block))
return false;
yval = -1;
}
}
if (mPatchFail)
return false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1))
return false;
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
if (iins.mMode == ASMIM_IMMEDIATE && yval + iins.mAddress > 255)
return false;
if (yval < 0 || yval > ymax)
return false;
else if (!(ins.mLive & LIVE_MEM))
return true;
if (yval == 0) ymax = 3;
}
if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_JSR)
{
if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(base) || ins.ChangesZeroPage(base + 1) || iins.MayBeChangedOnAddress(ins))
return false;
yval = -1;
}
else if (ins.mType == ASMIT_RTS)
{
if ((ins.mFlags & NCIF_LOWER) && (base == BC_REG_ACCU || reg == BC_REG_ACCU))
return false;
}
else if (ins.ChangesZeroPage(base) || ins.ChangesZeroPage(base + 1) || iins.MayBeChangedOnAddress(ins))
return false;
else if (ins.ChangesYReg())
yval = -1;
at++;
}
if (mTrueJump && !mTrueJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax))
return false;
if (mFalseJump && !mFalseJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0 && !mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
return false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1)));
if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
assert(yval >= 0);
bool done = !(ins.mLive & LIVE_MEM);
ins.mAddress = base;
ins.mFlags &= ~NCIF_YZERO;
const InterInstruction* inins(iins.mIns);
if (ins.mLive & LIVE_CPU_REG_Y)
{
mIns.Insert(at + 1, NativeCodeInstruction(inins, ASMIT_LDY, ASMIM_IMMEDIATE, yval));
if (mIns[at].mLive & LIVE_CPU_REG_Z)
mIns.Insert(at + 2, NativeCodeInstruction(inins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
}
mIns.Insert(at, NativeCodeInstruction(inins, ASMIT_LDY, iins));
at++;
for (int i = 0; i < yval; i++)
{
mIns.Insert(at, NativeCodeInstruction(inins, ASMIT_INY, ASMIM_IMPLIED));
at++;
}
changed = true;
if (done)
return changed;
}
else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.ChangesYReg())
yval = -1;
at++;
}
if (mTrueJump && mTrueJump->PatchForwardSumYPointer(block, reg, base, iins, 0, yval))
changed = true;
if (mFalseJump && mFalseJump->PatchForwardSumYPointer(block, reg, base, iins, 0, yval))
changed = true;
if (changed)
{
mEntryRequiredRegs += base;
mEntryRequiredRegs += base + 1;
if (iins.mMode == ASMIM_ZERO_PAGE)
mEntryRequiredRegs += iins.mAddress;
}
}
return changed;
}
bool NativeCodeBasicBlock::CrossBlock16BitFlood(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 3 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_MEM) && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1)
{
proc->ResetPatched();
if (CheckCrossBlock16BitFlood(this, mIns[i + 0].mAddress, mIns[i + 1].mAddress, i + 4, false))
{
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 + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_MEM;
proc->ResetPatched();
if (PatchCrossBlock16BitFlood(this, mIns[i + 0].mAddress, mIns[i + 1].mAddress, i + 4))
{
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->CrossBlock16BitFlood(proc))
changed = true;
if (mFalseJump && mFalseJump->CrossBlock16BitFlood(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at, bool rvalid)
{
if (at == 0 && this == block)
return false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[dreg] && !mEntryRequiredRegs[dreg + 1])
return true;
if (mEntryRequiredRegs[sreg] || mEntryRequiredRegs[sreg + 1])
return false;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlock16BitFloodExit(block, sreg, dreg, rvalid))
return false;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReferencesZeroPage(sreg) || ins.ReferencesZeroPage(sreg + 1))
return false;
else if ((ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS) && (ins.ReferencesZeroPage(dreg) || ins.ReferencesZeroPage(dreg + 1)))
return false;
at++;
}
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg, bool rvalid)
{
if (!mPatchExit)
{
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReferencesZeroPage(sreg) || ins.ReferencesZeroPage(sreg + 1))
return false;
else if ((ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS) && (ins.ReferencesZeroPage(dreg) || ins.ReferencesZeroPage(dreg + 1)))
return false;
at--;
}
mPatched = true;
if (mEntryBlocks.Size() == 0)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlock16BitFloodExit(block, sreg, dreg, rvalid))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[dreg] && !mEntryRequiredRegs[dreg + 1])
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlock16BitFloodExit(block, sreg, dreg))
changed = true;
mEntryRequiredRegs += sreg;
mEntryRequiredRegs += sreg + 1;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_INDIRECT_Y)
{
if (ins.mAddress == dreg)
{
ins.mAddress = sreg;
changed = true;
}
else if (ins.mAddress == dreg + 1)
{
ins.mAddress = sreg + 1;
changed = true;
}
}
at++;
}
mPatchExit = true;
mExitRequiredRegs += sreg;
mExitRequiredRegs += sreg + 1;
if (mTrueJump && mTrueJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PatchCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg)
{
bool changed = false;
if (!mPatchExit)
{
mPatchExit = true;
mExitRequiredRegs += sreg;
mExitRequiredRegs += sreg + 1;
if (mTrueJump && mTrueJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
changed = true;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y || ins.mMode == ASMIM_INDIRECT_X || ins.mMode == ASMIM_INDIRECT_Y)
{
if (ins.mAddress == dreg)
{
ins.mAddress = sreg;
changed = true;
}
else if (ins.mAddress == dreg + 1)
{
ins.mAddress = sreg + 1;
changed = true;
}
}
at--;
}
if (mEntryRequiredRegs[dreg] || mEntryRequiredRegs[dreg + 1])
{
mPatched = true;
mEntryRequiredRegs += sreg;
mEntryRequiredRegs += sreg + 1;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlock16BitFloodExit(block, sreg, dreg))
changed = true;
}
return changed;
}
return false;
}
bool NativeCodeBasicBlock::CrossBlockXYFlood(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
proc->ResetPatched();
if (mIns[i].mType != ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_X) && CheckCrossBlockXFlood(this, mIns[i].mAddress, i + 1, false))
{
if (mIns[i].mType == ASMIT_STX)
mIns[i].mType = ASMIT_NOP;
else
mIns[i].mType = ASMIT_TAX;
mIns[i].mMode = ASMIM_IMPLIED;
mIns[i].mLive |= LIVE_CPU_REG_X;
proc->ResetPatched();
if (PatchCrossBlockXFlood(this, mIns[i].mAddress, i + 1))
{
changed = true;
}
}
else
{
#if 1
proc->ResetPatched();
if (mIns[i].mType == ASMIT_STX && CheckCrossBlockXFlood(this, mIns[i].mAddress, i + 1, true))
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
mIns[i].mLive |= LIVE_CPU_REG_X;
proc->ResetPatched();
if (PatchCrossBlockXFlood(this, mIns[i].mAddress, i + 1))
{
changed = true;
}
}
else
#endif
{
proc->ResetPatched();
if (mIns[i].mType != ASMIT_STX && !(mIns[i].mLive & LIVE_CPU_REG_Y) && CheckCrossBlockYFlood(this, mIns[i].mAddress, i + 1, false))
{
if (mIns[i].mType == ASMIT_STY)
mIns[i].mType = ASMIT_NOP;
else
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
mIns[i].mLive |= LIVE_CPU_REG_Y;
proc->ResetPatched();
if (PatchCrossBlockYFlood(this, mIns[i].mAddress, i + 1))
{
changed = true;
}
}
}
}
}
}
if (mTrueJump && mTrueJump->CrossBlockXYFlood(proc))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockXYFlood(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid)
{
if (at == 0 && this == block)
return false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return true;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg, rvalid))
return false;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
return false;
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
if (!(ins.mLive & LIVE_MEM))
return true;
}
else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
{
if (rvalid) return false;
}
else if (ins.mType == ASMIT_LDX)
{
return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z));
}
else
return false;
}
else if (ins.ChangesXReg() || (!rvalid && ins.RequiresXReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
return false;
at++;
}
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg, bool rvalid)
{
if (!mPatchExit)
{
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
return false;
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
}
else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
{
if (rvalid) return false;
}
else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX)
{
return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_X));
}
else
return false;
}
else if (ins.ChangesXReg() || (!rvalid && ins.RequiresXReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
return false;
at--;
}
mPatched = true;
if (mEntryBlocks.Size() == 0)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg, rvalid))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg)
{
bool changed = false;
if (!mPatchExit)
{
mPatchExit = true;
mExitRequiredRegs += CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0))
changed = true;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
ins.mLive |= LIVE_CPU_REG_X;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
ins.mType = ASMIT_TXA;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_INC)
{
ins.mType = ASMIT_INX;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_DEC)
{
ins.mType = ASMIT_DEX;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_STA)
{
ins.mType = ASMIT_TAX;
ins.mMode = ASMIM_IMPLIED;
return true;
}
else if (ins.mType == ASMIT_STX)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true;
}
}
at--;
}
mPatched = true;
mEntryRequiredRegs += CPU_REG_X;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg))
changed = true;
return changed;
}
return false;
}
bool NativeCodeBasicBlock::PatchCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg))
changed = true;
mEntryRequiredRegs += CPU_REG_X;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
ins.mType = ASMIT_TXA;
ins.mMode = ASMIM_IMPLIED;
if (!(ins.mLive & LIVE_MEM))
return true;
changed = true;
}
else if (ins.mType == ASMIT_INC)
{
ins.mType = ASMIT_INX;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_DEC)
{
ins.mType = ASMIT_DEX;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_LDX)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true;
}
}
ins.mLive |= LIVE_CPU_REG_X;
at++;
}
mPatchExit = true;
mExitRequiredRegs |= CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid)
{
if (at == 0 && this == block)
return false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return true;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg, false))
return false;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
return false;
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
if (!(ins.mLive & LIVE_MEM))
return true;
}
else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
{
rvalid = false;
}
else if (ins.mType == ASMIT_LDY)
{
return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z));
}
else
return false;
}
else if (ins.ChangesYReg() || (!rvalid && ins.RequiresYReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
return false;
at++;
}
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0, rvalid))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0, rvalid))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg, bool rvalid)
{
if (!mPatchExit)
{
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0, false))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0, false))
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
return false;
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
}
else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
{
}
else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STY)
{
return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_Y));
}
else
return false;
}
else if (ins.ChangesYReg() || ins.RequiresYReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
return false;
at--;
}
mPatched = true;
if (mEntryBlocks.Size() == 0)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg, false))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg)
{
bool changed = false;
if (!mPatchExit)
{
mPatchExit = true;
mExitRequiredRegs += CPU_REG_Y;
if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0))
changed = true;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
ins.mLive |= LIVE_CPU_REG_Y;
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_INC)
{
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_DEC)
{
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_STA)
{
ins.mType = ASMIT_TAY;
ins.mMode = ASMIM_IMPLIED;
return true;
}
else if (ins.mType == ASMIT_STY)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true;
}
}
at--;
}
mPatched = true;
mEntryRequiredRegs += CPU_REG_Y;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg))
changed = true;
return changed;
}
return false;
}
bool NativeCodeBasicBlock::PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg))
changed = true;
mEntryRequiredRegs += CPU_REG_Y;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
{
if (ins.mType == ASMIT_LDA)
{
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
if (!(ins.mLive & LIVE_MEM))
return true;
changed = true;
}
else if (ins.mType == ASMIT_INC)
{
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_DEC)
{
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (ins.mType == ASMIT_LDY)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true;
}
}
ins.mLive |= LIVE_CPU_REG_Y;
at++;
}
mPatchExit = true;
mExitRequiredRegs |= CPU_REG_Y;
if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CrossBlockY2XFlood(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_X))
{
proc->ResetPatched();
if (CheckCrossBlockY2XFlood(this, i + 1))
{
mIns[i].mType = ASMIT_LDX;
mIns[i].mLive |= LIVE_CPU_REG_X;
proc->ResetPatched();
if (PatchCrossBlockY2XFlood(this, i + 1))
{
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->CrossBlockY2XFlood(proc))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockY2XFlood(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at)
{
if (at == 0 && this == block)
return false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return true;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockY2XFloodExit(block))
return false;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y || ins.ReferencesXReg())
return false;
else if (!(ins.mLive & LIVE_CPU_REG_Y))
return true;
at++;
}
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockY2XFlood(block, 0))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockY2XFlood(block, 0))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block)
{
if (!mPatchExit)
{
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockY2XFlood(block, 0))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockY2XFlood(block, 0))
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y || ins.ReferencesXReg())
return false;
else if (ins.mType == ASMIT_LDY || ins.mType == ASMIT_TAY)
return true;
at--;
}
mPatched = true;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockY2XFloodExit(block))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockY2XFloodExit(block))
changed = true;
mEntryRequiredRegs += CPU_REG_X;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReplaceYRegWithXReg())
changed = true;
if (!(ins.mLive & LIVE_CPU_REG_Y))
return changed;
at++;
}
mPatchExit = true;
mExitRequiredRegs |= CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PatchCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block)
{
bool changed = false;
if (!mPatchExit)
{
mPatchExit = true;
mExitRequiredRegs += CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReplaceYRegWithXReg())
changed = true;
if (ins.mType == ASMIT_LDX || ins.mType == ASMIT_TAX)
return changed;
at--;
}
mPatched = true;
mEntryRequiredRegs += CPU_REG_X;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockY2XFloodExit(block))
changed = true;
return changed;
}
return false;
}
void NativeCodeBasicBlock::PropagateAddGlobalCarry(void)
{
if (!mVisited)
{
mVisited = true;
// Accessing memory outside of a global array is undefined behaviour, so
// if we find an indirect memory access and the pointer arithmetic for the
// upper byte included an immediate address without an offset, the carry
// must be clear
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
int j = i - 1;
while (j > 0 && !(mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[i].mAddress + 1 && mIns[j].ChangesAddress()))
j--;
if (j > 0 &&
mIns[j].mType == ASMIT_STA &&
mIns[j - 1].mType == ASMIT_ADC &&
mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
(mIns[j - 1].mFlags & NCIF_UPPER) &&
mIns[j - 1].mAddress == 0)
{
while (j < mIns.Size() && !mIns[j].ChangesCarry())
j++;
if (j < mIns.Size() && mIns[j].mType == ASMIT_CLC)
mIns[j].mType = ASMIT_NOP;
}
}
}
if (mTrueJump) mTrueJump->PropagateAddGlobalCarry();
if (mFalseJump) mFalseJump->PropagateAddGlobalCarry();
}
}
void NativeCodeBasicBlock::PropagateZPAbsolute(const NativeRegisterDataSet& data)
{
if (!mVisited)
{
mDataSet = data;
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (mLoopHead)
{
if (mNumEntries == 2 && (mTrueJump == this || mFalseJump == this))
{
ResetModifiedDataSet(mDataSet);
}
else
mDataSet.Reset();
}
else if (mNumEntries > 0)
{
if (mNumEntered > 0)
mDataSet.Intersect(mNDataSet);
mNumEntered++;
if (mNumEntered < mNumEntries)
{
mNDataSet = mDataSet;
return;
}
}
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_A].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_A].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_A].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_X].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_X].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_X].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_Y].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_Y].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_Y].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
mDataSet.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_A].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_A].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_A].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
mDataSet.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_X].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_X].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_X].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
mDataSet.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE;
mDataSet.mRegs[CPU_REG_Y].mLinkerObject = mIns[i].mLinkerObject;
mDataSet.mRegs[CPU_REG_Y].mValue = mIns[i].mAddress;
mDataSet.mRegs[CPU_REG_Y].mFlags = mIns[i].mFlags;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
mDataSet.mRegs[mIns[i].mAddress] = mDataSet.mRegs[CPU_REG_A];
else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
mDataSet.mRegs[mIns[i].mAddress] = mDataSet.mRegs[CPU_REG_X];
else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
mDataSet.mRegs[mIns[i].mAddress] = mDataSet.mRegs[CPU_REG_Y];
else if (mIns[i].mType == ASMIT_JSR)
{
mDataSet.ResetCall(mIns[i], mProc->mFastCallBase);
// mDataSet.Reset();
}
else
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
int r = mIns[i].mAddress;
if (mIns[i].ChangesAddress())
mDataSet.ResetZeroPage(r);
else if (mDataSet.mRegs[r].mMode == NRDM_ABSOLUTE)
{
mIns[i].mMode = ASMIM_ABSOLUTE;
mIns[i].mLinkerObject = mDataSet.mRegs[r].mLinkerObject;
mIns[i].mAddress = mDataSet.mRegs[r].mValue;
}
}
else if (mIns[i].mMode == ASMIM_ABSOLUTE)
{
if (mIns[i].ChangesAddress())
mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
}
else if (mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_ABSOLUTE_Y)
{
if (mIns[i].ChangesAddress())
mDataSet.ResetAbsoluteXY(mIns[i].mLinkerObject, mIns[i].mAddress);
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
int r = mIns[i].mAddress;
if (mDataSet.mRegs[r].mMode == NRDM_ABSOLUTE && mDataSet.mRegs[r + 1].mMode == NRDM_ABSOLUTE &&
mDataSet.mRegs[r].mLinkerObject == mDataSet.mRegs[r + 1].mLinkerObject &&
mDataSet.mRegs[r].mValue + 1 == mDataSet.mRegs[r + 1].mValue)
{
mIns[i].mLinkerObject = mDataSet.mRegs[r].mLinkerObject;
mIns[i].mAddress = mDataSet.mRegs[r].mValue;
}
}
if (mIns[i].ChangesAccu())
mDataSet.mRegs[CPU_REG_A].Reset();
if (mIns[i].ChangesXReg())
mDataSet.mRegs[CPU_REG_X].Reset();
if (mIns[i].ChangesYReg())
mDataSet.mRegs[CPU_REG_Y].Reset();
}
}
if (mTrueJump) mTrueJump->PropagateZPAbsolute(mDataSet);
if (mFalseJump) mFalseJump->PropagateZPAbsolute(mDataSet);
}
}
void NativeCodeBasicBlock::RegisterFunctionCalls(void)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
mProc->mGenerator->RegisterFunctionCall(this, i);
}
if (mTrueJump) mTrueJump->RegisterFunctionCalls();
if (mFalseJump) mFalseJump->RegisterFunctionCalls();
}
}
bool NativeCodeBasicBlock::MergeFunctionCalls(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
{
if (mProc->mGenerator->MergeFunctionCall(this, i))
changed = true;
}
}
if (changed)
RemoveNops();
if (mTrueJump && mTrueJump->MergeFunctionCalls())
changed = true;
if (mFalseJump && mFalseJump->MergeFunctionCalls())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const
{
if (this == block)
return true;
#if 0
if (mEntryBlocks.Size())
{
if (mLoopHead)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsDominatedBy(block))
return false;
return true;
}
return false;
#else
else
{
NativeCodeBasicBlock* dom = mDominator;
while (dom)
{
if (dom == block)
return true;
dom = dom->mDominator;
}
return false;
}
#endif
}
bool NativeCodeBasicBlock::CheckPatchFailLoop(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg, bool changed)
{
if (!mPatchLoop || (changed && !mPatchLoopChanged))
{
mPatchLoop = true;
mPatchLoopChanged = changed;
if (this == block)
return true;
if (!changed)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].ChangesZeroPage(reg) || mIns[i].ChangesZeroPage(reg + 1))
changed = true;
}
}
if (mTrueJump)
{
if (mTrueJump == head)
{
if (changed)
return false;
}
else if (!mTrueJump->CheckPatchFailLoop(block, head, reg, changed))
return false;
}
if (mFalseJump)
{
if (mFalseJump == head)
{
if (changed)
return false;
}
else if (!mFalseJump->CheckPatchFailLoop(block, head, reg, changed))
return false;
}
}
return true;
}
bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int index, int at, int yval)
{
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
return CheckPatchFailUse();
if (mLoopHead && !CheckPatchFailLoop(block, this, reg, false))
return false;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsDominatedBy(block))
return false;
yval = -1;
}
}
else
{
mPatchStart = true;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (at + 6 < mIns.Size() &&
mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg &&
mIns[at + 2].mMode == ASMIM_IMMEDIATE && (mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mAddress == 0) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress != index &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress != index &&
!(mIns[at + 6].mLive & LIVE_CPU_REG_C))
{
if (!(mIns[at + 1].mLive & LIVE_MEM) && !(mIns[at + 4].mLive & LIVE_MEM))
return true;
at += 6;
}
else if (ins.mType == ASMIT_INC && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg + 1)
;
else if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (ins.mAddress == index && ins.ChangesAddress())
return false;
else if (ins.mAddress == reg || ins.mAddress == reg + 1)
{
if (ins.ChangesAddress() || reg == index)
return false;
}
}
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
if (yval < 0)
return false;
else if (!(ins.mLive & LIVE_MEM))
{
mPatchChecked = true;
return !mPatchFail;
}
}
if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS)
{
if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(index))
return false;
yval = -1;
}
else if (ins.ChangesYReg())
yval = -1;
at++;
}
if (mTrueJump && !mTrueJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
return false;
if (mFalseJump && !mFalseJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject* lobj, int address, uint32 flags)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0 && !mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
return false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
// assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1) && reg == index));
if (at + 6 < mIns.Size() &&
mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg &&
mIns[at + 2].mMode == ASMIM_IMMEDIATE && (mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mAddress == 0) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress != index &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress != index &&
!(mIns[at + 6].mLive & LIVE_CPU_REG_C))
{
bool done = !(mIns[at + 1].mLive & LIVE_MEM) && !(mIns[at + 4].mLive & LIVE_MEM);
mIns[at + 1].mAddress = index;
int naddr = address + mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
mIns[at + 2].mType = ASMIT_ADC;
if (flags & NCIF_LOWER)
{
mIns[at + 2].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE;
mIns[at + 2].mLinkerObject = lobj;
mIns[at + 2].mAddress = lobj ? naddr : naddr & 0xff;
mIns[at + 2].mFlags = NCIF_LOWER;
}
else
naddr &= 0xff00;
mIns[at + 4].mMode = ASMIM_IMMEDIATE;
mIns[at + 4].mAddress = 0;
mIns[at + 5].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE;;
mIns[at + 5].mLinkerObject = lobj;
mIns[at + 5].mAddress = lobj ? naddr : naddr >> 8;
mIns[at + 5].mFlags = NCIF_UPPER;
at += 6;
changed = true;
if (done)
return changed;
}
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
assert(yval >= 0);
bool done = !(ins.mLive & LIVE_MEM);
const InterInstruction* iins = ins.mIns;
ins.mMode = ASMIM_ABSOLUTE_Y;
ins.mLinkerObject = lobj;
ins.mAddress = address + yval;
ins.mFlags = (ins.mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | flags;
if (ins.mLive & LIVE_CPU_REG_Y)
{
mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, yval));
if (ins.mLive & LIVE_CPU_REG_Z)
{
mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
ins.mLive |= LIVE_CPU_REG_A;
}
}
mIns.Insert(at, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, index));
at++;
changed = true;
if (done)
return changed;
}
else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_INC && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg + 1)
{
ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
address += 256;
}
else if (ins.ChangesYReg())
yval = -1;
else if (at + 6 < mIns.Size() &&
mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg + 0 &&
mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
{
int add = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
mIns[at + 1].mAddress = index;
mIns[at + 2].mMode = ASMIM_IMMEDIATE_ADDRESS;
mIns[at + 2].mLinkerObject = lobj;
mIns[at + 2].mAddress = address + add;
mIns[at + 2].mFlags = NCIF_LOWER;
mIns[at + 4].mMode = ASMIM_IMMEDIATE;
mIns[at + 4].mAddress = 0;
mIns[at + 5].mMode = ASMIM_IMMEDIATE_ADDRESS;
mIns[at + 5].mLinkerObject = lobj;
mIns[at + 5].mAddress = address + add;
mIns[at + 5].mFlags = NCIF_UPPER;
changed = true;
}
at++;
}
if (mTrueJump && mTrueJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags))
changed = true;
if (mFalseJump && mFalseJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::FindGlobalAddressSumY(int at, int reg, bool direct, int& apos, const NativeCodeInstruction*& ains, const NativeCodeInstruction*& iins, uint32& flags, int& addr)
{
flags = 0;
int j = at - 7;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 1]);
iins = &(mIns[j + 2]);
apos = j + 0;
int ireg = iins->mAddress;
if (reg == ireg)
{
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else
{
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
else if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = &(mIns[j + 1]);
apos = j + 0;
int ireg = iins->mAddress;
if (reg == ireg)
{
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else
{
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
else if (
mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = &(mIns[j + 0]);
apos = j + 1;
int ireg = iins->mAddress;
if (reg == ireg)
{
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else
{
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
else if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ABSOLUTE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 1]);
iins = &(mIns[j + 2]);
apos = j + 0;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesGlobalMemory())
return false;
k++;
}
return true;
}
#if 1
else if (
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = nullptr;
apos = j + 1;
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
if (mIns[j + 0].mType == ASMIT_TAX)
flags |= LIVE_CPU_REG_X;
if (mIns[j + 0].mType == ASMIT_TAY)
flags |= LIVE_CPU_REG_Y;
int k = j + 7;
while (k < at)
{
assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else if (
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 5].mFlags & NCIF_UPPER) && mIns[j + 5].mLinkerObject == mIns[j + 2].mLinkerObject &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = nullptr;
apos = j + 1;
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
if (mIns[j + 0].mType == ASMIT_TAX)
flags |= LIVE_CPU_REG_X;
if (mIns[j + 0].mType == ASMIT_TAY)
flags |= LIVE_CPU_REG_Y;
int k = j + 7;
while (k < at)
{
assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = &(mIns[j + 1]);
apos = j + 0;
addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);
int ireg = iins->mAddress;
if (reg == ireg)
{
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else
{
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
else if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 1]);
iins = &(mIns[j + 2]);
apos = j + 0;
addr = mIns[j + 1].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);
int ireg = iins->mAddress;
if (reg == ireg)
{
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
int k = j + 7;
while (k < at)
{
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
else
{
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
else if (
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 2]);
iins = nullptr;
apos = j + 1;
addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;
if (mIns[j + 0].mType == ASMIT_TAX)
flags |= LIVE_CPU_REG_X;
if (mIns[j + 0].mType == ASMIT_TAY)
flags |= LIVE_CPU_REG_Y;
int k = j + 7;
while (k < at)
{
assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
#endif
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
return false;
j--;
}
if (at >= 6 &&
mIns[0].mType == ASMIT_CLC &&
mIns[1].mType == ASMIT_ADC && mIns[1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[1].mFlags & NCIF_LOWER) && mIns[1].mLinkerObject &&
mIns[2].mType == ASMIT_STA && mIns[2].mMode == ASMIM_ZERO_PAGE && mIns[2].mAddress == reg &&
mIns[3].mType == ASMIT_LDA && mIns[3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[3].mFlags & NCIF_UPPER) && mIns[3].mLinkerObject == mIns[1].mLinkerObject &&
mIns[4].mType == ASMIT_ADC && mIns[4].mMode == ASMIM_IMMEDIATE && mIns[4].mAddress == 0 &&
mIns[5].mType == ASMIT_STA && mIns[5].mMode == ASMIM_ZERO_PAGE && mIns[5].mAddress == reg + 1)
{
ains = &(mIns[1]);
iins = nullptr;
apos = 0;
if (!direct)
return false;
flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[0].mLive;
int k = 6;
while (k < at)
{
assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
if (mIns[k].ChangesYReg())
flags &= ~LIVE_CPU_REG_Y;
if (mIns[k].ChangesXReg())
flags &= ~LIVE_CPU_REG_X;
k++;
}
return flags != 0;
}
if (mFromJump)
{
while (j >= -6)
{
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
return false;
j--;
}
if (mFromJump->FindGlobalAddressSumY(mFromJump->mIns.Size(), reg, false, apos, ains, iins, flags, addr))
{
if (iins->mMode == ASMIM_ZERO_PAGE)
{
int ireg = iins->mAddress;
int k = 0;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
}
else
{
int k = 0;
while (k < at)
{
if (mIns[k].ChangesGlobalMemory())
return false;
k++;
}
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::FindSharedGlobalAddressSumY(int at, int reg, const NativeCodeInstruction*& ains, const NativeCodeInstruction*& iins)
{
int j = at - 7;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ains = &(mIns[j + 1]);
iins = &(mIns[j + 2]);
int ireg = iins->mAddress;
if (reg == ireg)
return false;
if (ChangesZeroPage(ireg, j + 7, at))
return false;
return true;
}
if (mIns[j + 6].ChangesZeroPage(reg) || mIns[j + 6].ChangesZeroPage(reg + 1))
return false;
j--;
}
if (mLoopHead)
return false;
if (mEntryBlocks.Size() > 0)
{
while (j >= -6)
{
if (mIns[j + 6].ChangesZeroPage(reg) || mIns[j + 6].ChangesZeroPage(reg + 1))
return false;
j--;
}
if (mEntryBlocks[0]->FindSharedGlobalAddressSumY(mEntryBlocks[0]->mIns.Size(), reg, ains, iins))
{
if (ChangesZeroPage(iins->mAddress, 0, at))
return false;
const NativeCodeInstruction* ains0;
const NativeCodeInstruction* iins0;
int i = 1;
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->FindSharedGlobalAddressSumY(mEntryBlocks[i]->mIns.Size(), reg, ains0, iins0) && ains0->IsSame(*ains) && iins0->IsSame(*iins))
i++;
if (i == mEntryBlocks.Size())
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::JoinTAXARange(int from, int to)
{
int start = from;
if (from >= 2)
{
start = from - 2;
if (mIns[start].mType == ASMIT_LDA && mIns[start].mMode == ASMIM_ZERO_PAGE && mIns[start + 1].mType == ASMIT_AND && mIns[start + 1].mMode == ASMIM_IMMEDIATE)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[start].mAddress && mIns[i].ChangesAddress())
return false;
}
int live = mIns[to].mLive;
mIns.Remove(to);
for (int i = start; i < from; i++)
{
mIns.Insert(to, mIns[start]);
mIns[to].mLive |= live;
mIns.Remove(start);
}
mIns.Remove(start);
CheckLive();
return true;
}
else if (mIns[start].mType == ASMIT_TXA && mIns[start + 1].mType == ASMIT_AND && mIns[start + 1].mMode == ASMIM_IMMEDIATE && !(mIns[start + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns.Insert(to + 1, NativeCodeInstruction(mIns[start + 1].mIns, ASMIT_AND, ASMIM_IMMEDIATE, mIns[start + 1].mAddress));
mIns.Remove(start, 3);
CheckLive();
return true;
}
else if (mIns[start].mType == ASMIT_LDA && mIns[start].mMode == ASMIM_ABSOLUTE_X && mIns[start + 1].ChangesAccu() && !mIns[start + 1].ChangesAddress() && !mIns[start + 1].RequiresYReg())
{
for (int i = from + 1; i < to; i++)
{
if (mIns[start].MayBeChangedOnAddress(mIns[i]) || mIns[start + 1].MayBeChangedOnAddress(mIns[i]))
return false;
if (mIns[start + 1].RequiresCarry() && mIns[i].ChangesCarry())
return false;
if ((mIns[start + 1].mLive & LIVE_CPU_REG_C) && mIns[i].RequiresCarry())
return false;
}
int live = mIns[to].mLive;
mIns.Remove(to);
for (int i = start; i < from; i++)
{
mIns.Insert(to, mIns[start]);
mIns[to].mLive |= live;
mIns.Remove(start);
}
mIns.Remove(start);
CheckLive();
return true;
}
else if (mIns[start + 0].mType == ASMIT_LDY && mIns[start + 0].mMode == ASMIM_IMMEDIATE &&
mIns[start + 1].mType == ASMIT_LDA && mIns[start + 1].mMode == ASMIM_INDIRECT_Y &&
!(mIns[start + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[to].mLive & LIVE_CPU_REG_Y))
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[start + 1].mAddress || mIns[i].mAddress == mIns[start + 1].mAddress + 1) && mIns[i].ChangesAddress())
return false;
if (mIns[i].ChangesGlobalMemory())
return false;
}
int live = mIns[to].mLive;
mIns.Remove(to);
for (int i = start; i < from; i++)
{
mIns.Insert(to, mIns[start]);
mIns[to].mLive |= live;
mIns.Remove(start);
}
mIns.Remove(start);
CheckLive();
return true;
}
if (!(mIns[from].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && !(mIns[to].mLive & LIVE_CPU_REG_C))
{
start = from;
while (start > 0 &&
mIns[start - 1].mType != ASMIT_LDA &&
mIns[start - 1].mType != ASMIT_TAY &&
mIns[start - 1].mType != ASMIT_TAX &&
(mIns[start - 1].mMode == ASMIM_IMMEDIATE || mIns[start - 1].mMode == ASMIM_IMPLIED))
start--;
if (start > 0 && mIns[start - 1].mType == ASMIT_LDA && mIns[start - 1].mMode == ASMIM_ZERO_PAGE)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[start - 1].mAddress && mIns[i].ChangesAddress())
return false;
if ((mIns[start - 1].mLive & LIVE_CPU_REG_C) && mIns[i].ChangesCarry())
return false;
}
start--;
int plive = mIns[start].mLive;
for (int i = from; i < to; i++)
mIns[i].mLive |= plive;
if (mIns[to].mLive & LIVE_CPU_REG_Y)
{
for (int i = start; i < from; i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
}
int live = mIns[to].mLive;
mIns.Remove(to);
for (int i = start; i < from; i++)
{
mIns.Insert(to, mIns[start]);
mIns[to].mLive |= live;
mIns.Remove(start);
}
mIns.Remove(start);
CheckLive();
return true;
}
}
}
if (from > 0 && mIns[from - 1].mType == ASMIT_LDA && mIns[from - 1].mMode == ASMIM_ABSOLUTE_X)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[from - 1].MayBeChangedOnAddress(mIns[i]))
return false;
}
int live = mIns[to].mLive;
mIns.Remove(to);
mIns.Insert(to, mIns[from - 1]);
mIns[to].mLive |= live;
mIns.Remove(from - 1);
CheckLive();
return true;
}
if (to + 2 < mIns.Size() && mIns[to + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[to + 2].mMode) && !(mIns[to + 2].mLive & LIVE_CPU_REG_X) && !ReferencesXReg(from + 1, to))
{
if (mIns[to + 1].mType == ASMIT_ORA && mIns[to + 1].mMode == ASMIM_IMMEDIATE)
{
mIns[to + 0].mType = ASMIT_NOP; mIns[to + 0].mMode = ASMIM_IMPLIED;
mIns[to + 1].mType = ASMIT_NOP; mIns[to + 1].mMode = ASMIM_IMPLIED;
mIns[to + 2].mType = ASMIT_STX;
mIns.Insert(from, NativeCodeInstruction(mIns[to + 0].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, mIns[to + 1].mAddress));
return true;
}
}
int i = from + 1;
while (i < to && (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i].mMode == ASMIM_ABSOLUTE || mIns[i].mMode == ASMIM_ZERO_PAGE))
i++;
if (i == to)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].mType == ASMIT_LDA)
mIns[i].mType = ASMIT_LDX;
else if (mIns[i].mType == ASMIT_STA)
mIns[i].mType = ASMIT_STX;
mIns[i].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_A;
}
mIns[from].mType = ASMIT_NOP; mIns[from].mMode = ASMIM_IMPLIED;
mIns[to].mType = ASMIT_NOP; mIns[to].mMode = ASMIM_IMPLIED;
CheckLive();
return true;
}
if (to + 1 < mIns.Size() && mIns[to + 1].mType == ASMIT_STA && !(mIns[to + 1].mLive & LIVE_CPU_REG_A))
{
NativeCodeInstruction ins(mIns[to + 1]);
if (ins.mMode == ASMIM_ABSOLUTE_Y)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].ChangesAddress())
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y || mIns[i].mMode == ASMIM_ABSOLUTE_X)
return false;
else if (mIns[i].mMode == ASMIM_ABSOLUTE)
{
if (mIns[i].mLinkerObject == ins.mLinkerObject && mIns[i].mAddress >= ins.mAddress && mIns[i].mAddress < ins.mAddress + 256)
return false;
}
else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
{
if (mIns[i].mLinkerObject == ins.mLinkerObject && mIns[i].mAddress == ins.mAddress)
return false;
}
}
else if (mIns[i].ChangesYReg())
return false;
}
mIns.Remove(to);
mIns.Remove(to);
mIns.Remove(from);
mIns.Insert(from, ins);
CheckLive();
return true;
}
else if (ins.mMode == ASMIM_INDIRECT_Y)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].MayBeSameAddress(ins))
return false;
else if (mIns[i].ChangesZeroPage(ins.mAddress) || mIns[i].ChangesZeroPage(ins.mAddress + 1))
return false;
else if (mIns[i].ChangesYReg())
return false;
}
ins.mLive |= mIns[from].mLive;
mIns.Remove(to);
mIns.Remove(to);
mIns.Remove(from);
mIns.Insert(from, ins);
CheckLive();
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::JoinTAYARange(int from, int to)
{
int start = from;
if (from >= 2)
{
start = from - 2;
if (mIns[start + 0].mType == ASMIT_LDY && mIns[start + 0].mMode == ASMIM_IMMEDIATE &&
mIns[start + 1].mType == ASMIT_LDA && mIns[start + 1].mMode == ASMIM_INDIRECT_Y)
{
for (int i = from + 1; i < to; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[start + 1].mAddress || mIns[i].mAddress == mIns[start + 1].mAddress + 1) && mIns[i].ChangesAddress())
return false;
if (mIns[i].ChangesGlobalMemory())
return false;
}
mIns.Remove(to);
for (int i = start; i < from; i++)
{
mIns.Insert(to, mIns[start]);
mIns.Remove(start);
}
mIns.Remove(start);
CheckLive();
return true;
}
}
if (from >= 1)
{
if (mIns[from - 1].mMode == ASMIM_IMMEDIATE && !mIns[from - 1].RequiresCarry())
{
mIns.Insert(to + 1, mIns[from - 1]);
mIns[to + 1].mLive |= mIns[to].mLive;
mIns.Remove(from - 1);
CheckLive();
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::ReverseReplaceTAX(int at)
{
int i = at;
while (i > 0)
{
if (mIns[i - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i - 1].mMode))
{
mIns[i - 1].mType = ASMIT_LDX;
mIns[i - 1].mLive |= LIVE_CPU_REG_X;
while (i < at)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_STA)
mIns[i].mType = ASMIT_STX;
i++;
}
mIns[at].mType = ASMIT_NOP;
return true;
}
else if (mIns[i - 1].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i - 1].mMode))
{
}
else
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::MergeXYSameValue(int from)
{
int to = from;
while (to < mIns.Size())
{
if (mIns[to].ChangesYReg() || mIns[to].ChangesXReg())
return false;
if (!(mIns[to].mLive & LIVE_CPU_REG_X))
{
for (int i = from; i <= to; i++)
{
if (mIns[i].mMode == ASMIM_INDIRECT_X)
return false;
else if (mIns[i].mMode == ASMIM_ABSOLUTE_X)
{
if (!HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
return false;
}
}
return ReplaceXRegWithYReg(from, to + 1);
}
else if (!(mIns[to].mLive & LIVE_CPU_REG_Y))
{
for (int i = from; i <= to; i++)
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
return false;
else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
{
if (!HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
return false;
}
}
return ReplaceYRegWithXReg(from, to + 1);
}
to++;
}
return false;
}
int NativeCodeBasicBlock::FindFreeAccu(int at) const
{
bool used[4] = { false, false, false, false };
for (int i = 0; i < 4; i++)
if (mEntryRequiredRegs[i + BC_REG_ACCU])
used[i] = true;
for (int i = 0; i < at; i++)
{
for (int j = 0; j < 4; j++)
if (mIns[i].ReferencesZeroPage(j + BC_REG_ACCU))
used[j] = true;
}
for(int j=0; j<4; j++)
if (!used[j])
return j + BC_REG_ACCU;
return -1;
}
int NativeCodeBasicBlock::RetrieveZPValue(int reg, int at) const
{
while (at >= 0 && !mIns[at].ChangesZeroPage(reg))
at--;
if (at >= 0)
{
if (mIns[at].mType == ASMIT_STA)
return RetrieveAValue(at);
else if (mIns[at].mType == ASMIT_STX)
return RetrieveXValue(at);
else if (mIns[at].mType == ASMIT_STY)
return RetrieveYValue(at);
else
return -1;
}
else if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->RetrieveZPValue(reg, mEntryBlocks[0]->mIns.Size() - 1);
else
return -1;
}
int NativeCodeBasicBlock::RetrieveYValue(int at) const
{
while (at >= 0 && !mIns[at].ChangesYReg())
at--;
if (at >= 0)
{
if (mIns[at].mType == ASMIT_LDY && mIns[at].mMode == ASMIM_IMMEDIATE)
return mIns[at].mAddress;
else
return -1;
}
else if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->RetrieveYValue(mEntryBlocks[0]->mIns.Size() - 1);
else
return -1;
}
int NativeCodeBasicBlock::RetrieveXValue(int at) const
{
while (at >= 0 && !mIns[at].ChangesXReg())
at--;
if (at >= 0)
{
if (mIns[at].mType == ASMIT_LDX && mIns[at].mMode == ASMIM_IMMEDIATE)
return mIns[at].mAddress;
else
return -1;
}
else if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->RetrieveXValue(mEntryBlocks[0]->mIns.Size() - 1);
else
return -1;
}
int NativeCodeBasicBlock::RetrieveAValue(int at) const
{
while (at >= 0 && !mIns[at].ChangesAccu())
at--;
if (at >= 0)
{
if (mIns[at].mType == ASMIT_LDA && mIns[at].mMode == ASMIM_IMMEDIATE)
return mIns[at].mAddress;
else
return -1;
}
else if (mEntryBlocks.Size() == 1)
return mEntryBlocks[0]->RetrieveAValue(mEntryBlocks[0]->mIns.Size() - 1);
else
return -1;
}
void NativeCodeBasicBlock::RepairLoadYImmediate(int at, int val)
{
if (mIns[at].mLive & LIVE_CPU_REG_Y)
{
const InterInstruction* iins = mIns[at].mIns;
if (mIns[at].mLive & LIVE_CPU_REG_Z)
{
int i = at;
while (i + 1 < mIns.Size() && !mIns[i + 1].ReferencesYReg())
{
if (!(mIns[i].mLive & LIVE_CPU_REG_Z))
{
mIns.Insert(i + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
return;
}
i++;
}
mIns[at].mLive |= LIVE_CPU_REG_A;
mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
}
else
mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
}
}
bool NativeCodeBasicBlock::PatchGlobalAdressSumYByX(int at, int reg, const NativeCodeInstruction& ains, int addr)
{
int yindex = 0;
int last = at;
while (last < mIns.Size())
{
if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE)
yindex = mIns[last].mAddress;
else if (mIns[last].ChangesYReg())
return false;
else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
return false;
else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
{
if (!(mIns[last].mLive & LIVE_MEM))
break;
}
else if (mIns[last].RequiresXReg())
return false;
last++;
}
if (last == mIns.Size())
return false;
yindex = 0;
for (int i = at; i <= last; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
yindex = mIns[i].mAddress;
else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
{
mIns[i].mMode = ASMIM_ABSOLUTE_X;
if (ains.mMode == ASMIM_IMMEDIATE)
{
mIns[i].mLinkerObject = nullptr;
mIns[i].mAddress = addr + yindex;
}
else
{
mIns[i].mLinkerObject = ains.mLinkerObject;
mIns[i].mAddress = ains.mAddress + yindex;
}
}
}
return true;
}
bool NativeCodeBasicBlock::PatchDirectAddressSumY(int at, int reg, int apos, int breg)
{
int yindex = 0;
int last = at;
while (last < mIns.Size())
{
if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE && (mIns[last].mAddress == yindex || mIns[last].mAddress == yindex + 1))
yindex = mIns[last].mAddress;
else if (mIns[last].ChangesYReg())
return false;
else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == breg || mIns[last].mAddress == breg + 1 || mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
return false;
else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
{
if (!(mIns[last].mLive & LIVE_MEM))
break;
}
else if (mIns[last].RequiresYReg())
return false;
last++;
}
if (last == mIns.Size())
return false;
RepairLoadYImmediate(last, yindex);
mIns[apos].mType = ASMIT_TAY;
for (int i = 0; i < 5; i++)
{
mIns[apos + i + 1].mType = ASMIT_NOP;
mIns[apos + i + 1].mMode = ASMIM_IMPLIED;
}
yindex = 0;
for (int i = apos; i <= last; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (mIns[i].mAddress == yindex)
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i].mType = ASMIT_INY;
mIns[i].mMode = ASMIM_IMPLIED;
yindex++;
}
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
{
mIns[i].mAddress = breg;
}
}
return true;
}
bool NativeCodeBasicBlock::PatchAddressSumY(int at, int reg, int apos, int breg, int ireg)
{
int yindex = 0;
int last = apos + 7;
while (last < mIns.Size())
{
if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE && (mIns[last].mAddress == yindex || mIns[last].mAddress == yindex + 1 || mIns[last].mAddress + 1 == yindex))
yindex = mIns[last].mAddress;
else if (mIns[last].ChangesYReg())
return false;
else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == breg || mIns[last].mAddress == breg + 1 || mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
return false;
else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
{
if (!(mIns[last].mLive & LIVE_MEM))
break;
}
else if (mIns[last].RequiresYReg())
return false;
last++;
}
if (last == mIns.Size())
return false;
RepairLoadYImmediate(last, yindex);
for (int i = 0; i < 5; i++)
{
mIns[apos + i + 2].mType = ASMIT_NOP;
mIns[apos + i + 2].mMode = ASMIM_IMPLIED;
}
mIns[apos + 1].mType = ASMIT_LDY;
mIns[apos + 1].mMode = ASMIM_ZERO_PAGE;
mIns[apos + 1].mAddress = ireg;
mIns[apos + 1].mLive |= LIVE_MEM | LIVE_CPU_REG_Y;
yindex = 0;
for (int i = apos + 7; i <= last; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (mIns[i].mAddress == yindex)
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mAddress == yindex + 1)
{
mIns[i].mType = ASMIT_INY;
mIns[i].mMode = ASMIM_IMPLIED;
yindex++;
}
else
{
mIns[i].mType = ASMIT_DEY;
mIns[i].mMode = ASMIM_IMPLIED;
yindex--;
}
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
{
mIns[i].mFlags &= ~NCIF_YZERO;
mIns[i].mAddress = breg;
}
}
return true;
}
bool NativeCodeBasicBlock::FindBypassAddressSumY(int at, int reg, int& apos, int& breg)
{
int j = at - 6;
while (j >= 0)
{
if (
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == reg &&
mIns[j + 3].mType == ASMIT_LDA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == mIns[j + 1].mAddress + 1 &&
mIns[j + 4].mType == ASMIT_ADC && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
mIns[j + 5].mType == ASMIT_STA && mIns[j + 5].mMode == ASMIM_ZERO_PAGE && mIns[j + 5].mAddress == reg + 1)
{
breg = mIns[j + 1].mAddress;
int k = j + 6;
while (k < at)
{
if (mIns[k].ChangesZeroPage(breg) || mIns[k].ChangesZeroPage(breg + 1))
return false;
k++;
}
apos = j;
return true;
}
if (mIns[j + 5].ReferencesZeroPage(reg) || mIns[j + 5].ReferencesZeroPage(reg + 1))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::PatchBypassAddressSumY(int at, int reg, int apos, int breg)
{
mIns[apos + 0].mType = ASMIT_NOP; mIns[apos + 0].mMode = ASMIM_IMPLIED;
mIns[apos + 1].mType = ASMIT_NOP; mIns[apos + 1].mMode = ASMIM_IMPLIED;
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 4].mType = ASMIT_NOP; mIns[apos + 4].mMode = ASMIM_IMPLIED;
mIns[apos + 5].mType = ASMIT_NOP; mIns[apos + 5].mMode = ASMIM_IMPLIED;
mIns[at + 0].mMode = ASMIM_ZERO_PAGE;
mIns[at + 0].mAddress = reg;
mIns[at + 1].mAddress = breg;
mIns[at + 1].mLive |= LIVE_MEM;
return true;
}
bool NativeCodeBasicBlock::FindDirectAddressSumY(int at, int reg, int& apos, int& breg)
{
int j = at - 6;
while (j >= 0)
{
if (
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == reg &&
mIns[j + 3].mType == ASMIT_LDA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == mIns[j + 1].mAddress + 1 &&
mIns[j + 4].mType == ASMIT_ADC && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
mIns[j + 5].mType == ASMIT_STA && mIns[j + 5].mMode == ASMIM_ZERO_PAGE && mIns[j + 5].mAddress == reg + 1)
{
breg = mIns[j + 1].mAddress;
int k = j + 6;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1) && mIns[k].ChangesAddress())
return false;
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
return false;
k++;
}
apos = j;
return true;
}
if (mIns[j + 5].mMode == ASMIM_ZERO_PAGE && (mIns[j + 5].mAddress == reg || mIns[j + 5].mAddress == reg + 1) && mIns[j + 5].ChangesAddress() || mIns[j + 5].ChangesYReg() || mIns[j + 5].RequiresYReg())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::FindExternAddressSumY(int at, int reg, int& breg, int& ireg)
{
int j = at - 7;
while (j >= 0)
{
if (
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 1].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 1].mAddress;
ireg = mIns[j + 2].mAddress;
if (ireg == breg || reg == breg || ireg == reg)
return false;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
else if (
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 2].mAddress;
ireg = mIns[j + 1].mAddress;
if (ireg == breg || reg == breg || ireg == reg)
return false;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
else if (
mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 2].mAddress;
ireg = mIns[j + 0].mAddress;
if (ireg == breg || reg == breg || ireg == reg)
return false;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
return false;
j--;
}
if (mFromJump)
{
while (j >= -6)
{
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
return false;
j--;
}
if (mFromJump->FindExternAddressSumY(mFromJump->mIns.Size(), reg, breg, ireg))
{
int k = 0;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
k++;
}
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::FindLoadAddressSumY(int at, int reg, int& apos, int& ireg)
{
int j = at - 7;
while (j >= 0)
{
if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode != ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == mIns[j + 0].mMode &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
ireg = mIns[j + 2].mAddress;
if (ireg == mIns[j + 3].mAddress || ireg == mIns[j + 6].mAddress)
return false;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
return false;
k++;
}
apos = j;
return true;
}
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1))
return false;
if (mIns[j + 6].mMode == ASMIM_INDIRECT_Y && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress + 1 == reg || mIns[j + 6].mAddress == reg + 1))
return false;
if (mIns[j + 6].mType == ASMIT_JSR)
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::PatchLoadAddressSumY(int at, int reg, int apos, int ireg)
{
mIns[apos + 1].mType = ASMIT_NOP; mIns[apos + 1].mMode = ASMIM_IMPLIED;
mIns[apos + 2].mType = ASMIT_NOP; mIns[apos + 2].mMode = ASMIM_IMPLIED;
mIns[apos + 5].mType = ASMIT_NOP; mIns[apos + 5].mMode = ASMIM_IMPLIED;
return true;
}
bool NativeCodeBasicBlock::FindAddressSumY(int at, int reg, int & apos, int& breg, int& ireg)
{
int j = at - 7;
while (j >= 0)
{
if (
#if 1
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 1].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 1].mAddress;
ireg = mIns[j + 2].mAddress;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
if (breg == reg || ireg == breg)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
return false;
}
else if (ireg == reg)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg)
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == ireg)
return false;
}
k++;
}
apos = j;
return true;
}
else if (
#endif
mIns[j + 0].mType == ASMIT_CLC &&
mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 2].mAddress;
ireg = mIns[j + 1].mAddress;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
if (breg == reg || ireg == breg)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
return false;
}
else if (ireg == reg)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg)
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == ireg)
return false;
}
k++;
}
apos = j;
return true;
}
else if (
mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 1].mType == ASMIT_CLC &&
mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
{
breg = mIns[j + 2].mAddress;
ireg = mIns[j + 0].mAddress;
int k = j + 7;
while (k < at)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
return false;
if (breg == reg || ireg == breg)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
return false;
if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
return false;
}
k++;
}
apos = j;
return true;
}
if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveIndirectLoadStoreDown(int at)
{
int j = at + 2;
while (j < mIns.Size())
{
if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 1].mAddress)
{
if (!(mIns[j].mLive & LIVE_MEM) && HasAsmInstructionMode(mIns[j].mType, ASMIM_INDIRECT_Y))
{
mIns[j].mMode = ASMIM_INDIRECT_Y;
mIns[j].mAddress = mIns[at].mAddress;
mIns[j].mLive |= LIVE_MEM;
mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
for (int k = at; k < j; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
return true;
}
return false;
}
if (mIns[j].ChangesYReg())
return false;
if (mIns[j].ChangesZeroPage(mIns[at].mAddress) || mIns[j].ChangesZeroPage(mIns[at].mAddress + 1))
return false;
if (mIns[j].ChangesGlobalMemory())
return false;
j++;
}
return false;
}
bool NativeCodeBasicBlock::MoveLDXBeforeZ(int at)
{
int i = at;
while (i > 0)
{
i--;
NativeCodeInstruction& ins(mIns[i]);
if (ins.ReferencesXReg())
return false;
if (ins.ChangesZFlag())
{
if (ins.ChangesAccuAndFlag())
{
mIns[at].mLive |= mIns[i].mLive;
mIns.Insert(i, mIns[at]);
mIns.Remove(at + 1);
mIns.Remove(at + 1);
for (int j = i; j < at + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
return true;
}
else
return false;
}
if (ins.ChangesXReg() || ins.ChangesAccu())
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveLDXUp(int at)
{
NativeCodeInstruction& lins(mIns[at]);
int i = at;
while (i > 0)
{
i--;
NativeCodeInstruction& ins(mIns[i]);
if (ins.mType == ASMIT_STA && ins.SameEffectiveAddress(lins))
{
if (ins.mLive & LIVE_CPU_REG_Z)
return false;
ins.mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 1, NativeCodeInstruction(lins.mIns, ASMIT_TAX));
mIns.Remove(at + 1);
while (i <= at)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
return true;
}
if (ins.ReferencesXReg() || lins.MayBeChangedOnAddress(ins))
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveLDYUp(int at)
{
NativeCodeInstruction& lins(mIns[at]);
int i = at;
while (i > 0)
{
i--;
NativeCodeInstruction& ins(mIns[i]);
if (ins.mType == ASMIT_STA && ins.SameEffectiveAddress(lins))
{
if (ins.mLive & LIVE_CPU_REG_Z)
return false;
ins.mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 1, NativeCodeInstruction(lins.mIns, ASMIT_TAY));
mIns.Remove(at + 1);
while (i <= at)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
return true;
}
if (ins.ReferencesYReg() || lins.MayBeChangedOnAddress(ins))
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveIndirectLoadStoreDownY(int at)
{
int j = at + 3;
int saddr = mIns[at + 1].mAddress, daddr = mIns[at + 2].mAddress;
NativeCodeBasicBlock* block = this;
while (block)
{
while (j < block->mIns.Size())
{
if (block->mIns[j].mMode == ASMIM_ZERO_PAGE && block->mIns[j].mAddress == daddr)
{
if (!(block->mIns[j].mLive & (LIVE_MEM | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(block->mIns[j].mType, ASMIM_INDIRECT_Y))
{
block->mIns[j].mMode = ASMIM_INDIRECT_Y;
block->mIns[j].mAddress = saddr;
block->mIns[j].mLive |= LIVE_MEM;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
block->mIns.Insert(j, NativeCodeInstruction(mIns[at + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[at + 0].mAddress));
while (block != this)
{
block->mEntryRequiredRegs += saddr;
block->mEntryRequiredRegs += saddr + 1;
block = block->mEntryBlocks[0];
block->mExitRequiredRegs += saddr;
block->mExitRequiredRegs += saddr + 1;
}
return true;
}
return false;
}
if (block->mIns[j].ReferencesZeroPage(daddr))
return false;
if (block->mIns[j].ChangesZeroPage(saddr) || block->mIns[j].ChangesZeroPage(saddr + 1))
return false;
if (block->mIns[j].ChangesGlobalMemory())
return false;
j++;
}
if (block->mFalseJump)
{
if (block->mTrueJump->mNumEntries == 1 && !block->mFalseJump->mEntryRequiredRegs[daddr])
{
block = block->mTrueJump;
j = 0;
}
else if (block->mFalseJump->mNumEntries == 1 && !block->mTrueJump->mEntryRequiredRegs[daddr])
{
block = block->mFalseJump;
j = 0;
}
else
block = nullptr;
}
else
block = nullptr;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadIndirectTempStoreUp(int at)
{
// ldy #imm
// lda (t0), y
// sta t1
int j = at - 1;
while (j >= 3)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
{
if (mIns[j - 3].mType == ASMIT_LDA && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 2].mType == ASMIT_STA && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 1].mType == ASMIT_LDA && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 0].mType == ASMIT_STA && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
{
for (int k = j + 1; k < at; k++)
mIns[k].mLive |= mIns[at + 2].mLive & LIVE_CPU_REG_Y;
mIns[at + 0].mLive |= mIns[j].mLive;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[at + 1].mAddress = mIns[j - 3].mAddress;
mIns[at + 1].mLive |= LIVE_MEM;
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Remove(at + 3);
mIns.Remove(at + 3);
mIns.Remove(at + 3);
return true;
}
}
return false;
}
if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
{
if (mIns[j - 3].mType == ASMIT_LDX && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 2].mType == ASMIT_STX && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 1].mType == ASMIT_LDX && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 0].mType == ASMIT_STX && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
{
int addr = mIns[j - 3].mAddress;
while (mIns[j].mLive & LIVE_CPU_REG_A)
{
j++;
if (mIns[j].ReferencesZeroPage(addr) || mIns[j].ReferencesZeroPage(addr + 1))
return false;
}
for (int k = j + 1; k < at; k++)
mIns[k].mLive |= mIns[at + 2].mLive & LIVE_CPU_REG_Y;
mIns[at + 0].mLive |= mIns[j].mLive;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[at + 1].mAddress = addr;
mIns[at + 1].mLive |= LIVE_MEM;
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Insert(j + 1, mIns[at + 2]);
mIns.Remove(at + 3);
mIns.Remove(at + 3);
mIns.Remove(at + 3);
return true;
}
}
return false;
}
if (mIns[j].ReferencesYReg())
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1))
return false;
if (mIns[j].ReferencesZeroPage(mIns[at + 2].mAddress))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadIndirectBypassYUp(int at)
{
// ldy #imm
// lda (t0), y
// move up, and keep A in Y for the interval
int j = at - 1;
while (j >= 3)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
{
if (mIns[j - 3].mType == ASMIT_LDA && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 2].mType == ASMIT_STA && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 1].mType == ASMIT_LDA && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 0].mType == ASMIT_STA && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
{
const InterInstruction* iins(mIns[at + 0].mIns);
mIns[at + 0].mLive |= mIns[j].mLive;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 1].mAddress = mIns[j - 3].mAddress;
mIns[at + 1].mLive |= LIVE_MEM;
mIns.Insert(j + 1, mIns[at + 0]);
mIns.Remove(at + 1);
mIns.Insert(j + 2, mIns[at + 1]);
mIns.Remove(at + 2);
mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_TYA));
mIns.Insert(j + 3, NativeCodeInstruction(iins, ASMIT_TAY));
for (int k = j + 3; k < at + 3; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
return true;
}
}
return false;
}
if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
{
if (mIns[j - 3].mType == ASMIT_LDX && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 2].mType == ASMIT_STX && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 1].mType == ASMIT_LDX && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
mIns[j - 0].mType == ASMIT_STX && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
{
const InterInstruction* iins(mIns[at + 0].mIns);
int addr = mIns[j - 3].mAddress;
while (mIns[j].mLive & LIVE_CPU_REG_A)
{
j++;
if (mIns[j].ReferencesZeroPage(addr) || mIns[j].ReferencesZeroPage(addr + 1))
return false;
}
mIns[at + 0].mLive |= mIns[j].mLive;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 1].mAddress = addr;
mIns[at + 1].mLive |= LIVE_MEM;
mIns.Insert(j + 1, mIns[at + 0]);
mIns.Remove(at + 1);
mIns.Insert(j + 2, mIns[at + 1]);
mIns.Remove(at + 2);
mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_TYA));
mIns.Insert(j + 3, NativeCodeInstruction(iins, ASMIT_TAY));
for (int k = j + 3; k < at + 3; k++)
mIns[k].mLive |= LIVE_CPU_REG_Y;
return true;
}
}
return false;
}
if (mIns[j].ReferencesYReg())
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveIndirectLoadStoreUp(int at)
{
int j = at - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_Y)
return false;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 1]);
mIns.Insert(j + 2, mIns[at + 3]);
mIns[at + 4].mType = ASMIT_NOP;
mIns[at + 4].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress)
{
if (j > 0 && mIns[j - 1].mType == ASMIT_LDY && mIns[j - 1].mMode == ASMIM_IMMEDIATE && mIns[j - 1].mAddress != mIns[at + 1].mAddress)
;
else
return false;
}
else if (mIns[at + 2].MayBeSameAddress(mIns[j]))
return false;
else if (mIns[j].mType == ASMIT_JSR)
return false;
if (mIns[j].ChangesZeroPage(mIns[at].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadStoreOutOfXYRangeUp(int at)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j].MayBeChangedOnAddress(mIns[at + 2]))
return false;
if (mIns[j].ChangesAddress() && mIns[j].SameEffectiveAddress(mIns[at + 1]))
return false;
if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg())
return false;
if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg())
return false;
if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].mType == ASMIT_JSR)
return false;
if (mIns[j].mType == ASMIT_LDA)
{
if (j > 0 && (mIns[j - 1].mType == ASMIT_CLC || mIns[j - 1].mType == ASMIT_SEC))
j--;
mIns.Insert(j, mIns[at + 2]);
mIns.Insert(j, mIns[at + 2]);
int live = 0;
if (j > 0)
live = mIns[j - 1].mLive;
else
{
if (mEntryRequiredRegs[CPU_REG_X])
live |= LIVE_CPU_REG_X;
if (mEntryRequiredRegs[CPU_REG_Y])
live |= LIVE_CPU_REG_Y;
}
mIns[j].mLive |= live;
mIns[j + 1].mLive |= live;
mIns.Remove(at + 3);
mIns.Remove(at + 3);
return true;
}
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveAbsoluteLoadStoreUp(int at)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
{
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 1]);
mIns[j + 1].mLive |= LIVE_CPU_REG_A;
mIns[j + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mType = ASMIT_NOP;
mIns[at + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[j].mType == ASMIT_LDA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
{
while (j < at && !mIns[j + 1].ChangesAccu() && (mIns[j].mLive & LIVE_CPU_REG_A))
j++;
if (j < at)
{
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 1]);
mIns[j + 1].mLive |= LIVE_CPU_REG_A;
mIns[j + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mType = ASMIT_NOP;
mIns[at + 2].mMode = ASMIM_IMPLIED;
return true;
}
else
return false;
}
if (mIns[j].ChangesZeroPage(mIns[at].mAddress))
return false;
if (mIns[j].MayBeSameAddress(mIns[at + 1], true))
return false;
if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg())
return false;
if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg())
return false;
if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[j].ChangesYReg() || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
return false;
if (mIns[j].mType == ASMIT_JSR)
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::ReplaceZeroPageDown(int at)
{
int i = at + 2;
while (i < mIns.Size())
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
mIns[i].mLive |= LIVE_CPU_REG_A;
mIns[at + 1].mLive |= mIns[i].mLive;
mIns.Insert(i + 1, mIns[at + 1]);
mIns.Remove(at, 2);
return true;
}
if (mIns[i].ChangesZeroPage(mIns[at].mAddress))
return false;
if (mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress))
return false;
i++;
}
return false;
}
bool NativeCodeBasicBlock::ReplaceZeroPageUp(int at)
{
int i = at - 1;
while (i >= 0)
{
if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
while (i < at)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
mIns[i].mAddress = mIns[at + 1].mAddress;
i++;
}
mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[i].mType == ASMIT_JSR)
return false;
if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[i].UsesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress == mIns[at + 1].mAddress || mIns[i].mAddress + 1 == mIns[at + 1].mAddress))
return false;
if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress == mIns[at].mAddress || mIns[i].mAddress + 1 == mIns[at].mAddress))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInstruction& lins, const NativeCodeInstruction& sins)
{
if (!mPatched)
{
mPatched = true;
if (at == -2)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].ChangesZeroPage(lins.mAddress))
return false;
if (mIns[i].ReferencesZeroPage(sins.mAddress))
return false;
if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress))
return false;
}
at = mIns.Size();
}
else
{
if (at == -1)
at = mIns.Size();
int i = at;
while (i > 0)
{
i--;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == lins.mAddress)
{
while (i < at)
{
if (mIns[i].mAddress == lins.mAddress)
mIns[i].mAddress = sins.mAddress;
i++;
}
return true;
}
if (mIns[i].ChangesZeroPage(lins.mAddress))
return false;
else if (mIns[i].mMode == ASMIM_ZERO_PAGE && !mIns[i].ChangesAddress() && mIns[i].mAddress == lins.mAddress)
;
else if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress))
return false;
else if (mIns[i].ReferencesZeroPage(sins.mAddress))
return false;
else if (mIns[i].mType == ASMIT_JSR && mIns[i].ReferencesZeroPage(lins.mAddress))
return false;
}
}
int pat = -1;
NativeCodeBasicBlock* eb = nullptr;
if (mEntryBlocks.Size() == 1 || mEntryBlocks.Size() == 2 && mEntryBlocks[1] == this)
{
eb = mEntryBlocks[0];
if (!eb->mFalseJump)
;
else if (eb->mTrueJump == eb || eb->mFalseJump == eb)
pat = -2;
else if (eb->mFalseJump->mPatched && eb->mTrueJump->mPatched)
;
else if (
eb->mTrueJump == this && !eb->mFalseJump->mEntryRequiredRegs[lins.mAddress] && !eb->mFalseJump->mEntryRequiredRegs[sins.mAddress] ||
eb->mFalseJump == this && !eb->mTrueJump->mEntryRequiredRegs[lins.mAddress] && !eb->mTrueJump->mEntryRequiredRegs[sins.mAddress])
;
else
return false;
}
else if (mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock* eb0 = mEntryBlocks[0];
NativeCodeBasicBlock* eb1 = mEntryBlocks[1];
if (eb0->mEntryBlocks.Size() == 1 && eb0->mEntryBlocks[0] == eb1)
eb = eb0;
else if (eb1->mEntryBlocks.Size() == 1 && eb1->mEntryBlocks[0] == eb0)
eb = eb1;
else
return false;
if (!eb->mFalseJump)
;
else if (eb->mTrueJump == eb || eb->mFalseJump == eb)
;
else if (eb->mFalseJump->mPatched && eb->mTrueJump->mPatched)
;
else if (
eb->mTrueJump == this && !eb->mFalseJump->mEntryRequiredRegs[lins.mAddress] && !eb->mFalseJump->mEntryRequiredRegs[sins.mAddress] ||
eb->mFalseJump == this && !eb->mTrueJump->mEntryRequiredRegs[lins.mAddress] && !eb->mTrueJump->mEntryRequiredRegs[sins.mAddress])
;
else
return false;
pat = -2;
}
else
return false;
if (!eb->MoveZeroPageCrossBlockUp(pat, lins, sins))
return false;
for(int i=0; i<at; i++)
{
if (mIns[i].mAddress == lins.mAddress)
mIns[i].mAddress = sins.mAddress;
}
mEntryRequiredRegs += lins.mAddress;
return true;
}
else
return false;
}
bool NativeCodeBasicBlock::ShortcutCrossBlockCondition(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int sz = mIns.Size();
if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !mFalseJump)
{
if (mTrueJump->mIns.Size() == 2 && mTrueJump->mIns[0].mType == ASMIT_STA &&
mTrueJump->mIns[1].mType == ASMIT_ORA && mTrueJump->mIns[1].mMode == ASMIM_IMMEDIATE && mTrueJump->mIns[1].mAddress == 0 &&
(mTrueJump->mBranch == ASMIT_BEQ || mTrueJump->mBranch == ASMIT_BNE))
{
mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if (mTrueJump->mBranch == ASMIT_BEQ)
{
if (mIns[sz - 1].mAddress == 0)
mTrueJump = mTrueJump->mTrueJump;
else
mTrueJump = mTrueJump->mFalseJump;
}
else
{
if (mIns[sz - 1].mAddress != 0)
mTrueJump = mTrueJump->mTrueJump;
else
mTrueJump = mTrueJump->mFalseJump;
}
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
changed = true;
}
}
if (mTrueJump && mTrueJump->ShortcutCrossBlockCondition())
changed = true;
if (mFalseJump && mFalseJump->ShortcutCrossBlockCondition())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ShortcutCrossBlockMoves(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (!mLoopHead)
{
int i = 0;
while (i + 1 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
proc->ResetPatched();
if (MoveZeroPageCrossBlockUp(i, mIns[i + 0], mIns[i + 1]))
{
changed = true;
mIns.Remove(i, 2);
}
else
i++;
}
else
i++;
}
CheckLive();
}
if (mTrueJump && mTrueJump->ShortcutCrossBlockMoves(proc))
changed = true;
if (mFalseJump && mFalseJump->ShortcutCrossBlockMoves(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Check16BitSum(int at, NativeRegisterSum16Info& info)
{
if (at + 6 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA &&
(mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 2].mAddress == 0) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 4].mType == ASMIT_LDA &&
mIns[at + 5].mType == ASMIT_ADC &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
{
info.mDstL = &(mIns[at + 3]);
info.mDstH = &(mIns[at + 6]);
if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && (mIns[at + 5].mMode == ASMIM_ZERO_PAGE || mIns[at + 5].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mAddress == 0))
{
if (mIns[at + 1].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE)
{
info.mAddress = (mIns[at + 1].mAddress & 0xff) + (mIns[at + 4].mAddress << 8);
info.mLinkerObject = nullptr;
info.mSrcL = &(mIns[at + 2]);
info.mSrcH = &(mIns[at + 5]);
info.mAddL = &(mIns[at + 1]);
info.mAddH = &(mIns[at + 4]);
info.mImmediate = true;
return true;
}
else if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 1].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 1].mAddress == mIns[at + 4].mAddress)
{
info.mAddress = mIns[at + 1].mAddress;
info.mLinkerObject = mIns[at + 1].mLinkerObject;
info.mSrcL = &(mIns[at + 2]);
info.mSrcH = &(mIns[at + 5]);
info.mAddL = &(mIns[at + 1]);
info.mAddH = &(mIns[at + 4]);
info.mImmediate = true;
return true;
}
}
else if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && (mIns[at + 4].mMode == ASMIM_ZERO_PAGE || mIns[at + 4].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mAddress == 0))
{
if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE)
{
info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8);
info.mLinkerObject = nullptr;
info.mSrcL = &(mIns[at + 1]);
info.mSrcH = &(mIns[at + 4]);
info.mAddL = &(mIns[at + 2]);
info.mAddH = &(mIns[at + 5]);
info.mImmediate = true;
return true;
}
else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress)
{
info.mAddress = mIns[at + 2].mAddress;
info.mLinkerObject = mIns[at + 2].mLinkerObject;
info.mSrcL = &(mIns[at + 1]);
info.mSrcH = &(mIns[at + 4]);
info.mAddL = &(mIns[at + 2]);
info.mAddH = &(mIns[at + 5]);
info.mImmediate = true;
return true;
}
}
if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mMode == ASMIM_ZERO_PAGE)
{
info.mSrcL = &(mIns[at + 1]);
info.mSrcH = &(mIns[at + 4]);
info.mAddL = &(mIns[at + 2]);
info.mAddH = &(mIns[at + 5]);
info.mImmediate = false;
return true;
}
}
else if (mIns[at + 0].mType == ASMIT_LDA &&
mIns[at + 1].mType == ASMIT_CLC &&
mIns[at + 2].mType == ASMIT_ADC &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 4].mType == ASMIT_LDA &&
mIns[at + 5].mType == ASMIT_ADC &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
{
info.mDstL = &(mIns[at + 3]);
info.mDstH = &(mIns[at + 6]);
if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[at + 5].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[at + 0].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE)
{
info.mAddress = (mIns[at + 0].mAddress & 0xff) + (mIns[at + 4].mAddress << 8);
info.mLinkerObject = nullptr;
info.mSrcL = &(mIns[at + 2]);
info.mSrcH = &(mIns[at + 5]);
info.mAddL = &(mIns[at + 0]);
info.mAddH = &(mIns[at + 4]);
info.mImmediate = true;
return true;
}
else if (mIns[at + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 0].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 0].mAddress == mIns[at + 4].mAddress)
{
info.mAddress = mIns[at + 0].mAddress;
info.mLinkerObject = mIns[at + 0].mLinkerObject;
info.mSrcL = &(mIns[at + 2]);
info.mSrcH = &(mIns[at + 5]);
info.mAddL = &(mIns[at + 0]);
info.mAddH = &(mIns[at + 4]);
info.mImmediate = true;
return true;
}
}
else if (mIns[at + 0].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE)
{
info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8);
info.mLinkerObject = nullptr;
info.mSrcL = &(mIns[at + 0]);
info.mSrcH = &(mIns[at + 4]);
info.mAddL = &(mIns[at + 2]);
info.mAddH = &(mIns[at + 5]);
info.mImmediate = true;
return true;
}
else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress)
{
info.mAddress = mIns[at + 2].mAddress;
info.mLinkerObject = mIns[at + 2].mLinkerObject;
info.mSrcL = &(mIns[at + 0]);
info.mSrcH = &(mIns[at + 4]);
info.mAddL = &(mIns[at + 2]);
info.mAddH = &(mIns[at + 5]);
info.mImmediate = true;
return true;
}
}
}
}
return false;
}
bool NativeCodeBasicBlock::IsFinalZeroPageUseTail(const NativeCodeBasicBlock* block, int from, int to, bool pair)
{
if (!mPatched)
{
mPatched = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mAddress == to)
return false;
if (pair && mIns[i].mAddress == to + 1)
return false;
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
if (mIns[i].mAddress == to || mIns[i].mAddress + 1 == to)
return false;
if (pair && mIns[i].mAddress == to + 1)
return false;
if (!pair && (mIns[i].mAddress == from || mIns[i].mAddress + 1 == from))
return false;
}
else if (mIns[i].ReferencesZeroPage(to) || (pair && mIns[i].ReferencesZeroPage(to + 1)))
return false;
else if (mIns[i].mType == ASMIT_JSR)
{
if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
{
if (to >= mIns[i].mParam && to < mIns[i].mParam + 4 ||
from >= mIns[i].mParam && from < mIns[i].mParam + 4)
return false;
}
}
}
if (mTrueJump && !mTrueJump->IsFinalZeroPageUseTail(block, from, to, pair))
return false;
if (mFalseJump && !mFalseJump->IsFinalZeroPageUseTail(block, from, to, pair))
return false;
}
return true;
}
static bool ZeroPageMayBeChangedOnBlockPathUp(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg)
{
ExpandingArray<const NativeCodeBasicBlock*> blocks;
blocks.Push(block);
int i = 0;
while (i < blocks.Size())
{
block = blocks[i++];
if (block != head)
{
if (block->ChangesZeroPage(reg))
return true;
for (int j = 0; j < block->mEntryBlocks.Size(); j++)
{
if (!blocks.Contains(block->mEntryBlocks[j]))
blocks.Push(block->mEntryBlocks[j]);
}
}
}
return false;
}
bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair, bool fchanged)
{
if (at == 0 && mVisited)
return false;
if (!mPatched)
{
if (at != 0 || (mEntryRequiredRegs[from] || mEntryRequiredRegs[to] || (pair && (mEntryRequiredRegs[from + 1] || mEntryRequiredRegs[to + 1]))))
{
mPatched = true;
if (at == 0)
{
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i] != block && !mEntryBlocks[i]->IsDominatedBy(block))
return false;
if (!fchanged && (ZeroPageMayBeChangedOnBlockPathUp(mEntryBlocks[i], block, from) || pair && ZeroPageMayBeChangedOnBlockPathUp(mEntryBlocks[i], block, from + 1)))
fchanged = true;
}
}
}
while (at < mIns.Size())
{
if (mIns[at].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[at].mAddress == to && (fchanged || mIns[at].ChangesAddress()))
return false;
if (pair && mIns[at].mAddress == to + 1 && (fchanged || mIns[at].ChangesAddress()))
return false;
if (mIns[at].mAddress == from && mIns[at].ChangesAddress())
fchanged = true;
if (pair && mIns[at].mAddress == from + 1 && mIns[at].ChangesAddress())
fchanged = true;
}
else if (mIns[at].mMode == ASMIM_INDIRECT_Y)
{
if (!pair && mIns[at].mAddress == to)
return false;
if (mIns[at].mAddress == to && (fchanged || mIns[at].ChangesAddress()))
return false;
if (mIns[at].mAddress + 1 == to)
return false;
if (pair && mIns[at].mAddress == to + 1)
return false;
if (!pair && mIns[at].mAddress == from)
return false;
if (mIns[at].mAddress + 1 == from)
return false;
if (pair && mIns[at].mAddress == from + 1)
return false;
}
else if (mIns[at].mType == ASMIT_JSR)
{
fchanged = true;
LinkerObject* lo = mIns[at].mLinkerObject;
if (lo)
{
for (int i = 0; i < lo->mNumTemporaries; i++)
{
if (from >= lo->mTemporaries[i] && from < lo->mTemporaries[i] + lo->mTempSizes[i] ||
to >= lo->mTemporaries[i] && to < lo->mTemporaries[i] + lo->mTempSizes[i])
return false;
}
}
if (mIns[at].mFlags & NCIF_USE_ZP_32_X)
{
if (to >= mIns[at].mParam && to < mIns[at].mParam + 4 ||
from >= mIns[at].mParam && from < mIns[at].mParam + 4)
return false;
}
}
at++;
}
if (mTrueJump && !mTrueJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged))
return false;
if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged))
return false;
}
else
return IsFinalZeroPageUseTail(block, from, to, pair);
}
return true;
}
bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc)
{
// return false;
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
mIns[i + 1].mAddress >= BC_REG_TMP)
{
nproc->ResetPatched();
if (IsFinalZeroPageUse(this, i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false, false))
{
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false))
changed = true;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
mIns[i + 1].mAddress >= BC_REG_TMP)
{
nproc->ResetPatched();
if (IsFinalZeroPageUse(this, i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, false))
{
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true))
changed = true;
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 4, mIns[i + 3].mAddress, mIns[i + 2].mAddress, false))
changed = true;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (i + 5 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ADC &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress + 1 &&
mIns[i + 4].mType == ASMIT_ADC && !mIns[i + 4].MayBeSameAddress(mIns[i + 2]) &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
mIns[i + 2].mAddress >= BC_REG_TMP)
{
nproc->ResetPatched();
if (IsFinalZeroPageUse(this, i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true, true))
{
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true))
changed = true;
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 6, mIns[i + 5].mAddress, mIns[i + 3].mAddress, false))
changed = true;
mIns[i + 2].mAddress = mIns[i + 0].mAddress;
mIns[i + 5].mAddress = mIns[i + 3].mAddress;
changed = true;
}
}
if (i + 4 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
mIns[i + 3].mType == ASMIT_ADC && !mIns[i + 3].MayBeSameAddress(mIns[i + 1]) &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
mIns[i + 1].mAddress >= BC_REG_TMP)
{
nproc->ResetPatched();
if (IsFinalZeroPageUse(this, i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, true))
{
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true))
changed = true;
nproc->ResetPatched();
if (ForwardReplaceZeroPage(i + 5, mIns[i + 4].mAddress, mIns[i + 2].mAddress, false))
changed = true;
mIns[i + 1].mAddress = mIns[i + 0].mAddress;
mIns[i + 4].mAddress = mIns[i + 2].mAddress;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->ReplaceFinalZeroPageUse(nproc))
changed = true;
if (mFalseJump && mFalseJump->ReplaceFinalZeroPageUse(nproc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Check16BitSum(const NativeCodeBasicBlock* block, int origin, int at, int reg)
{
if (!mEntryRequiredRegs.Size())
return false;
if (mPatched)
return true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return true;
mPatched = true;
}
for (int i = at; i < mIns.Size(); i++)
{
if (mIns[i].ReferencesZeroPage(reg))
{
if (block == this && i == origin)
return true;
if (mIns[i].mType == ASMIT_JSR)
return false;
if (mIns[i].UsesZeroPage(reg))
return false;
if (mIns[i].ChangesZeroPage(reg))
return true;
}
}
if (mTrueJump && !mTrueJump->Check16BitSum(block, origin, 0, reg))
return false;
if (mFalseJump && !mFalseJump->Check16BitSum(block, origin, 0, reg))
return false;
return true;
}
bool NativeCodeBasicBlock::EliminateUpper16BitSum(NativeCodeProcedure* nproc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
(mIns[i + 1].mType == ASMIT_ADC || mIns[i + 1].mType == ASMIT_SBC) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) &&
mIns[i + 2].mAddress != BC_REG_LOCALS + 1 && mIns[i + 2].mAddress != BC_REG_STACK + 1)
{
nproc->ResetPatched();
if (Check16BitSum(this, i, i + 3, mIns[i + 2].mAddress))
{
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;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->EliminateUpper16BitSum(nproc))
changed = true;
if (mFalseJump && mFalseJump->EliminateUpper16BitSum(nproc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Propagate16BitHighSum(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 5 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress + 1 && !(mIns[i + 3].mLive & LIVE_MEM) &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
{
bool success = false;
int taddr = mIns[i + 1].mAddress, saddr = mIns[i + 0].mAddress;
int j = i + 6;
while (j < mIns.Size())
{
if (mIns[j].mType == ASMIT_JSR)
break;
else if (mIns[j].ChangesZeroPage(saddr) || mIns[j].ChangesZeroPage(saddr + 1))
break;
else if (mIns[j].ChangesZeroPage(taddr) || mIns[j].ChangesZeroPage(taddr + 1))
break;
else if (mIns[j].UsesZeroPage(taddr + 1) && !(mIns[j].mLive & LIVE_MEM))
{
success = true;
break;
}
j++;
}
if (success)
{
mIns[i + 5].mAddress = saddr + 1;
for (int k = i + 6; k <= j; k++)
{
if (mIns[k].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[k].mAddress == taddr)
mIns[k].mAddress = saddr;
else if (mIns[k].mAddress == taddr + 1)
mIns[k].mAddress = saddr + 1;
}
else if (mIns[k].mMode == ASMIM_INDIRECT_Y)
{
if (mIns[k].mAddress == taddr)
mIns[k].mAddress = saddr;
}
}
changed = true;
}
}
}
if (mTrueJump && mTrueJump->Propagate16BitHighSum())
changed = true;
if (mFalseJump && mFalseJump->Propagate16BitHighSum())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::ForwardReplaceZeroPage(int at, int from, int to, bool pair)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
for (int i = at; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_INDIRECT_Y)
{
if (mIns[i].mAddress == from)
{
mIns[i].mAddress = to;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->ForwardReplaceZeroPage(0, from, to, pair))
changed = true;
if (mFalseJump && mFalseJump->ForwardReplaceZeroPage(0, from, to, pair))
changed = true;
if (mEntryRequiredRegs[from])
mEntryRequiredRegs += to;
}
return changed;
}
bool NativeCodeBasicBlock::CanZeroPageCopyUp(int at, int from, int to, bool diamond)
{
mPatchChecked = true;
while (at > 0)
{
at--;
if (mIns[at].mType == ASMIT_JSR)
return false;
if (mIns[at].mMode == ASMIM_ZERO_PAGE && mIns[at].mAddress == to)
return false;
if (mIns[at].mMode == ASMIM_INDIRECT_Y)
{
if (mIns[at].mAddress == from || mIns[at].mAddress == from - 1 ||
mIns[at].mAddress == to || mIns[at].mAddress == to - 1)
return false;
}
if (mIns[at].mMode == ASMIM_ZERO_PAGE && mIns[at].mAddress == from)
{
if (mIns[at].mType == ASMIT_STA || mIns[at].mType == ASMIT_STX || mIns[at].mType == ASMIT_STY)
{
if (!diamond)
return true;
if (mEntryRequiredRegs[from])
{
if (mEntryRequiredRegs[to])
return false;
int i = 0;
while (i < at && !mIns[i].ReferencesZeroPage(from))
{
if (mIns[i].ReferencesZeroPage(to))
return false;
i++;
}
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == to)
{
return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, false);
}
return false;
}
return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, false);
}
}
}
if (mLoopHead)
return false;
if (mEntryBlocks.Size() == 1)
{
if (mEntryBlocks[0]->mFalseJump)
{
if (this == mEntryBlocks[0]->mTrueJump)
{
if (mEntryBlocks[0]->mFalseJump->mEntryRequiredRegs[from] || mEntryBlocks[0]->mFalseJump->mEntryRequiredRegs[to])
return false;
}
else
{
if (mEntryBlocks[0]->mTrueJump->mEntryRequiredRegs[from] || mEntryBlocks[0]->mTrueJump->mEntryRequiredRegs[to])
return false;
}
}
return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, false);
}
else if (mEntryBlocks.Size() == 2)
{
if (mEntryBlocks[0]->mTrueJump == this && mEntryBlocks[0]->mFalseJump == mEntryBlocks[1] && !mEntryBlocks[1]->mFalseJump ||
mEntryBlocks[0]->mFalseJump == this && mEntryBlocks[0]->mTrueJump == mEntryBlocks[1] && !mEntryBlocks[1]->mFalseJump)
return mEntryBlocks[1]->CanZeroPageCopyUp(mEntryBlocks[1]->mIns.Size(), from, to, true);
else if (mEntryBlocks[1]->mTrueJump == this && mEntryBlocks[1]->mFalseJump == mEntryBlocks[0] && !mEntryBlocks[0]->mFalseJump ||
mEntryBlocks[1]->mFalseJump == this && mEntryBlocks[1]->mTrueJump == mEntryBlocks[0] && !mEntryBlocks[0]->mFalseJump)
return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, true);
}
return false;
}
bool NativeCodeBasicBlock::ShortcutZeroPageCopyUp(NativeCodeProcedure* nproc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
nproc->ResetPatched();
if (CanZeroPageCopyUp(i, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false))
{
BackwardReplaceZeroPage(i, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false);
changed = true;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
}
}
if (mTrueJump && mTrueJump->ShortcutZeroPageCopyUp(nproc))
changed = true;
if (mFalseJump && mFalseJump->ShortcutZeroPageCopyUp(nproc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::IsSameRegisterSource(const NativeCodeInstruction& rins) const
{
for (int i = mIns.Size() - 1; i >= 0; i--)
{
const NativeCodeInstruction& ins(mIns[i]);
if (rins.IsSame(ins))
return true;
if (rins.mType == ASMIT_LDY && ins.ChangesYReg())
return false;
if (rins.mType == ASMIT_LDX && ins.ChangesXReg())
return false;
if (rins.mType == ASMIT_LDA && ins.ChangesAccu())
return false;
if (rins.MayBeChangedOnAddress(ins))
return false;
}
if (mLoopHead || mEntryBlocks.Size() == 0)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsSameRegisterSource(rins))
return false;
return true;
}
bool NativeCodeBasicBlock::FindInitialLoadA(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesAccu())
return false;
}
return false;
}
bool NativeCodeBasicBlock::FindInitialLoadX(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesXReg())
return false;
}
return false;
}
bool NativeCodeBasicBlock::FindInitialLoadY(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesYReg())
return false;
}
return false;
}
bool NativeCodeBasicBlock::HoistCommonLoads(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
{
NativeCodeInstruction * tins = nullptr, * fins = nullptr;
if (!mExitRequiredRegs[CPU_REG_A] && mTrueJump->FindInitialLoadA(tins) && mFalseJump->FindInitialLoadA(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesAccu(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (!mExitRequiredRegs[CPU_REG_X] && mTrueJump->FindInitialLoadX(tins) && mFalseJump->FindInitialLoadX(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesXReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (!mExitRequiredRegs[CPU_REG_Y] && mTrueJump->FindInitialLoadY(tins) && mFalseJump->FindInitialLoadY(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesYReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->HoistCommonLoads())
changed = true;
if (mFalseJump && mFalseJump->HoistCommonLoads())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PartialBackwardValuePropagation(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (!mLoopHead && mEntryBlocks.Size() > 1)
{
bool afail = mEntryRequiredRegs[CPU_REG_A];
bool xfail = mEntryRequiredRegs[CPU_REG_X];
bool yfail = mEntryRequiredRegs[CPU_REG_Y];
int i = 0;
while (i < mIns.Size() && !(afail && xfail && yfail))
{
NativeCodeInstruction& ins(mIns[i]);
if ((!yfail && ins.mType == ASMIT_LDY || !xfail && ins.mType == ASMIT_LDX || !afail && ins.mType == ASMIT_LDA)
&& (ins.mMode == ASMIM_IMMEDIATE || ins.mMode == ASMIM_IMMEDIATE_ADDRESS || ins.mMode == ASMIM_ZERO_PAGE)
&& !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
{
if (ins.mMode != ASMIM_ZERO_PAGE || !ChangesZeroPage(ins.mAddress, 0, i))
{
int j = 0;
while (j < mEntryBlocks.Size() && !mEntryBlocks[j]->IsSameRegisterSource(ins))
j++;
if (j < mEntryBlocks.Size())
{
NativeCodeBasicBlock* pblock = mProc->AllocateBlock();
pblock->mEntryRequiredRegs = mEntryRequiredRegs;
pblock->mExitRequiredRegs = mEntryRequiredRegs;
pblock->mIns.Push(ins);
pblock->Close(ins.mIns, this, nullptr, ASMIT_JMP);
while (j > 0)
{
j--;
NativeCodeBasicBlock* eblock = mEntryBlocks[j];
mEntryBlocks.Remove(j);
mNumEntries--;
if (eblock->mTrueJump == this)
eblock->mTrueJump = pblock;
else if (eblock->mFalseJump == this)
eblock->mFalseJump = pblock;
pblock->mEntryBlocks.Push(eblock);
pblock->mNumEntries++;
}
j++;
while (j < mEntryBlocks.Size())
{
if (mEntryBlocks[j]->IsSameRegisterSource(ins))
j++;
else
{
NativeCodeBasicBlock* eblock = mEntryBlocks[j];
mEntryBlocks.Remove(j);
mNumEntries--;
if (eblock->mTrueJump == this)
eblock->mTrueJump = pblock;
else if (eblock->mFalseJump == this)
eblock->mFalseJump = pblock;
pblock->mEntryBlocks.Push(eblock);
pblock->mNumEntries++;
}
}
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
mEntryBlocks.Push(pblock);
mNumEntries++;
changed = true;
}
}
}
if (ins.ChangesYReg())
yfail = true;
if (ins.ChangesXReg())
xfail = true;
if (ins.ChangesAccu())
afail = true;
i++;
}
}
if (mTrueJump && mTrueJump->PartialBackwardValuePropagation())
changed = true;
if (mFalseJump && mFalseJump->PartialBackwardValuePropagation())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::BackwardReplaceZeroPage(int at, int from, int to, bool diamond)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
assert(mPatchChecked);
if (at == mIns.Size())
mExitRequiredRegs += to;
bool done = false;
while (at > 0)
{
at--;
if (mIns[at].mMode == ASMIM_ZERO_PAGE && mIns[at].mAddress == from)
{
mIns[at].mAddress = to;
changed = true;
if (mIns[at].mType == ASMIT_STA || mIns[at].mType == ASMIT_STX || mIns[at].mType == ASMIT_STY)
{
done = true;
break;
}
}
}
mEntryRequiredRegs += to;
if (diamond)
{
if (mEntryRequiredRegs[from])
{
int i = 0;
while (i < at && !mIns[i].ReferencesZeroPage(from))
i++;
if (i < at)
{
mIns[i].mAddress = to;
changed = true;
}
}
if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, false))
changed = true;
}
else if (!done)
{
if (mEntryBlocks.Size() == 1)
{
if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, false))
changed = true;
}
else if (mEntryBlocks.Size() == 2)
{
if (mEntryBlocks[0]->mTrueJump == this && mEntryBlocks[0]->mFalseJump == mEntryBlocks[1] && !mEntryBlocks[1]->mFalseJump ||
mEntryBlocks[0]->mFalseJump == this && mEntryBlocks[0]->mTrueJump == mEntryBlocks[1] && !mEntryBlocks[1]->mFalseJump)
{
if (mEntryBlocks[1]->BackwardReplaceZeroPage(mEntryBlocks[1]->mIns.Size(), from, to, true))
changed = true;
}
else if (mEntryBlocks[1]->mTrueJump == this && mEntryBlocks[1]->mFalseJump == mEntryBlocks[0] && !mEntryBlocks[0]->mFalseJump ||
mEntryBlocks[1]->mFalseJump == this && mEntryBlocks[1]->mTrueJump == mEntryBlocks[0] && !mEntryBlocks[0]->mFalseJump)
{
if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, true))
changed = true;
}
}
}
}
return changed;
}
bool NativeRegisterSum16Info::operator==(const NativeRegisterSum16Info& ri) const
{
if (mSrcL != ri.mSrcL || mSrcH != ri.mSrcH || mAddL != ri.mAddL || mAddH != ri.mAddH || mDstL != ri.mDstL || mDstH != ri.mDstH)
return false;
if (mImmediate)
return mAddress == ri.mAddress && mLinkerObject == ri.mLinkerObject;
else
return true;
}
bool NativeRegisterSum16Info::operator!=(const NativeRegisterSum16Info& ri) const
{
return !(*this == ri);
}
bool NativeCodeBasicBlock::Propagate16BitSum(const ExpandingArray<NativeRegisterSum16Info> & cinfo)
{
bool changed = false;
if (!mVisited)
{
if (mLoopHead)
mRSumInfos.SetSize(0);
else
{
if (mNumEntered == 0)
mRSumInfos = cinfo;
else
{
int i = 0;
while (i < mRSumInfos.Size())
{
if (cinfo.Contains(mRSumInfos[i]))
i++;
else
mRSumInfos.Remove(i);
}
}
mNumEntered++;
if (mNumEntered < mNumEntries)
return false;
}
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeRegisterSum16Info info;
if (Check16BitSum(i, info))
{
for (int j = 0; j < mRSumInfos.Size(); j++)
{
if (info.mSrcL->mAddress == mRSumInfos[j].mDstL->mAddress && info.mSrcH->mAddress == mRSumInfos[j].mDstH->mAddress)
{
if (info.mImmediate && mRSumInfos[j].mImmediate)
{
if (!info.mLinkerObject && !mRSumInfos[j].mLinkerObject)
{
info.mAddress += mRSumInfos[j].mAddress;
info.mAddL->mType = ASMIT_ADC;
info.mAddL->mAddress = info.mAddress & 0xff;
info.mAddH->mAddress = info.mAddress >> 8;
info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
changed = true;
}
else if (!mRSumInfos[j].mLinkerObject)
{
info.mAddress += mRSumInfos[j].mAddress;
info.mAddL->mType = ASMIT_ADC;
info.mAddL->mAddress = info.mAddress;
info.mAddH->mAddress = info.mAddress;
info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
changed = true;
}
else if (!info.mLinkerObject)
{
info.mAddress += mRSumInfos[j].mAddress;
info.mLinkerObject = mRSumInfos[j].mLinkerObject;
info.mAddL->mType = ASMIT_ADC;
info.mAddL->mAddress = info.mAddress;
info.mAddL->mLinkerObject = info.mLinkerObject;
info.mAddL->mMode = ASMIM_IMMEDIATE_ADDRESS;
info.mAddL->mFlags = NCIF_LOWER;
info.mAddH->mAddress = info.mAddress;
info.mAddH->mLinkerObject = info.mLinkerObject;
info.mAddH->mMode = ASMIM_IMMEDIATE_ADDRESS;
info.mAddH->mFlags = NCIF_UPPER;
info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
changed = true;
}
}
}
else if (info.mSrcL->mAddress == mRSumInfos[j].mSrcL->mAddress && info.mSrcH->mAddress == mRSumInfos[j].mSrcH->mAddress)
{
if (info.mAddH->mMode == ASMIM_IMMEDIATE && mRSumInfos[j].mAddH->mMode == ASMIM_IMMEDIATE &&
info.mAddL->mMode == ASMIM_ZERO_PAGE && mRSumInfos[j].mAddL->mMode == ASMIM_ZERO_PAGE && info.mAddL->mAddress == mRSumInfos[j].mAddL->mAddress)
{
info.mAddL->mType = ASMIT_NOP; info.mAddL->mMode = ASMIM_IMPLIED;
info.mSrcL->mAddress = mRSumInfos[j].mDstL->mAddress;
info.mSrcH->mAddress = mRSumInfos[j].mDstH->mAddress;
info.mAddH->mAddress -= mRSumInfos[j].mAddH->mAddress;
changed = true;
}
else if (info.mAddL->mMode == ASMIM_IMMEDIATE && info.mAddH->mMode == ASMIM_IMMEDIATE &&
mRSumInfos[j].mAddL->mMode == ASMIM_IMMEDIATE && mRSumInfos[j].mAddH->mMode == ASMIM_IMMEDIATE)
{
if (info.mAddress == mRSumInfos[j].mAddress)
{
info.mSrcL->mAddress = mRSumInfos[j].mDstL->mAddress;
info.mSrcH->mAddress = mRSumInfos[j].mDstH->mAddress;
info.mAddL->mType = ASMIT_NOP; info.mAddL->mMode = ASMIM_IMPLIED;
info.mAddH->mType = ASMIT_NOP; info.mAddH->mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
}
if (info.mSrcL->mAddress != info.mDstL->mAddress && (info.mSrcH->mMode == ASMIM_IMMEDIATE || info.mSrcH->mAddress != info.mDstH->mAddress))
mRSumInfos.Push(info);
}
int j = 0;
while (j < mRSumInfos.Size())
{
if (mRSumInfos[j].mDstL != &(mIns[i]) && mRSumInfos[j].mDstH != &(mIns[i]))
{
if (
mRSumInfos[j].mSrcL->MayBeChangedOnAddress(mIns[i]) ||
mRSumInfos[j].mSrcH->MayBeChangedOnAddress(mIns[i]) ||
mRSumInfos[j].mAddL->MayBeChangedOnAddress(mIns[i]) ||
mRSumInfos[j].mAddH->MayBeChangedOnAddress(mIns[i]) ||
mRSumInfos[j].mDstL->MayBeChangedOnAddress(mIns[i]) ||
mRSumInfos[j].mDstH->MayBeChangedOnAddress(mIns[i]))
{
mRSumInfos.Remove(j);
}
else
j++;
}
else
j++;
}
}
if (mTrueJump && mTrueJump->Propagate16BitSum(mRSumInfos))
changed = true;
if (mFalseJump && mFalseJump->Propagate16BitSum(mRSumInfos))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::MoveLoadXUp(int at)
{
int i = at - 1;
while (i >= 0)
{
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
mIns[i].mType = ASMIT_TAX;
mIns[i].mMode = ASMIM_IMPLIED;
mIns[at].mType = ASMIT_NOP;
mIns[at].mMode = ASMIM_IMPLIED;
while (i < at)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
return true;
}
else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
mIns[i].mType = ASMIT_LDX;
mIns[i].mLive |= LIVE_MEM;
mIns[at].mType = ASMIT_INX;
mIns[at].mMode = ASMIM_IMPLIED;
while (i < at)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
return true;
}
if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X) || mIns[i].UsesZeroPage(mIns[at].mAddress))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::MoveStoreXUp(int at)
{
bool done = false;
int n = 0, inc = 0;;
int reg = mIns[at].mAddress;
while (at > 0)
{
if (mIns[at - 1].mType == ASMIT_INX)
{
n++;
inc++;
}
else if (mIns[at - 1].mType == ASMIT_DEX)
{
n++;
inc--;
}
else
{
if (mIns[at - 1].mType == ASMIT_LDX || mIns[at - 1].mType == ASMIT_TAX || mIns[at - 1].mType == ASMIT_TXA)
return done;
else if (mIns[at - 1].ChangesXReg() || mIns[at - 1].mType == ASMIT_STX)
return done;
else if (mIns[at + n].mMode == ASMIM_ZERO_PAGE)
{
if ((mIns[at - 1].mMode == ASMIM_ZERO_PAGE || mIns[at - 1].mMode == ASMIM_INDIRECT_Y) && mIns[at - 1].mAddress == reg)
return done;
if (mIns[at - 1].mMode == ASMIM_INDIRECT_Y && mIns[at - 1].mAddress + 1 == reg)
return done;
}
else
{
if (mIns[at - 1].mMode == ASMIM_ABSOLUTE && mIns[at - 1].mLinkerObject == mIns[at + n].mLinkerObject && mIns[at - 1].mAddress == mIns[at + n].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 + n].mLinkerObject)
return done;
}
if (mIns[at - 1].mMode == ASMIM_ABSOLUTE_X && inc)
{
if (!mIns[at - 1].mLinkerObject || mIns[at - 1].mLinkerObject->mSize > 255)
return done;
}
if (n > 0 && mIns[at + n].mLive & LIVE_CPU_REG_Z)
{
if (mIns[at - 1].ChangesZFlag())
return done;
mIns[at - 1].mLive |= LIVE_CPU_REG_Z;
}
int live = mIns[at - 1].mLive;
mIns[at + n].mLive |= LIVE_CPU_REG_X;
NativeCodeInstruction ins = mIns[at - 1];
if (ins.mMode == ASMIM_ABSOLUTE_X)
ins.mAddress -= inc;
if (ins.RequiresCarry()) live |= LIVE_CPU_REG_C;
if (ins.RequiresYReg()) live |= LIVE_CPU_REG_Y;
if (ins.RequiresAccu()) live |= LIVE_CPU_REG_A;
for (int i = 0; i <= n; i++)
{
mIns[at + i].mLive |= live;
mIns[at - 1 + i] = mIns[at + i];
}
mIns[at + n] = ins;
if (ins.mType != ASMIT_STY)
done = true;
}
at--;
}
return done;
}
bool NativeCodeBasicBlock::MoveLoadYUp(int at)
{
int i = at - 1;
while (i >= 0)
{
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
mIns[at].mType = ASMIT_NOP;
mIns[at].mMode = ASMIM_IMPLIED;
while (i < at)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
return true;
}
else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
{
mIns[i].mType = ASMIT_LDY;
mIns[i].mLive |= LIVE_MEM;
mIns[at].mType = ASMIT_INY;
mIns[at].mMode = ASMIM_IMPLIED;
while (i < at)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
return true;
}
if (mIns[i].RequiresYReg() || mIns[i].ChangesYReg() || (mIns[i].mLive & LIVE_CPU_REG_Y) || mIns[i].UsesZeroPage(mIns[at].mAddress))
return false;
i--;
}
return false;
}
bool NativeCodeBasicBlock::MoveStoreYUp(int at)
{
bool done = false;
while (at > 0)
{
if (mIns[at - 1].ChangesYReg() || mIns[at - 1].mType == ASMIT_STY)
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 + 1 == mIns[at].mAddress)
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;
mIns[at].mLive |= LIVE_CPU_REG_Y;
NativeCodeInstruction ins = mIns[at - 1];
if (ins.RequiresXReg()) mIns[at].mLive |= LIVE_CPU_REG_X;
if (ins.RequiresAccu()) mIns[at].mLive |= LIVE_CPU_REG_A;
if (ins.RequiresCarry()) mIns[at].mLive |= LIVE_CPU_REG_C;
mIns[at - 1] = mIns[at];
mIns[at] = ins;
at--;
if (ins.mType != ASMIT_STX)
done = true;
}
return done;
}
bool NativeCodeBasicBlock::MoveStoreHighByteDown(int at)
{
int i = at + 4;
while (i + 1 < mIns.Size())
{
if (mIns[i].mLive & LIVE_CPU_REG_Y)
return false;
if (mIns[i].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 2].mAddress + 1) || mIns[i].ChangesZeroPage(mIns[at + 3].mAddress))
return false;
if (mIns[i].UsesZeroPage(mIns[at + 3].mAddress))
return false;
if (mIns[i].ChangesGlobalMemory())
return false;
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns.Insert(i + 1, mIns[at + 3]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Insert(i + 1, mIns[at + 2]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Insert(i + 1, mIns[at + 1]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; // LDY
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; // LDA (x), y
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED; // STA T
return true;
}
i++;
}
return false;
}
bool NativeCodeBasicBlock::MoveAddHighByteDown(int at)
{
int i = at + 4;
while (i + 1 < mIns.Size())
{
if (mIns[i].mLive & LIVE_CPU_REG_C)
return false;
if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 3].mAddress))
return false;
if (mIns[i].UsesZeroPage(mIns[at + 3].mAddress))
return false;
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
for (int j = at + 4; j < i + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_C;
mIns.Insert(i + 1, mIns[at + 3]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Insert(i + 1, mIns[at + 2]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns.Insert(i + 1, mIns[at + 1]); mIns[i + 1].mLive |= mIns[i].mLive;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; // LDA U
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; // ADC #
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED; // STA T
return true;
}
i++;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadImmStoreAbsoluteUp(int at)
{
int j = at;
while (j > 0)
{
if (mIns[j - 1].mType == ASMIT_LDA && (mIns[j - 1].mMode == ASMIM_IMMEDIATE || mIns[j - 1].mMode == ASMIM_ZERO_PAGE))
{
if (mIns[j - 1].mMode == mIns[at + 0].mMode && mIns[j - 1].mAddress == mIns[at + 0].mAddress)
{
while (j < at && mIns[j].mType == ASMIT_STA)
j++;
mIns[j - 1].mLive |= LIVE_CPU_REG_A;
NativeCodeInstruction sins = mIns[at + 1];
mIns.Remove(at + 1);
if (!(sins.mLive & LIVE_CPU_REG_A))
mIns.Remove(at);
if (sins.ReferencesXReg())
sins.mLive |= LIVE_CPU_REG_X;
if (sins.ReferencesYReg())
sins.mLive |= LIVE_CPU_REG_Y;
mIns.Insert(j, sins);
return true;
}
else if (mIns[j - 1].mMode == mIns[at + 1].mMode && mIns[j - 1].mAddress == mIns[at + 1].mAddress)
return false;
j--;
}
else if (mIns[j - 1].mType == ASMIT_STA && mIns[j - 1].mMode == mIns[at + 1].mMode && !(mIns[j - 1].mLinkerObject == mIns[at + 1].mLinkerObject && mIns[j - 1].mAddress == mIns[at + 1].mAddress))
j--;
else
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadStoreUp(int at)
{
int j = at;
while (j > 0 && !((mIns[j - 1].mType == ASMIT_STA || mIns[j - 1].mType == ASMIT_LDA) && mIns[j - 1].mMode == ASMIM_ZERO_PAGE && mIns[j - 1].mAddress == mIns[at].mAddress))
{
j--;
if ((mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_INDIRECT_Y) && mIns[j].mAddress == mIns[at + 1].mAddress)
return false;
if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress + 1 == mIns[at + 1].mAddress)
return false;
if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress && mIns[j].ChangesAddress())
return false;
if (mIns[j].mMode == ASMIM_ABSOLUTE_Y && mIns[j].mAddress <= mIns[at + 1].mAddress && mIns[j].mType == ASMIT_LDA && !mIns[j].mLinkerObject)
return false;
if (mIns[j].mType == ASMIT_JSR)
return false;
}
if (j > 0 && j < at)
{
mIns.Insert(j, mIns[at + 1]);
mIns[j - 1].mLive |= LIVE_CPU_REG_A;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[j].mLive |= mIns[j - 1].mLive;
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
return true;
}
return false;
}
// Assume [at ] = SHIFT
// Assume [at + 1] = ORA
bool NativeCodeBasicBlock::FoldShiftORAIntoLoadImmUp(int at)
{
int ora = mIns[at + 1].mAddress;
int i = at;
while (i >= 0)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE)
{
mIns[i].mAddress |= ora;
mIns[at + 1].mType = ASMIT_NOP;
mIns[at + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if ((mIns[i].mType == ASMIT_ROL || mIns[i].mType == ASMIT_ASL) && mIns[i].mMode == ASMIM_IMPLIED)
{
if ((mIns[i].mLive & LIVE_CPU_REG_C) || (ora & 0x01))
return false;
ora >>= 1;
}
else if ((mIns[i].mType == ASMIT_ROR || mIns[i].mType == ASMIT_LSR) && mIns[i].mMode == ASMIM_IMPLIED)
{
if ((mIns[i].mLive & LIVE_CPU_REG_C) || (ora & 0x80))
return false;
ora <<= 1;
}
else if (mIns[i].ReferencesAccu())
return false;
i--;
}
return false;
}
// TAX
// CLC
// ADC #1, 2, 3
// STA
//
// convert to INX/DEX/STX when X not needed anymore
bool NativeCodeBasicBlock::MoveTAXADCSTADown(int at)
{
int n = mIns[at + 2].mAddress;
int addr = mIns[at + 3].mAddress;
int si = at + 4;
while (si < mIns.Size())
{
if (!(mIns[si].mLive & LIVE_CPU_REG_X))
{
if (mIns[si].mLive & LIVE_CPU_REG_Z)
return false;
mIns[si].mLive |= LIVE_CPU_REG_X;
si++;
for (int i = 0; i < n; i++)
{
mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_INX));
si++;
}
mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr));
return true;
}
if (mIns[si].ChangesXReg())
return false;
if (mIns[si].ReferencesZeroPage(addr))
return false;
si++;
}
return false;
}
// CLC
// LDA zp0
// ADC #1, 2, 3
// STA zp1
// ...
// LDX zp1
//
// Convert to INX/DEX
bool NativeCodeBasicBlock::MoveSimpleADCToINCDECDown(int at)
{
if (at >= 4)
{
int si = at - 4;
while (si >= 0)
{
if (mIns[si + 3].ReferencesZeroPage(mIns[at].mAddress))
{
if (mIns[si + 0].mType == ASMIT_CLC &&
mIns[si + 1].mType == ASMIT_LDA && mIns[si + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[si + 2].mType == ASMIT_ADC && mIns[si + 2].mMode == ASMIM_IMMEDIATE && (mIns[si + 2].mAddress >= 0 && mIns[si + 2].mAddress <= 4) &&
mIns[si + 3].mType == ASMIT_STA && !(mIns[si + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
int i = si + 4;
while (i < at && !mIns[i].ChangesZeroPage(mIns[si + 1].mAddress))
i++;
if (i != at)
return false;
AsmInsType t = mIns[at].mType == ASMIT_LDX ? ASMIT_INX : ASMIT_INY;
mIns[at].mAddress = mIns[si + 1].mAddress;
for (int i = 0; i < mIns[si + 2].mAddress; i++)
mIns.Insert(at + 1, NativeCodeInstruction(mIns[si].mIns, t));
mIns[si + 0].mType = ASMIT_NOP; mIns[si + 0].mMode = ASMIM_IMPLIED;
mIns[si + 1].mType = ASMIT_NOP; mIns[si + 1].mMode = ASMIM_IMPLIED;
mIns[si + 2].mType = ASMIT_NOP; mIns[si + 2].mMode = ASMIM_IMPLIED;
mIns[si + 3].mType = ASMIT_NOP; mIns[si + 3].mMode = ASMIM_IMPLIED;
return true;
}
else
return false;
}
si--;
}
}
return false;
}
bool NativeCodeBasicBlock::CombineImmediateADCUp(int at)
{
int addr = mIns[at].mAddress;
int i = at;
while (i > 3)
{
i--;
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[i - 3].mType == ASMIT_CLC &&
mIns[i - 2].mType == ASMIT_LDA && mIns[i - 2].mMode == ASMIM_ZERO_PAGE && mIns[i - 2].mAddress == addr &&
mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
{
int val = mIns[at + 1].mAddress;
mIns[at + 1].CopyMode(mIns[i - 1]);
if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
mIns[at + 1].mAddress += val * 256;
else
mIns[at + 1].mAddress += val;
mIns.Remove(i - 3, 4);
return true;
}
else if (mIns[i - 3].mType == ASMIT_CLC &&
mIns[i - 2].mType == ASMIT_LDA && (mIns[i - 2].mMode == ASMIM_IMMEDIATE || mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
mIns[i - 1].mType == ASMIT_ADC && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == addr)
{
int val = mIns[at + 1].mAddress;
mIns[at + 1].CopyMode(mIns[i - 2]);
if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
mIns[at + 1].mAddress += val * 256;
else
mIns[at + 1].mAddress += val;
mIns.Remove(i - 3, 4);
return true;
}
else if
(mIns[i - 2].mType == ASMIT_CLC &&
mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
{
int val = mIns[at + 1].mAddress;
mIns[at + 1].CopyMode(mIns[i - 1]);
if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
mIns[at + 1].mAddress += val * 256;
else
mIns[at + 1].mAddress += val;
mIns.Remove(i - 2, 2);
return true;
}
}
return false;
}
if (mIns[i].ReferencesZeroPage(addr))
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveTXADCDown(int at)
{
int i = at + 4;
while (i < mIns.Size())
{
if (mIns[i].ChangesXReg())
return false;
if (mIns[i].ReferencesZeroPage(mIns[at + 3].mAddress))
return false;
if (!(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 3].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[at + 3].mAddress));
switch (mIns[at + 2].mAddress)
{
case -2:
case 254:
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_DEX));
case -1:
case 255:
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_DEX));
break;
case 2:
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_INX));
case 1:
mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_INX));
break;
}
while (i > at)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i--;
}
mIns.Remove(at, 4);
return true;
}
i++;
}
return false;
}
bool NativeCodeBasicBlock::CombineImmediateADCUpX(int at)
{
int i = at;
while (i > 3)
{
i--;
if (mIns[i].mType == ASMIT_TAX)
{
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[i - 3].mType == ASMIT_CLC &&
mIns[i - 2].mType == ASMIT_LDA &&
mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
{
int val = mIns[at + 1].mAddress;
mIns[at + 1].CopyMode(mIns[i - 1]);
if (mIns[at + 1].mFlags & NCIF_UPPER)
mIns[at + 1].mAddress += val * 256;
else
mIns[at + 1].mAddress += val;
mIns[i - 1].mType = ASMIT_NOP; mIns[i - 1].mMode = ASMIM_IMPLIED;
mIns[i - 3].mType = ASMIT_NOP; mIns[i - 3].mMode = ASMIM_IMPLIED;
return true;
}
else if
(mIns[i - 2].mType == ASMIT_CLC &&
mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
{
int val = mIns[at + 1].mAddress;
mIns[at + 1].CopyMode(mIns[i - 1]);
if (mIns[at + 1].mFlags & NCIF_UPPER)
mIns[at + 1].mAddress += val * 256;
else
mIns[at + 1].mAddress += val;
mIns[i - 2].mType = ASMIT_NOP; mIns[i - 2].mMode = ASMIM_IMPLIED;
mIns[i - 1].mType = ASMIT_NOP; mIns[i - 1].mMode = ASMIM_IMPLIED;
return true;
}
}
return false;
}
if (mIns[i].ReferencesXReg())
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveASLMemUp(int at)
{
int j = at;
while (j > 0 && !mIns[j - 1].SameEffectiveAddress(mIns[at]))
{
if ((mIns[at].mLive & LIVE_CPU_REG_C) && mIns[j - 1].ReferencesCarry())
return false;
j--;
}
if (j > 0 && mIns[j - 1].mType == ASMIT_STA && !(mIns[j - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (mIns[at].mLive & LIVE_CPU_REG_C)
{
for (int i = j - 1; i < at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
}
mIns.Insert(j - 1, NativeCodeInstruction(mIns[at].mIns, mIns[at].mType));
mIns.Remove(at + 1);
return true;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadStoreXUp(int at)
{
int j = at;
while (j > 0 && !((mIns[j - 1].mType == ASMIT_STA || mIns[j - 1].mType == ASMIT_LDA) && mIns[j - 1].mMode == ASMIM_ZERO_PAGE && mIns[j - 1].mAddress == mIns[at].mAddress))
{
j--;
if ((mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_INDIRECT_Y) && mIns[j].mAddress == mIns[at + 1].mAddress)
return false;
if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress + 1 == mIns[at + 1].mAddress)
return false;
if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress && mIns[j].ChangesAddress())
return false;
if (mIns[j].mMode == ASMIM_ABSOLUTE_Y && mIns[j].mAddress <= mIns[at + 1].mAddress && mIns[j].mType == ASMIT_LDA && !mIns[j].mLinkerObject)
return false;
if (mIns[j].mType == ASMIT_JSR)
return false;
}
if (j > 0 && j < at)
{
for (int i = at; i > j; i--)
{
mIns[i] = mIns[i - 1];
}
mIns[at + 1].mLive |= mIns[j - 1].mLive;
mIns[j - 1].mLive |= LIVE_CPU_REG_A;
mIns[j] = mIns[at + 1];
mIns[j].mType = ASMIT_STA;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
return true;
}
return false;
}
bool NativeCodeBasicBlock::MoveStaTaxLdaStaDown(int at)
{
int j = at + 4;
while (j < mIns.Size())
{
if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
{
if (mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_MEM))
return false;
if (!HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_X))
return false;
mIns[j].CopyMode(mIns[at + 2]);
mIns.Insert(j, NativeCodeInstruction(mIns[at].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[at + 0].mAddress));
mIns.Remove(at + 1);
mIns.Remove(at + 1);
mIns.Remove(at + 1);
return true;
}
if (mIns[at + 0].MayBeChangedOnAddress(mIns[j]))
return false;
if (mIns[at + 2].MayBeChangedOnAddress(mIns[j]))
return false;
if (mIns[at + 3].MayBeChangedOnAddress(mIns[j]))
return false;
j++;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadAddImmStoreAbsXUp(int at)
{
int j = at - 1, top = at;
while (j > 0)
{
if (mIns[j].ChangesXReg())
break;
if (mIns[j].MayBeSameAddress(mIns[at + 3], true))
break;
if (mIns[j].MayBeSameAddress(mIns[at + 0], true) && mIns[j].ChangesAddress())
break;
if (!(mIns[j - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
top = j;
j--;
}
if (top < at)
{
int live = 0;
if (top > 0)
live = mIns[top - 1].mLive;
else if (mIns[top].RequiresYReg())
live |= LIVE_CPU_REG_Y;
mIns[at + 0].mLive |= live;
mIns[at + 1].mLive |= live;
mIns[at + 2].mLive |= live;
mIns[at + 3].mLive |= live;
mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
return true;
}
else
return false;
}
bool NativeCodeBasicBlock::MoveLoadAddImmStoreUp(int at)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 1].mAddress)
{
while (j + 1 < mIns.Size() && mIns[j + 1].mType == ASMIT_STA)
j++;
if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))
return false;
mIns[j].mLive |= LIVE_CPU_REG_A;
for (int i = j + 1; i < at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
mIns[at + 0].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[at + 3].mLive |= mIns[j].mLive;
mIns.Insert(j + 1, mIns[at + 3]); // STA
mIns.Insert(j + 1, mIns[at + 3]); // ADC
mIns.Insert(j + 1, mIns[at + 2]); // CLC
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
mIns[at + 6].mType = ASMIT_NOP; mIns[at + 6].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].UsesMemoryOf(mIns[at + 3]))
return false;
if (mIns[j].ChangesCarry())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadEorImmStoreUp(int at)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_A)
return false;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns.Insert(j + 1, mIns[at + 2]); // STA
mIns.Insert(j + 1, mIns[at + 2]); // EOR
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[j].IsShift() && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress && mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 2].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_A)
return false;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[at + 0].mLive |= LIVE_CPU_REG_C;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[j].mMode = ASMIM_IMPLIED;
mIns.Insert(j, mIns[at + 0]); // LDA
mIns.Insert(j + 2, mIns[at + 3]); // STA
mIns.Insert(j + 2, mIns[at + 3]); // EOR
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
return false;
if (mIns[j].UsesMemoryOf(mIns[at + 2]))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveCLCLoadAddZPStoreUp(int at)
{
int j = at - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 2].mAddress))
{
bool flip = mIns[j].mAddress != mIns[at + 1].mAddress;
if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))
{
int k = j;
j++;
while (j < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[j].ChangesAccu())
return false;
j++;
}
while (k < j)
mIns[k++].mLive |= LIVE_CPU_REG_A;
}
if (mIns[at + 2].mLive & LIVE_CPU_REG_C)
{
for (int i = j + 1; i < at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
}
if (flip)
mIns[at + 2].mAddress = mIns[at + 1].mAddress;
mIns[at + 0].mLive |= mIns[j].mLive | LIVE_CPU_REG_A;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[at + 3].mLive |= mIns[j].mLive;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 3]); // STA
mIns.Insert(j + 1, mIns[at + 3]); // ADC
mIns.Insert(j + 1, mIns[at + 2]); // CLC
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
mIns[at + 6].mType = ASMIT_LDA;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
return false;
if ((mIns[at + 2].mLive & LIVE_CPU_REG_C) && mIns[j].ChangesCarry())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::ReverseLoadCommutativeOpUp(int aload, int aop)
{
int j = aload - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[aop].mAddress)
{
mIns[aop].CopyMode(mIns[aload]);
mIns[aop].mLive |= LIVE_MEM;
mIns[aload].mType = ASMIT_NOP;
mIns[aload].mMode = ASMIM_IMPLIED;
while (j < aop)
{
mIns[j].mLive |= LIVE_CPU_REG_A;
j++;
}
j = aload;
while (j < aop)
{
mIns[j].mLive |= mIns[aload - 1].mLive;
j++;
}
return true;
}
if (mIns[j].ChangesAccu())
return false;
if (mIns[j].ChangesZeroPage(mIns[aop].mAddress))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveTYADCStoreDown(int at)
{
// [at + 0] TYA
// [at + 1] CLC
// [at + 2] ADC #
// [at + 3] STA
int offset = mIns[at + 2].mAddress;
int addr = mIns[at + 3].mAddress;
for (int i = at + 4; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (mIns[i].mType == ASMIT_INY)
offset--;
else if (mIns[i].mType == ASMIT_DEY)
offset++;
else if (mIns[i].ChangesYReg())
return false;
else if (mIns[i].ReferencesZeroPage(addr))
return false;
else if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
if (offset < -2 || offset > 2)
return false;
while (offset < 0)
{
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_DEY));
offset++;
i++;
}
while (offset > 0)
{
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_INY));
offset--;
i++;
}
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
while (i > at)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i--;
}
mIns.Remove(at, 4);
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::MoveLDSTXOutOfRange(int at)
{
bool vol = mIns[at + 1].mFlags & NCIF_VOLATILE;
int j = at + 2;
while (j < mIns.Size())
{
if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j].ReferencesZeroPage(mIns[at + 1].mAddress))
return false;
}
else if (mIns[j].MayBeSameAddress(mIns[at + 1]))
return false;
else if (vol && mIns[j].ChangesGlobalMemory())
return false;
else if (mIns[at + 1].mMode == ASMIM_ABSOLUTE && (mIns[j].mFlags & NCIF_VOLATILE))
return false;
else if (mIns[j].ReferencesXReg())
return false;
if (mIns[j].mType == ASMIT_JSR || mIns[j].mType == ASMIT_RTS)
return false;
if (!(mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
mIns.Insert(j + 1, NativeCodeInstruction(mIns[at].mIns, ASMIT_LDA, mIns[at]));
mIns.Remove(at, 2);
return true;
}
j++;
}
j = at;
while (j > 0)
{
j--;
if (!(mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_LDA, mIns[at + 1]));
mIns.Remove(at + 2, 2);
return true;
}
if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[j].ReferencesZeroPage(mIns[at + 1].mAddress))
return false;
}
else if (mIns[j].MayBeSameAddress(mIns[at + 1]))
return false;
else if (vol && mIns[j].ChangesGlobalMemory())
return false;
else if (mIns[at + 1].mMode == ASMIM_ABSOLUTE && (mIns[j].mFlags & NCIF_VOLATILE))
return false;
else if (mIns[j].ReferencesXReg())
return false;
if (mIns[j].mType == ASMIT_JSR)
return false;
}
return false;
}
bool NativeCodeBasicBlock::MoveShiftZeroPageUp(int at)
{
int j = at - 1;
while (j >= 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_A)
{
if (mIns[j + 1].mType == ASMIT_TAY || mIns[j + 1].mType == ASMIT_TAX)
{
if (mIns[j + 1].mLive & LIVE_CPU_REG_A)
return false;
NativeCodeInstruction ins(mIns[j + 1]);
ins.mLive |= LIVE_CPU_REG_A;
mIns.Remove(j + 1);
mIns.Insert(j, ins);
mIns[j + 1].mLive |= ins.mLive;
j++;
}
else
return false;
}
NativeCodeInstruction sins(mIns[at]);
mIns.Remove(at);
sins.mMode = ASMIM_IMPLIED;
sins.mLive |= LIVE_CPU_REG_A;
mIns.Insert(j, sins);
mIns[j].mLive |= mIns[j + 1].mLive;
if (sins.mLive & LIVE_CPU_REG_C)
{
for (int i = j; i <= at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
}
return true;
}
if (mIns[j].ReferencesCarry())
return false;
if (mIns[j].ReferencesZeroPage(mIns[at].mAddress))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadShiftStoreUp(int at)
{
int j = at - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_C)
return false;
if (mIns[j].mLive & LIVE_CPU_REG_A)
{
if (mIns[j + 1].mType == ASMIT_STA && !(mIns[j + 1].mLive & LIVE_CPU_REG_A))
{
NativeCodeInstruction ins = mIns[j + 1];
mIns[j + 1] = mIns[j];
mIns[j] = ins;
mIns[j].mLive |= LIVE_CPU_REG_A;
j++;
}
else
return false;
}
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
for (int i = j + 1; i < at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
mIns.Insert(j + 1, mIns[at + 2]); // STORE
mIns.Insert(j + 1, mIns[at + 2]); // SHIFT
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
return true;
}
if ((mIns[at + 1].RequiresCarry() || (mIns[at + 2].mLive & LIVE_CPU_REG_C) != 0) && mIns[j].ChangesCarry())
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadShiftRotateUp(int at)
{
int j = at - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
{
if (mIns[j].mLive & LIVE_CPU_REG_C)
return false;
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
for (int i = j + 1; i < at; i++)
mIns[i].mLive |= LIVE_CPU_REG_C;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 2]); // ROR ZP
mIns.Insert(j + 1, mIns[at + 2]); // LSR
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveLoadAddZPStoreUp(int at)
{
int j = at - 1;
while (j > 0)
{
if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
{
while (j < at && (mIns[j].mLive & LIVE_CPU_REG_A))
{
if (mIns[j].ChangesAccu())
return false;
j++;
}
mIns[at + 1].mLive |= mIns[j].mLive;
mIns[at + 2].mLive |= mIns[j].mLive;
mIns[j].mLive |= LIVE_CPU_REG_A;
mIns.Insert(j + 1, mIns[at + 2]); // STA
mIns.Insert(j + 1, mIns[at + 2]); // ADC
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].ChangesCarry())
return false;
j--;
}
return false;
}
bool NativeCodeBasicBlock::MoveCLCLoadAddZPStoreDown(int at)
{
int j = at + 4;
while (j < mIns.Size())
{
if (mIns[j].mType == ASMIT_LDA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 3].mAddress)
{
if (j == at + 4)
return false;
if (mIns[j].mLive & LIVE_CPU_REG_C)
return false;
mIns.Insert(j, mIns[at + 3]); // STA
mIns.Insert(j, mIns[at + 2]); // ADC
mIns.Insert(j, mIns[at + 1]); // LDA
mIns.Insert(j, mIns[at + 0]); // CLC
mIns[j + 0].mLive |= mIns[j - 1].mLive;
mIns[j + 1].mLive |= mIns[j - 1].mLive;
mIns[j + 2].mLive |= mIns[j - 1].mLive;
mIns[j + 3].mLive |= mIns[j - 1].mLive;
mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
return true;
}
if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
return false;
if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
return false;
if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
return false;
j++;
}
return false;
}
//static bool PeepCheck = false;
//static bool PeepCheck = false;
bool NativeCodeBasicBlock::ReverseBitfieldForwarding(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
int aused = 0xff;
bool cused = 0;
for (int i = mIns.Size() - 1; i >= 0; i--)
{
NativeCodeInstruction& ins(mIns[i]);
switch (ins.mType)
{
case ASMIT_TXA:
case ASMIT_TYA:
case ASMIT_LDA:
aused = 0;
break;
case ASMIT_CLC:
case ASMIT_SEC:
cused = false;
break;
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_JSR:
cused = true;
aused = 0xff;
break;
case ASMIT_CMP:
cused = false;
aused = 0xff;
break;
case ASMIT_STA:
case ASMIT_TAX:
case ASMIT_TAY:
case ASMIT_EOR:
aused = 0xff;
break;
case ASMIT_LSR:
if (ins.mMode == ASMIM_IMPLIED)
{
aused = (aused << 1) & 0xff;
if (cused)
aused |= 1;
}
cused = false;
break;
case ASMIT_ASL:
if (ins.mMode == ASMIM_IMPLIED)
{
aused >>= 1;
if (cused)
aused |= 0x80;
}
cused = false;
break;
case ASMIT_ROR:
if (ins.mMode == ASMIM_IMPLIED)
{
if (aused & 0x80)
{
aused = (aused << 1) & 0xff;
if (cused)
aused |= 1;
cused = true;
}
else
{
ins.mType = ASMIT_LSR;
aused = (aused << 1) & 0xff;
if (cused)
aused |= 1;
cused = false;
}
}
else
cused = true;
break;
case ASMIT_ROL:
if (ins.mMode == ASMIM_IMPLIED)
{
if (aused & 0x01)
{
aused >>= 1;
if (cused)
aused |= 0x80;
cused = true;
}
else
{
ins.mType = ASMIT_ASL;
aused >>= 1;
if (cused)
aused |= 0x80;
cused = false;
}
}
else
cused = true;
break;
case ASMIT_ORA:
if (ins.mMode == ASMIM_IMMEDIATE)
aused &= ~ins.mAddress;
else
aused = 0xff;
break;
case ASMIT_AND:
if (ins.mMode == ASMIM_IMMEDIATE)
aused &= ins.mAddress;
else
aused = 0xff;
break;
}
}
if (mTrueJump && mTrueJump->ReverseBitfieldForwarding())
changed = true;
if (mFalseJump && mFalseJump->ReverseBitfieldForwarding())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::RemoveLocalUnusedLinkerObjects(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_LOCAL_VAR) && !(ins.mLinkerObject->mFlags & LOBJF_LOCAL_USED))
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (mTrueJump && mTrueJump->RemoveLocalUnusedLinkerObjects())
changed = true;
if (mFalseJump && mFalseJump->RemoveLocalUnusedLinkerObjects())
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::MarkLocalUsedLinkerObjects(void)
{
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mLinkerObject)
{
if (ins.mMode == ASMIM_IMMEDIATE_ADDRESS || ins.UsesAddress())
ins.mLinkerObject->mFlags |= LOBJF_LOCAL_USED;
}
}
if (mTrueJump) mTrueJump->MarkLocalUsedLinkerObjects();
if (mFalseJump) mFalseJump->MarkLocalUsedLinkerObjects();
}
}
bool NativeCodeBasicBlock::AbsoluteValueForwarding(const ExpandingArray<NativeCodeLoadStorePair> & npairs)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
ExpandingArray<NativeCodeLoadStorePair> pairs;
if (mNumEntries == 1)
pairs = npairs;
int ains = -1;
for (int i = 0; i < mIns.Size(); i++)
{
// Check content of accu
if (mIns[i].mType == ASMIT_LDA)
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_ZERO_PAGE)
ains = i;
else if (mIns[i].mMode == ASMIM_ABSOLUTE && !(mIns[i].mFlags & NCIF_VOLATILE))
{
int j = 0;
while (j < pairs.Size() && !pairs[j].mStore.SameEffectiveAddress(mIns[i]))
j++;
if (j < pairs.Size())
{
mIns[i].CopyMode(pairs[j].mLoad);
ains = i;
changed = true;
}
else
ains = -1;
}
else
ains = -1;
}
else if (mIns[i].ChangesAccu())
ains = -1;
else if (ains >= 0 && mIns[ains].MayBeChangedOnAddress(mIns[i]))
ains = -1;
if (ains >= 0 && mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ABSOLUTE && !(mIns[i].mFlags & NCIF_VOLATILE))
{
int j = 0;
while (j < pairs.Size() && !pairs[j].mStore.SameEffectiveAddress(mIns[i]))
j++;
if (j < pairs.Size())
{
pairs[j].mLoad = mIns[ains];
pairs[j].mStore = mIns[i];
}
else
{
NativeCodeLoadStorePair pair;
pair.mLoad = mIns[ains];
pair.mStore = mIns[i];
pairs.Push(pair);
}
}
else if (mIns[i].mType == ASMIT_JSR)
{
pairs.SetSize(0);
ains = -1;
}
else if (mIns[i].ChangesAddress())
{
int j = 0, k = 0;
while (j < pairs.Size())
{
if (!pairs[j].mLoad.MayBeChangedOnAddress(mIns[i]) && !pairs[j].mStore.MayBeChangedOnAddress(mIns[i]))
{
if (k != j)
pairs[k] = pairs[j];
k++;
}
j++;
}
pairs.SetSize(k);
}
}
if (mTrueJump && mTrueJump->AbsoluteValueForwarding(pairs))
changed = true;
if (mFalseJump && mFalseJump->AbsoluteValueForwarding(pairs))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OffsetValueForwarding(const ValueNumberingDataSet& data)
{
bool changed = false;
if (!mVisited)
{
mNNumDataSet = data;
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (mLoopHead)
{
mNNumDataSet.Reset();
}
else if (mNumEntries > 0)
{
if (mNumEntered > 0)
mNNumDataSet.Intersect(mNumDataSet);
mNumEntered++;
if (mNumEntered < mNumEntries)
{
mNumDataSet = mNNumDataSet;
return false;
}
}
mVisited = true;
int carry = -1;
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.mType == ASMIT_JSR)
{
mNNumDataSet.ResetCall(ins);
carry = -1;
}
else if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE)
{
mNNumDataSet.mRegs[CPU_REG_A] = mNNumDataSet.mRegs[mIns[i + 0].mAddress];
}
else if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE)
{
int reg = ins.mAddress;
if (mNNumDataSet.mRegs[reg].SameBase(mNNumDataSet.mRegs[CPU_REG_A]))
{
int d = mNNumDataSet.mRegs[CPU_REG_A].mOffset - mNNumDataSet.mRegs[reg].mOffset;
if (d == 0)
{
ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
changed = true;
}
else if (d == 1 && !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
ins.mType = ASMIT_INC;
changed = true;
}
else if (d == -1 && !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
ins.mType = ASMIT_DEC;
changed = true;
}
}
mNNumDataSet.mRegs[reg] = mNNumDataSet.mRegs[CPU_REG_A];
}
else if (ins.mType == ASMIT_ADC && ins.mMode == ASMIM_IMMEDIATE && carry != -1)
mNNumDataSet.mRegs[CPU_REG_A].mOffset += ins.mAddress + carry;
else if (ins.mType == ASMIT_SBC && ins.mMode == ASMIM_IMMEDIATE && carry != -1)
mNNumDataSet.mRegs[CPU_REG_A].mOffset -= ins.mAddress + 1 - carry;
else if (ins.ChangesAccu())
mNNumDataSet.mRegs[CPU_REG_A].Reset();
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
mNNumDataSet.mRegs[ins.mAddress].Reset();
if (ins.mType == ASMIT_CLC)
carry = 0;
else if (ins.mType == ASMIT_SEC)
carry = 1;
else if (ins.ChangesCarry())
carry = -1;
}
mFNumDataSet = mNNumDataSet;
if (this->mTrueJump && this->mTrueJump->OffsetValueForwarding(mNNumDataSet))
changed = true;
if (this->mFalseJump && this->mFalseJump->OffsetValueForwarding(mFNumDataSet))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::IndexXYValueForwarding(int xreg, int xoffset, int xvalue, int yreg, int yoffset, int yvalue)
{
bool changed = false;
if (!mVisited)
{
if (mLoopHead)
{
xreg = -1;
yreg = -1;
}
else if (mNumEntries > 0)
{
if (mNumEntered > 0)
{
if (xreg != mXReg || xoffset != mXOffset || xvalue != mXValue)
xreg = -1;
if (yreg != mYReg || yoffset != mYOffset || yvalue != mYValue)
yreg = -1;
}
mXReg = xreg; mXOffset = xoffset; mXValue = xvalue;
mYReg = yreg; mYOffset = yoffset; mYValue = yvalue;
mNumEntered++;
if (mNumEntered < mNumEntries)
return false;
}
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_INY)
yoffset = (yoffset + 1) & 255;
else if (mIns[i].mType == ASMIT_DEY)
yoffset = (yoffset - 1) & 255;
else if (mIns[i].mType == ASMIT_INX)
xoffset = (xoffset + 1) & 255;
else if (mIns[i].mType == ASMIT_DEX)
xoffset = (xoffset - 1) & 255;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mAddress == xreg)
{
if (xoffset <= 3)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
for (int j = 0; j < xoffset; j++)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
changed = true;
}
else if (xoffset >= 253)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
for (int j = xoffset; j <= 256; j++)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
changed = true;
}
else
xoffset = 0;
}
else if (i + 1 < mIns.Size() && mIns[i].mAddress == yreg && yoffset == 0 &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(mIns[i].mLive & LIVE_CPU_REG_A))
{
mIns[i] = NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDA, mIns[i + 1]);
mIns[i].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 1].mType = ASMIT_TAY; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else
{
xreg = mIns[i].mAddress;
xoffset = 0;
xvalue = GlobalValueNumber++;
}
}
else
xreg = -1;
}
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (mIns[i].mAddress == yreg)
{
if (yoffset <= 3)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
for (int j = 0; j < yoffset; j++)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
changed = true;
}
else if (yoffset >= 253)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
for (int j = yoffset; j <= 256; j++)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
changed = true;
}
else
yoffset = 0;
}
else
{
yreg = mIns[i].mAddress;
yoffset = 0;
yvalue = GlobalValueNumber++;
}
}
else
yreg = -1;
}
else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && yreg == -1)
{
if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
xreg = -1;
yreg = mIns[i].mAddress;
yoffset = 0;
yvalue = GlobalValueNumber++;
}
else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && xreg == -1)
{
if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
yreg = -1;
xreg = mIns[i].mAddress;
xoffset = 0;
xvalue = GlobalValueNumber++;
}
else if (i + 2 < mIns.Size() &&
mIns[i].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
if (mIns[i + 1].mAddress == yreg)
{
mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mAddress = (mIns[i + 2].mAddress - yoffset) & 255;
changed = true;
}
else if (i + 3 < mIns.Size() && mIns[i + 3].mType == ASMIT_TAY)
{
yreg = mIns[i + 1].mAddress;
yoffset = mIns[i + 2].mAddress;
yvalue = GlobalValueNumber++;
i += 3;
}
else if (mIns[i + 1].mAddress == xreg)
{
mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mAddress = (mIns[i + 2].mAddress - xoffset) & 255;
changed = true;
}
else if (i + 3 < mIns.Size() && mIns[i + 3].mType == ASMIT_TAX)
{
xreg = mIns[i + 1].mAddress;
xoffset = mIns[i + 2].mAddress;
xvalue = GlobalValueNumber++;
i += 3;
}
}
else if (i + 2 < mIns.Size() &&
mIns[i].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_ADC, mIns[i].mMode) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE)
{
if (yreg == mIns[i + 2].mAddress && yoffset == 0)
{
mIns[i + 2].CopyMode(mIns[i]);
mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
}
else if (xreg == mIns[i + 2].mAddress && xoffset == 0)
{
mIns[i + 2].CopyMode(mIns[i]);
mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;
}
}
else
{
if (mIns[i].ChangesXReg())
xreg = -1;
if (mIns[i].ChangesYReg())
yreg = -1;
if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
xreg = -1;
if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
yreg = -1;
}
}
mVisited = true;
if (this->mTrueJump && this->mTrueJump->IndexXYValueForwarding(xreg, xoffset, xvalue, yreg, yoffset, yvalue))
changed = true;
if (this->mFalseJump && this->mFalseJump->IndexXYValueForwarding(xreg, xoffset, xvalue, yreg, yoffset, yvalue))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::BitFieldForwarding(const NativeRegisterDataSet& data)
{
bool changed = false;
if (!mVisited)
{
mNDataSet = data;
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (mLoopHead)
{
mNDataSet.ResetMask();
}
else if (mNumEntries > 0)
{
if (mNumEntered > 0)
mNDataSet.IntersectMask(mDataSet);
mNumEntered++;
if (mNumEntered < mNumEntries)
{
mDataSet = mNDataSet;
return false;
}
}
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
AsmInsType carryop = ASMIT_NOP;
#if 1
if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress &&
(mNDataSet.mRegs[CPU_REG_A].mMask & mIns[i + 2].mAddress) == mIns[i + 2].mAddress &&
(mNDataSet.mRegs[CPU_REG_A].mValue & mIns[i + 2].mAddress) == 0)
{
mIns[i + 1].mType = ASMIT_EOR;
mIns[i + 2].mAddress = mIns[i + 2].mAddress ^ 0xff;
mIns[i + 3].mType = ASMIT_EOR;
mIns[i + 3].mAddress = mIns[i + 1].mAddress;
changed = true;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAX)
{
if (mIns[i + 1].mAddress == 1 && (mNDataSet.mRegs[CPU_REG_X].mMask & 1))
{
if (mNDataSet.mRegs[CPU_REG_X].mValue & 1)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
}
else if (mIns[i + 1].mAddress == 2 && (mNDataSet.mRegs[CPU_REG_X].mMask & 2))
{
if (mNDataSet.mRegs[CPU_REG_X].mValue & 2)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
else
{
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
}
}
#endif
if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1)
{
if (mNDataSet.mRegs[CPU_REG_X].mMask & 1)
{
if (mNDataSet.mRegs[CPU_REG_X].mValue & 1)
{
mIns[i + 1].mAddress = 0;
changed = true;
}
else
{
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
bool skip = false;
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_EOR && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
{
if (mNDataSet.mRegs[mIns[i + 0].mAddress].mMask == 0)
{
mNDataSet.mRegs[CPU_REG_A].mMask &= mIns[i + 1].mAddress;
mNDataSet.mRegs[CPU_REG_Z].ResetMask();
i += 2;
skip = true;
}
}
if (!skip)
{
if (mIns[i].BitFieldForwarding(mNDataSet, carryop))
changed = true;
if (carryop != ASMIT_NOP)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
}
}
if (mFalseJump)
{
mFDataSet = mNDataSet;
if (mIns.Size() > 0)
{
const NativeCodeInstruction& lins(mIns[mIns.Size() - 1]);
if (lins.ChangesAccuAndFlag())
{
switch (mBranch)
{
case ASMIT_BEQ:
if (mNDataSet.mRegs[CPU_REG_A].mMask == 0xff)
{
if (mNDataSet.mRegs[CPU_REG_A].mValue != 0)
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
}
else
{
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
}
mBranch = ASMIT_JMP;
changed = true;
}
else
{
mNDataSet.mRegs[CPU_REG_A].mMask = 0xff;
mNDataSet.mRegs[CPU_REG_A].mValue = 0x00;
if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
{
mNDataSet.mRegs[lins.mAddress].mMask = 0xff;
mNDataSet.mRegs[lins.mAddress].mValue = 0x00;
}
}
break;
case ASMIT_BNE:
if (mNDataSet.mRegs[CPU_REG_A].mMask == 0xff)
{
if (mNDataSet.mRegs[CPU_REG_A].mValue == 0)
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
}
else
{
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
}
mBranch = ASMIT_JMP;
changed = true;
}
else
{
mFDataSet.mRegs[CPU_REG_A].mMask = 0xff;
mFDataSet.mRegs[CPU_REG_A].mValue = 0x00;
if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
{
mFDataSet.mRegs[lins.mAddress].mMask = 0xff;
mFDataSet.mRegs[lins.mAddress].mValue = 0x00;
}
}
break;
case ASMIT_BPL:
if (mNDataSet.mRegs[CPU_REG_A].mMask & 0x80)
{
if (mNDataSet.mRegs[CPU_REG_A].mValue & 0x80)
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
}
else
{
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
}
mBranch = ASMIT_JMP;
changed = true;
}
else
{
mNDataSet.mRegs[CPU_REG_A].mMask |= 0x80;
mNDataSet.mRegs[CPU_REG_A].mValue &= 0x7f;
mFDataSet.mRegs[CPU_REG_A].mMask |= 0x80;
mFDataSet.mRegs[CPU_REG_A].mValue |= 0x80;
if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
{
mNDataSet.mRegs[lins.mAddress].mMask |= 0x80;
mNDataSet.mRegs[lins.mAddress].mValue &= 0x7f;
mFDataSet.mRegs[lins.mAddress].mMask |= 0x80;
mFDataSet.mRegs[lins.mAddress].mValue |= 0x80;
}
}
break;
case ASMIT_BMI:
if (mNDataSet.mRegs[CPU_REG_A].mMask & 0x80)
{
if (!(mNDataSet.mRegs[CPU_REG_A].mValue & 0x80))
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
}
else
{
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
}
mBranch = ASMIT_JMP;
changed = true;
}
else
{
mFDataSet.mRegs[CPU_REG_A].mMask |= 0x80;
mFDataSet.mRegs[CPU_REG_A].mValue &= 0x7f;
mNDataSet.mRegs[CPU_REG_A].mMask |= 0x80;
mNDataSet.mRegs[CPU_REG_A].mValue |= 0x80;
if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
{
mFDataSet.mRegs[lins.mAddress].mMask |= 0x80;
mFDataSet.mRegs[lins.mAddress].mValue &= 0x7f;
mNDataSet.mRegs[lins.mAddress].mMask |= 0x80;
mNDataSet.mRegs[lins.mAddress].mValue |= 0x80;
}
}
break;
}
}
}
}
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (this->mTrueJump && this->mTrueJump->BitFieldForwarding(mNDataSet))
changed = true;
if (this->mFalseJump && this->mFalseJump->BitFieldForwarding(mFDataSet))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::GlobalValueForwarding(NativeCodeProcedure* proc, bool final)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mEntryBlocks.Size() == 0)
mDataSet.Reset();
else
{
if (this == mEntryBlocks[0]->mTrueJump)
mDataSet = mEntryBlocks[0]->mNDataSet;
else
mDataSet = mEntryBlocks[0]->mFDataSet;
for (int i = 1; i < mEntryBlocks.Size(); i++)
{
if (this == mEntryBlocks[i]->mTrueJump)
mDataSet.Intersect(mEntryBlocks[i]->mNDataSet);
else
mDataSet.Intersect(mEntryBlocks[i]->mFDataSet);
}
}
for (int i = 0; i < mIns.Size(); i++)
{
AsmInsType carryop;
#if 1
if (i + 1 < mIns.Size() &&
mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i].SameEffectiveAddress(mIns[i + 1]) &&
mDataSet.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE &&
mDataSet.mRegs[CPU_REG_A].mLinkerObject == mIns[i].mLinkerObject &&
mDataSet.mRegs[CPU_REG_A].mValue == mIns[i].mAddress)
{
mIns[i + 1].mType = ASMIT_STA;
mIns[i + 0].mType = ASMIT_ADC; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 1;
mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_CLC));
changed = true;
}
#endif
if (mIns[i].ValueForwarding(mDataSet, carryop, true, final, proc->mFastCallBase))
changed = true;
if (carryop != ASMIT_NOP)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
}
if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding(proc, final))
changed = true;
if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding(proc, final))
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::ResetModifiedDataSet(NativeRegisterDataSet& data)
{
// Single block loop
for (int i = 0; i < mIns.Size(); i++)
{
NativeCodeInstruction& ins(mIns[i]);
if (ins.ChangesAccu())
data.mRegs[CPU_REG_A].Reset();
if (ins.ChangesXReg())
data.mRegs[CPU_REG_X].Reset();
if (ins.ChangesYReg())
data.mRegs[CPU_REG_Y].Reset();
if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
data.ResetZeroPage(ins.mAddress);
else if (ins.mMode == ASMIM_ABSOLUTE && ins.ChangesAddress())
data.ResetAbsolute(ins.mLinkerObject, ins.mAddress);
if (ins.mType == ASMIT_JSR)
{
data.ResetWorkRegs();
if (!(ins.mFlags & NCIF_RUNTIME) && ins.mLinkerObject || (ins.mFlags & NCIF_FEXEC))
{
if (ins.mLinkerObject && ins.mLinkerObject->mProc)
{
for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
data.ResetZeroPage(i);
}
else
{
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
data.ResetZeroPage(i);
}
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
data.ResetZeroPage(i);
}
}
}
}
bool NativeCodeBasicBlock::ValueForwarding(NativeCodeProcedure* proc, const NativeRegisterDataSet& data, bool global, bool final)
{
bool changed = false;
if (!mVisited)
{
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
mNDataSet = data;
if (mLoopHead)
{
#if 1
if (mNumEntries == 2 && (mTrueJump == this || mFalseJump == this))
{
mNDataSet.mRegs[CPU_REG_C].Reset();
mNDataSet.mRegs[CPU_REG_Z].Reset();
bool loopx = false, loopy = false;
int loopya, loopxa;
if (mIns.Size() > 2)
{
int sz = mIns.Size();
if ((mIns[sz - 2].mType == ASMIT_LDY || mIns[sz - 2].mType == ASMIT_STY) && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE)
{
if (mNDataSet.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mIns[sz - 2].mAddress == mNDataSet.mRegs[CPU_REG_Y].mValue ||
mNDataSet.mRegs[CPU_REG_Y].SameData(mNDataSet.mRegs[mIns[sz - 2].mAddress]))
{
loopya = mIns[sz - 2].mAddress;
loopy = true;
}
}
else if ((mIns[sz - 2].mType == ASMIT_LDX || mIns[sz - 2].mType == ASMIT_STX) && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE)
{
if (mNDataSet.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mIns[sz - 2].mAddress == mNDataSet.mRegs[CPU_REG_X].mValue ||
mNDataSet.mRegs[CPU_REG_X].SameData(mNDataSet.mRegs[mIns[sz - 2].mAddress]))
{
loopxa = mIns[sz - 2].mAddress;
loopx = true;
}
}
}
ResetModifiedDataSet(mNDataSet);
if (loopy)
{
mNDataSet.mRegs[CPU_REG_Y].mMode = NRDM_ZERO_PAGE;
mNDataSet.mRegs[CPU_REG_Y].mValue = loopya;
}
if (loopx)
{
mNDataSet.mRegs[CPU_REG_X].mMode = NRDM_ZERO_PAGE;
mNDataSet.mRegs[CPU_REG_X].mValue = loopxa;
}
}
else if (mNumEntries == 2 && global)
{
NativeCodeBasicBlock* lblock = nullptr;
if (mTrueJump && mFalseJump)
{
if (mTrueJump->mTrueJump == this && mTrueJump->mFalseJump == mFalseJump ||
mTrueJump->mFalseJump == this && mTrueJump->mTrueJump == mFalseJump)
{
lblock = mTrueJump;
}
else if (mFalseJump->mTrueJump == this && mFalseJump->mFalseJump == mTrueJump ||
mFalseJump->mFalseJump == this && mFalseJump->mTrueJump == mTrueJump)
{
lblock = mFalseJump;
}
}
if (lblock)
{
mNDataSet.mRegs[CPU_REG_C].Reset();
mNDataSet.mRegs[CPU_REG_Z].Reset();
ResetModifiedDataSet(mNDataSet);
lblock->ResetModifiedDataSet(mNDataSet);
}
else
mNDataSet.Reset();
}
else
#endif
mNDataSet.Reset();
}
else if (!global)
{
mNDataSet.Reset();
}
#if 0
else if (mNumEntries != 1)
{
ndata.Reset();
}
#endif
else if (mNumEntries > 0)
{
if (mNumEntered > 0)
mNDataSet.Intersect(mDataSet);
mNumEntered++;
if (mNumEntered < mNumEntries)
{
mDataSet = mNDataSet;
return false;
}
}
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
AsmInsType carryop;
#if 1
if (mIns[i].mMode == ASMIM_INDIRECT_Y && HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y) &&
mNDataSet.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE &&
mNDataSet.mRegs[mIns[i].mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && (mNDataSet.mRegs[mIns[i].mAddress + 1].mFlags & NCIF_UPPER) &&
mNDataSet.mRegs[mIns[i].mAddress].mMode != NRDM_IMMEDIATE_ADDRESS)
{
int reg = mIns[i].mAddress;
mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 1].mLinkerObject = mNDataSet.mRegs[reg + 1].mLinkerObject;
mIns[i + 1].mAddress = mNDataSet.mRegs[reg + 1].mValue + mNDataSet.mRegs[CPU_REG_Y].mValue;
mIns[i + 1].mFlags &= ~NCIF_LOWER;
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mNDataSet.mRegs[CPU_REG_Y].mValue));
mIns.Insert(i + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
changed = true;
}
#endif
// Check load and commutative with current accu value
#if 1
if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA &&
mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 1].mAddress)
{
mIns[i].mType = mIns[i + 1].mType;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
#endif
if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && !mIns[i].RequiresYReg() &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1] = mIns[i];
mIns[i].mType = ASMIT_TAY; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && !mIns[i].RequiresXReg() &&
mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1] = mIns[i];
mIns[i].mType = ASMIT_TAX; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
#if 1
if (i + 2 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].IsCommutative() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 2].mAddress)
{
mIns[i + 2].CopyMode(mIns[i + 0]);
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
#endif
if (mIns[i].ValueForwarding(mNDataSet, carryop, !global, final, proc->mFastCallBase))
changed = true;
if (carryop != ASMIT_NOP)
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
}
#if 1
if (global)
{
NativeCodeBasicBlock* fork = this;
if (!mFalseJump && mTrueJump && mTrueJump->mIns.Size() == 0)
fork = mTrueJump;
if (fork->mFalseJump)
{
mFDataSet = mNDataSet;
switch (fork->mBranch)
{
case ASMIT_BCS:
if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if (!mNDataSet.mRegs[CPU_REG_C].mValue)
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
break;
case ASMIT_BCC:
if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if (mNDataSet.mRegs[CPU_REG_C].mValue)
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
break;
case ASMIT_BNE:
if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if (!mNDataSet.mRegs[CPU_REG_Z].mValue)
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
else if (global && mIns.Size() > 0 && fork == this)
{
NativeCodeInstruction& lins(mIns[mIns.Size() - 1]);
if (lins.mType == ASMIT_LDY)
{
mFDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_Y].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mFDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_LDX)
{
mFDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_X].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mFDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_LDA)
{
mFDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_A].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mFDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_CPY && lins.mMode == ASMIM_IMMEDIATE)
{
mFDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_Y].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_CPX && lins.mMode == ASMIM_IMMEDIATE)
{
mFDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_X].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_CMP && lins.mMode == ASMIM_IMMEDIATE)
{
mFDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_A].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_ORA || lins.mType == ASMIT_AND || lins.mType == ASMIT_EOR || lins.mType == ASMIT_ADC || lins.mType == ASMIT_SBC)
{
mFDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_A].mValue = 0;
}
else if (lins.mType == ASMIT_TXA || lins.mType == ASMIT_TAX)
{
mFDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_A].mValue = 0;
mFDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_X].mValue = 0;
}
else if (lins.mType == ASMIT_INX || lins.mType == ASMIT_DEX)
{
mFDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_X].mValue = 0;
}
else if (lins.mType == ASMIT_INY || lins.mType == ASMIT_DEY)
{
mFDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[CPU_REG_Y].mValue = 0;
}
else if ((lins.mType == ASMIT_INC || lins.mType == ASMIT_DEC) && lins.mMode == ASMIM_ZERO_PAGE)
{
mFDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mFDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
break;
case ASMIT_BEQ:
if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if (mNDataSet.mRegs[CPU_REG_Z].mValue)
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
else if (global && mIns.Size() > 0 && fork == this)
{
NativeCodeInstruction& lins(mIns[mIns.Size() - 1]);
if (lins.mType == ASMIT_LDY)
{
mNDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_Y].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mNDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_LDX)
{
mNDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_X].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mNDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_LDA)
{
mNDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_A].mValue = 0;
if (lins.mMode == ASMIM_ZERO_PAGE)
{
mNDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
else if (lins.mType == ASMIT_CPY && lins.mMode == ASMIM_IMMEDIATE)
{
mNDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_Y].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_CPX && lins.mMode == ASMIM_IMMEDIATE)
{
mNDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_X].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_CMP && lins.mMode == ASMIM_IMMEDIATE)
{
mNDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_A].mValue = lins.mAddress;
}
else if (lins.mType == ASMIT_ORA || lins.mType == ASMIT_AND || lins.mType == ASMIT_EOR || lins.mType == ASMIT_ADC || lins.mType == ASMIT_SBC)
{
mNDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_A].mValue = 0;
}
else if (lins.mType == ASMIT_TXA || lins.mType == ASMIT_TAX)
{
mNDataSet.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_A].mValue = 0;
mNDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_X].mValue = 0;
}
else if (lins.mType == ASMIT_INX || lins.mType == ASMIT_DEX)
{
mNDataSet.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_X].mValue = 0;
}
else if (lins.mType == ASMIT_INY || lins.mType == ASMIT_DEY)
{
mNDataSet.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[CPU_REG_Y].mValue = 0;
}
else if ((lins.mType == ASMIT_INC || lins.mType == ASMIT_DEC) && lins.mMode == ASMIM_ZERO_PAGE)
{
mNDataSet.mRegs[lins.mAddress].mMode = NRDM_IMMEDIATE;
mNDataSet.mRegs[lins.mAddress].mValue = 0;
}
}
break;
case ASMIT_BPL:
if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mNumEntries--;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
if ((mNDataSet.mRegs[CPU_REG_Z].mValue & 0x80))
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
break;
case ASMIT_BMI:
if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
mBranch = ASMIT_JMP;
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
mTrueJump->mNumEntries--;
if (!(mNDataSet.mRegs[CPU_REG_Z].mValue & 0x80))
mTrueJump = fork->mFalseJump;
else
mTrueJump = fork->mTrueJump;
mTrueJump->mNumEntries++;
mTrueJump->mEntryBlocks.Push(this);
if (mFalseJump)
{
mFalseJump->mNumEntries--;
mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
}
mFalseJump = nullptr;
changed = true;
}
break;
}
}
}
#endif
if (global && mTrueJump && mTrueJump->mIns.Size() == 1 && mTrueJump->mTrueJump && !mTrueJump->mFalseJump)
{
if (mTrueJump->mIns[0].mType == ASMIT_LDY && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE)
{
if (mNDataSet.mRegs[CPU_REG_Y].SameData(mNDataSet.mRegs[mTrueJump->mIns[0].mAddress]))
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
}
}
if (global && mFalseJump && mFalseJump->mIns.Size() == 1 && mFalseJump->mTrueJump && !mFalseJump->mFalseJump)
{
if (mFalseJump->mIns[0].mType == ASMIT_LDY && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE)
{
if (mFDataSet.mRegs[CPU_REG_Y].SameData(mFDataSet.mRegs[mFalseJump->mIns[0].mAddress]))
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
}
}
#if 1
if (mTrueJump && !mFalseJump && mTrueJump->mIns.Size() == 1 && (mTrueJump->mBranch == ASMIT_BEQ || mTrueJump->mBranch == ASMIT_BNE) && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mTrueJump->mIns[0].mType == ASMIT_CMP)
{
if (mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
NativeCodeBasicBlock* target;
if (mNDataSet.mRegs[CPU_REG_A].mValue == mTrueJump->mIns[0].mAddress)
{
if (mTrueJump->mBranch == ASMIT_BEQ)
target = mTrueJump->mTrueJump;
else
target = mTrueJump->mFalseJump;
}
else
{
if (mTrueJump->mBranch == ASMIT_BNE)
target = mTrueJump->mTrueJump;
else
target = mTrueJump->mFalseJump;
}
if (target != mTrueJump)
{
mIns.Push(mTrueJump->mIns[0]);
mTrueJump->mEntryBlocks.RemoveAll(this);
mTrueJump->mNumEntries--;
target->mEntryBlocks.Push(this);
target->mNumEntries++;
mTrueJump = target;
changed = true;
}
}
}
else if (mTrueJump->mIns[0].mType == ASMIT_ORA && mTrueJump->mIns[0].mAddress == 0)
{
if (mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE)
{
NativeCodeBasicBlock* target;
if (mNDataSet.mRegs[CPU_REG_A].mValue == 0)
{
if (mTrueJump->mBranch == ASMIT_BEQ)
target = mTrueJump->mTrueJump;
else
target = mTrueJump->mFalseJump;
}
else
{
if (mTrueJump->mBranch == ASMIT_BNE)
target = mTrueJump->mTrueJump;
else
target = mTrueJump->mFalseJump;
}
if (target != mTrueJump)
{
mTrueJump->mEntryBlocks.RemoveAll(this);
mTrueJump->mNumEntries--;
target->mEntryBlocks.Push(this);
target->mNumEntries++;
mTrueJump = target;
changed = true;
}
}
}
}
#endif
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
if (this->mTrueJump && this->mTrueJump->ValueForwarding(proc, mNDataSet, global, final))
changed = true;
if (this->mFalseJump && this->mFalseJump->ValueForwarding(proc, mFDataSet, global, final))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, bool full)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* xblock = mTrueJump == this ? mFalseJump : mTrueJump;
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = xblock->mEntryRequiredRegs;
eblock->mExitRequiredRegs = xblock->mEntryRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
for (int i = 0; i < mIns.Size(); i++)
lblock->mIns.Push(mIns[i]);
mIns.SetSize(0);
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
return lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
}
bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mEntryBlocks.Size() > 1)
{
NativeCodeBasicBlock* pblock = nullptr;
ExpandingArray<NativeCodeBasicBlock*> lblocks, pblocks;
bool addprefix = false;
for(int i=0; i<mEntryBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mEntryBlocks[i];
if (b == this || b->IsDominatedBy(this))
lblocks.Push(b);
else
{
if (b->mFalseJump)
addprefix = true;
pblocks.Push(b);
}
}
if (pblocks.Size() < mEntryBlocks.Size())
{
if (pblocks.Size() > 1 || addprefix)
{
pblock = mProc->AllocateBlock();
pblock->mEntryRequiredRegs = mEntryRequiredRegs;
pblock->mExitRequiredRegs = mEntryRequiredRegs;
pblock->Close(pblocks[0]->mBranchIns, this, nullptr, ASMIT_JMP);
AddEntryBlock(pblock);
for (int i = 0; i < pblocks.Size(); i++)
{
NativeCodeBasicBlock* b = pblocks[i];
if (this == b->mTrueJump)
{
b->mTrueJump = pblock;
RemEntryBlock(b);
pblock->AddEntryBlock(b);
}
if (this == b->mFalseJump)
{
b->mFalseJump = pblock;
RemEntryBlock(b);
pblock->AddEntryBlock(b);
}
}
}
else if (pblocks.Size() == 1)
pblock = pblocks[0];
}
if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
{
proc->ResetPatched();
mPatched = true;
if (!lblocks.Contains(this))
lblocks.Push(this);
for (int i = 0; i < lblocks.Size(); i++)
lblocks[i]->mPatched = true;
pblock->mPatched = true;
int i = 0;
while (i < lblocks.Size())
{
NativeCodeBasicBlock* block = lblocks[i];
for(int j=0; j<block->mEntryBlocks.Size(); j++)
{
NativeCodeBasicBlock* cblock = block->mEntryBlocks[j];
if (!cblock->mPatched)
{
cblock->mPatched = true;
lblocks.Push(cblock);
}
}
i++;
}
NativeCodeBasicBlock* eblock = nullptr;
i = 0;
while (i < lblocks.Size())
{
NativeCodeBasicBlock* b = lblocks[i];
// !FIXME should be &&
if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
{
if (eblock)
{
eblock = nullptr;
break;
}
else
eblock = b;
}
i++;
}
if (eblock)
{
bool aimm = false;
NativeCodeInstruction ains;
if (!pblock->mExitRequiredRegs[CPU_REG_A] || !pblock->mExitRequiredRegs[CPU_REG_X])
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS))
{
aimm = true;
ains = mIns[i];
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !this->ChangesZeroPage(mIns[i].mAddress))
{
int j = 0;
while (j < lblocks.Size() && !lblocks[j]->ChangesZeroPage(mIns[i].mAddress))
j++;
if (j == lblocks.Size())
{
aimm = true;
ains = mIns[i];
}
else
aimm = false;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm)
{
int reg = mIns[i].mAddress;
if (!ReferencedOnPath(this, 0, i, reg) && !ChangedOnPath(this, i + 1, mIns.Size(), reg))
{
int k = 0;
while (k < lblocks.Size() && !(lblocks[k] != this && lblocks[k]->ChangesZeroPage(reg)))
k++;
if (k == lblocks.Size())
{
if (!pblock->mExitRequiredRegs[CPU_REG_A])
{
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ains));
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else if (!pblock->mExitRequiredRegs[CPU_REG_X])
{
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ains));
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
}
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
mEntryRequiredRegs += reg;
mExitRequiredRegs += reg;
pblock->mExitRequiredRegs += reg;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += reg;
lblocks[i]->mExitRequiredRegs += reg;
}
}
}
}
else if (mIns[i].ChangesAccu())
aimm = false;
}
}
if (!changed)
{
changed = OptimizeSingleEntryLoopInvariant(proc, pblock, eblock, lblocks);
}
}
}
}
if (mTrueJump && mTrueJump->OptimizeSingleEntryLoop(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeSingleEntryLoop(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mFalseJump)
{
NativeCodeBasicBlock* hblock = nullptr;
if (mBranch == ASMIT_BCC && mTrueJump->mLoopHead)
hblock = mTrueJump;
else if (mBranch == ASMIT_BCS && mFalseJump->mLoopHead)
hblock = mFalseJump;
if (hblock && hblock->mIns.Size() > 0 && hblock->mIns[0].mType == ASMIT_CLC && hblock->mNumEntries == 2)
{
NativeCodeBasicBlock* pblock;
if (hblock->mEntryBlocks[0] == this)
pblock = hblock->mEntryBlocks[1];
else
pblock = hblock->mEntryBlocks[0];
if (!pblock->mFalseJump)
{
pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_CLC));
hblock->mIns.Remove(0);
pblock->mExitRequiredRegs += CPU_REG_C;
hblock->mEntryRequiredRegs += CPU_REG_C;
mExitRequiredRegs += CPU_REG_C;
changed = true;
}
}
int sz = mIns.Size();
if (sz > 0)
{
hblock = nullptr;
if (mTrueJump->mLoopHead)
hblock = mTrueJump;
else if (mFalseJump->mLoopHead)
hblock = mFalseJump;
if (hblock && hblock->mIns.Size() > 0 && hblock->mNumEntries == 2)
{
NativeCodeBasicBlock* pblock;
if (hblock->mEntryBlocks[0] == this)
pblock = hblock->mEntryBlocks[1];
else
pblock = hblock->mEntryBlocks[0];
if (!pblock->mFalseJump)
{
if (hblock->mIns[0].mType == ASMIT_TAX && mIns[sz - 1].mType == ASMIT_TXA && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z))
{
pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_TAX));
hblock->mIns.Remove(0);
pblock->mExitRequiredRegs += CPU_REG_X;
hblock->mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
changed = true;
}
else if (hblock->mIns[0].mType == ASMIT_TAY && mIns[sz - 1].mType == ASMIT_TYA && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z))
{
pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_TAY));
hblock->mIns.Remove(0);
pblock->mExitRequiredRegs += CPU_REG_Y;
hblock->mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
changed = true;
}
else if (sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA
&& hblock->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z) && !(hblock->mIns[0].mFlags & NCIF_VOLATILE))
{
pblock->mIns.Push(hblock->mIns[0]);
hblock->mIns.Remove(0);
pblock->mExitRequiredRegs += CPU_REG_A;
hblock->mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
changed = true;
}
}
}
}
}
if (mTrueJump && mTrueJump->OptimizeLoopCarryOver())
changed = true;
if (mFalseJump && mFalseJump->OptimizeLoopCarryOver())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::RemoveSimpleLoopUnusedIndex(void)
{
bool changed = false;
assert(mEntryRequiredRegs.Size() > 0);
if (!mVisited)
{
mVisited = true;
if (mFalseJump && mTrueJump == this)
{
NumberSet required(mFalseJump->mEntryRequiredRegs);
bool complex = false;
int k = mIns.Size() - 1;
while (k >= 0)
{
NativeCodeInstruction & ins(mIns[k]);
if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && !(ins.mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && !required[ins.mAddress])
{
if (k > 2 && mIns[k - 1].mMode == ASMIM_IMMEDIATE && mIns[k - 2].mType == ASMIT_LDA && mIns[k - 2].mMode == ASMIM_ZERO_PAGE && mIns[k - 2].mAddress == mIns[k].mAddress)
k -= 2;
else
required += ins.mAddress;
}
else if (ins.mMode == ASMIM_ZERO_PAGE)
required += ins.mAddress;
else if (ins.mMode == ASMIM_INDIRECT_Y)
{
required += ins.mAddress;
required += ins.mAddress + 1;
}
else if (ins.mType == ASMIT_JSR)
{
required += BC_REG_ADDR + 0;
required += BC_REG_ADDR + 1;
for (int i = 0; i < 4; i++)
required += BC_REG_ACCU + i;
for (int i = 0; i < 8; i++)
required += BC_REG_WORK + i;
required += BC_REG_WORK_Y;
if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
{
#if 1
if (ins.mLinkerObject)
{
LinkerObject* lo = ins.mLinkerObject;
for (int i = 0; i < 256; i++)
{
if (lo->mZeroPageSet[i])
required += i;
}
for (int i = 0; i < ins.mLinkerObject->mNumTemporaries; i++)
{
for (int j = 0; j < ins.mLinkerObject->mTempSizes[i]; j++)
required += ins.mLinkerObject->mTemporaries[i] + j;
}
}
#else
for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
required += i;
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
required += i;
#endif
}
// complex = true;
}
k--;
}
if (!complex)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !required[mIns[i].mAddress])
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->RemoveSimpleLoopUnusedIndex())
changed = true;
if (mFalseJump && mFalseJump->RemoveSimpleLoopUnusedIndex())
changed = true;
}
return changed;
}
static bool Is16BitInc(NativeCodeBasicBlock* block, int reg, int at)
{
if (at + 6 < block->mIns.Size())
{
if (block->mIns[at + 0].mType == ASMIT_CLC &&
block->mIns[at + 1].mType == ASMIT_LDA && block->mIns[at + 1].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 1].mAddress == reg &&
block->mIns[at + 2].mType == ASMIT_ADC && block->mIns[at + 2].mMode == ASMIM_IMMEDIATE && block->mIns[at + 2].mAddress == 1 &&
block->mIns[at + 3].mType == ASMIT_STA && block->mIns[at + 3].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 3].mAddress == reg &&
block->mIns[at + 4].mType == ASMIT_LDA && block->mIns[at + 4].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 4].mAddress == reg + 1 &&
block->mIns[at + 5].mType == ASMIT_ADC && block->mIns[at + 5].mMode == ASMIM_IMMEDIATE && block->mIns[at + 5].mAddress == 0 &&
block->mIns[at + 6].mType == ASMIT_STA && block->mIns[at + 6].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 6].mAddress == reg + 1 &&
!(block->mIns[at + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
return true;
}
}
return false;
}
static bool IsPointerIncAddrs(NativeCodeBasicBlock* block, int reg)
{
bool changed = false;
bool used = false;
int i = 0;
while (i < block->mIns.Size())
{
NativeCodeInstruction ins(block->mIns[i]);
if (ins.mMode == ASMIM_INDIRECT_Y)
{
if (ins.mAddress == reg)
{
if (changed)
return false;
used = true;
i++;
}
else
return false;
}
else if (Is16BitInc(block, reg, i))
{
changed = true;
i += 7;
}
else if (ins.ReferencesZeroPage(reg) || ins.ReferencesZeroPage(reg + 1) || ins.ReferencesYReg())
return false;
else
i++;
}
return changed;
}
bool NativeCodeBasicBlock::Is16BitImmSum(int at, int& val, int& reg) const
{
if (at + 6 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress == mIns[at + 1].mAddress &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == mIns[at + 1].mAddress + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress == mIns[at + 4].mAddress)
{
reg = mIns[at + 1].mAddress;
val = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prevBlock, NativeCodeBasicBlock* exitBlock, bool full)
{
bool changed = false;
if (mBranch == ASMIT_JMP)
return false;
assert(mEntryRequiredRegs.Size());
CheckLive();
if (!exitBlock)
{
if (mTrueJump == this)
exitBlock = mFalseJump;
else
exitBlock = mTrueJump;
}
int sz = mIns.Size();
if (sz == 2 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && mIns[0].mType == ASMIT_LDA && mIns[1].mType == ASMIT_CMP && !(mIns[1].mFlags & NCIF_VOLATILE) && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mIns[1].mType = ASMIT_LDA; mIns[1].mLive |= LIVE_CPU_REG_A;
mIns[0].mType = ASMIT_CMP; mIns[0].mLive |= LIVE_CPU_REG_Z;
prevBlock->mIns.Push(mIns[1]);
prevBlock->mExitRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mIns.Remove(1);
CheckLive();
return true;
}
#if 1
if (full && mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_C] && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
{
int i = 0;
while (i < mIns.Size() && !mIns[i].ChangesCarry())
i++;
if (i < mIns.Size() &&
mIns[i].mType == ASMIT_CLC && ((mBranch == ASMIT_BCC && mTrueJump == this) || (mBranch == ASMIT_BCS && mFalseJump == this)) ||
mIns[i].mType == ASMIT_SEC && ((mBranch == ASMIT_BCS && mTrueJump == this) || (mBranch == ASMIT_BCC && mFalseJump == this)))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[i]);
prevBlock->mExitRequiredRegs += CPU_REG_C;
for (int j = 0; j < i; j++)
mIns[j].mLive |= LIVE_CPU_REG_C;
mEntryRequiredRegs += CPU_REG_C;
mIns.Remove(i);
CheckLive();
return true;
}
}
#endif
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int reg = mIns[i + 1].mAddress;
if (!ReferencesZeroPage(reg, 0, i) && !ChangesZeroPage(reg, i + 2))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
if (!mEntryRequiredRegs[CPU_REG_A])
{
prevBlock->mIns.Push(mIns[i + 0]);
prevBlock->mIns.Push(mIns[i + 1]);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
prevBlock->mExitRequiredRegs += reg;
mEntryRequiredRegs += reg;
mExitRequiredRegs += reg;
changed = true;
}
}
}
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int a0 = mIns[i + 0].mAddress, a1 = mIns[i + 1].mAddress;
if (!mEntryRequiredRegs[a0] && !ReferencesZeroPage(a0, i + 2) && !ChangesZeroPage(a1, i + 2))
{
if (!exitBlock)
return OptimizeSimpleLoopInvariant(proc, full);
if (exitBlock->mNumEntries == 1 && !exitBlock->mEntryRequiredRegs[CPU_REG_Z])
{
if (!exitBlock->mEntryRequiredRegs[CPU_REG_A])
{
mExitRequiredRegs += a1;
exitBlock->mEntryRequiredRegs += a1;
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, mIns[i + 1]));
exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, mIns[i + 0]));
mIns.Remove(i + 0);
sz--;
changed = true;
}
}
}
else if (!mEntryRequiredRegs[a1] && !ReferencesZeroPage(a1, i + 2) && !ChangesZeroPage(a0, i + 2))
{
if (!exitBlock)
return OptimizeSimpleLoopInvariant(proc, full);
if (exitBlock->mNumEntries == 1 && !exitBlock->mEntryRequiredRegs[CPU_REG_Z])
{
if (!exitBlock->mEntryRequiredRegs[CPU_REG_A])
{
mExitRequiredRegs += a0;
exitBlock->mEntryRequiredRegs += a0;
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDA, mIns[i + 0]));
exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, mIns[i + 1]));
mIns.Remove(i + 1);
sz--;
changed = true;
}
}
}
}
}
if (sz >= 3 && mIns[0].mType == ASMIT_LDA && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) && mIns[sz - 1].mType == ASMIT_CMP)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->CheckLive();
CheckLive();
return true;
}
if (sz >= 2 && mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 1]))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->CheckLive();
CheckLive();
return true;
}
if (sz >= 3 && mIns[0].mType == ASMIT_LDY && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) &&
mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mIns[sz - 2].mType = ASMIT_LDY; mIns[sz - 2].mLive |= LIVE_CPU_REG_Y;
mIns[sz - 1].mType = ASMIT_CPY; mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
prevBlock->mExitRequiredRegs += CPU_REG_Y;
prevBlock->CheckLive();
CheckLive();
return true;
}
if (sz >= 2 && mIns[0].mType == ASMIT_LDY && mIns[sz - 1].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 1]) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mIns[sz - 1].mType = ASMIT_LDY; mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
prevBlock->mExitRequiredRegs += CPU_REG_Y;
prevBlock->CheckLive();
CheckLive();
return true;
}
if (sz >= 3 && mIns[0].mType == ASMIT_LDX && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) &&
mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mIns[sz - 2].mType = ASMIT_LDX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X;
mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
prevBlock->mExitRequiredRegs += CPU_REG_X;
prevBlock->CheckLive();
CheckLive();
return true;
}
int si = 0, ei = mIns.Size() - 1;
while (si < mIns.Size() && !mIns[si].ReferencesYReg())
si++;
while (ei > si && !(mIns[ei].ChangesYReg() || mIns[ei].mType == ASMIT_STY))
ei--;
if (si < ei && mIns[si].mType == ASMIT_LDY && mIns[ei].mType == ASMIT_STY && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
if (prevBlock->mExitRequiredRegs[CPU_REG_C])
mIns[si].mLive |= LIVE_CPU_REG_C;
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
CheckLive();
prevBlock->CheckLive();
return true;
}
}
}
if (si < ei && mIns[ei].mType == ASMIT_STY && mIns[ei].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
j++;
if (j == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mExitRequiredRegs += CPU_REG_Y;
exitBlock->mEntryRequiredRegs += CPU_REG_Y;
exitBlock->mIns.Insert(0, mIns[ei]);
mIns.Remove(ei);
CheckLive();
return true;
}
}
si = 0, ei = mIns.Size() - 1;
while (si < mIns.Size() && !mIns[si].ReferencesXReg())
si++;
while (ei > si && !(mIns[ei].ChangesXReg() || mIns[ei].mType == ASMIT_STX))
ei--;
if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[ei].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
if (prevBlock->mExitRequiredRegs[CPU_REG_C])
mIns[si].mLive |= LIVE_CPU_REG_C;
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
prevBlock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
CheckLive();
prevBlock->CheckLive();
return true;
}
}
}
si = 0;
ei = mIns.Size() - 1;
while (si < mIns.Size() && !mIns[si].ReferencesXReg())
si++;
while (ei > si && !mIns[ei].ReferencesXReg())
ei--;
if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[ei].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
prevBlock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
CheckLive();
prevBlock->CheckLive();
return true;
}
}
}
if (si + 2 < mIns.Size() && mIns[si].mType == ASMIT_LDX && mIns[si + 2].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[si + 2].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[si + 2].mAddress && mIns[si + 1].mType == ASMIT_INX)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = si + 3;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress) && !mIns[i].ChangesXReg())
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
for(int i=0; i<mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
prevBlock->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
CheckLive();
prevBlock->CheckLive();
return true;
}
}
}
if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[si].mMode == ASMIM_ZERO_PAGE)
{
// Loads X once from zero page and never changes it again
int i = si;
while (i < ei && !mIns[i + 1].ChangesXReg())
i++;
if (i == ei)
{
i = 0;
while (i < si && !mIns[i].ReferencesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i++;
while (i < mIns.Size() && !mIns[i].ReferencesZeroPage(mIns[si].mAddress))
i++;
if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC) && (!(mIns[ei].mLive & LIVE_CPU_REG_Z) || mIns[ei].ChangesAccuAndFlag()))
{
int j = i + 1;
while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(mIns[si].mAddress))
j++;
if (j == mIns.Size())
{
// So we have an LDX from ZP, and exactly one INC/DECof this ZP and X never changes in the loop
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
bool needRecheck = mIns[ei].mLive & LIVE_CPU_REG_Z;
prevBlock->mIns.Push(mIns[si]);
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[si].mIns, ASMIT_STX, mIns[si]));
mIns[si].mType = ASMIT_NOP;
mIns[si].mMode = ASMIM_IMPLIED;
AsmInsType t;
if (mIns[i].mType == ASMIT_DEC)
t = ASMIT_DEX;
else
t = ASMIT_INX;
if (i < ei)
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
if (needRecheck)
{
mIns[ei].mLive |= LIVE_CPU_REG_A;
mIns.Insert(ei + 1, NativeCodeInstruction(mIns[ei].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
}
mIns.Insert(ei + 1, NativeCodeInstruction(mIns[i].mIns, t));
}
else
{
mIns[i].mType = t;
mIns[i].mMode = ASMIM_IMPLIED;
}
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
prevBlock->mExitRequiredRegs += CPU_REG_X;
exitBlock->mEntryRequiredRegs += CPU_REG_X;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
}
}
}
if (si < ei && mIns[ei].mType == ASMIT_STX && mIns[ei].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
j++;
if (j == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
exitBlock->mIns.Insert(0, mIns[ei]);
mIns.Remove(ei);
CheckLive();
return true;
}
}
si = 0;
ei = mIns.Size() - 1;
while (si < mIns.Size() && !mIns[si].ReferencesAccu())
si++;
while (ei > si && !mIns[ei].ReferencesAccu())
ei--;
if (si < ei && mIns[si].mType == ASMIT_LDA && mIns[ei].mType == ASMIT_STA && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
}
ei = mIns.Size() - 1;
while (ei > si && !mIns[ei].ReferencesYReg())
ei--;
if (si < ei && mIns[si].mType == ASMIT_TYA && mIns[ei].mType == ASMIT_TAY)
{
int i = 0;
while (i < si && !mIns[i].ChangesYReg())
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesAccu())
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
}
if (si + 2 < ei &&
mIns[si + 0].mType == ASMIT_LDA &&
mIns[si + 1].mType == ASMIT_CLC &&
mIns[si + 2].mType == ASMIT_ADC &&
mIns[ei].mType == ASMIT_STA && mIns[si + 2].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si + 2].mAddress == mIns[ei].mAddress)
{
int i = 0;
while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == si)
{
i = ei + 1;
while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
i = 0;
while (i < si)
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
i = ei;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_A;
i++;
}
mIns[si + 2].CopyMode(mIns[si + 0]);
if (mIns[si + 2].RequiresYReg())
mIns[si + 1].mLive |= LIVE_CPU_REG_Y;
if (mIns[si + 2].RequiresXReg())
mIns[si + 1].mLive |= LIVE_CPU_REG_X;
mIns[si + 0].CopyMode(mIns[ei]);
prevBlock->mIns.Push(mIns[si]);
mIns.Remove(si);
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
}
if (si < ei && mIns[ei].mType == ASMIT_STA && mIns[ei].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
j++;
if (j == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
exitBlock->mIns.Insert(0, mIns[ei]);
mIns.Remove(ei);
CheckLive();
return true;
}
}
if (sz >= 2 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
{
int i = mIns.Size() - 1;
while (i > 0 && !mIns[i].ChangesYReg() && !mIns[i].ChangesZeroPage(mIns[0].mAddress))
i--;
if (i > 0 &&
(mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[0].mAddress) ||
(mIns[i].mType == ASMIT_TAY && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_STA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == mIns[0].mAddress))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
if (sz >= 2 && mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE)
{
int i = mIns.Size() - 1;
while (i > 0 && !mIns[i].ChangesXReg() && !mIns[i].ChangesZeroPage(mIns[0].mAddress))
i--;
if (i > 0 &&
(mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[0].mAddress) ||
(mIns[i].mType == ASMIT_TAX && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_STA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == mIns[0].mAddress))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_X;
i++;
}
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
prevBlock->mExitRequiredRegs += CPU_REG_X;
prevBlock->CheckLive();
CheckLive();
return true;
}
}
if (sz >= 2 &&
mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_MEM) &&
mIns[1].mType == ASMIT_STA && mIns[1].mMode == ASMIM_ZERO_PAGE && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
int i = mIns.Size() - 1;
while (i > 1 && !mIns[i].ReferencesZeroPage(mIns[1].mAddress) && !mIns[i].ReferencesZeroPage(mIns[0].mAddress))
i--;
if (i > 1)
{
i--;
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[1].mAddress &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[0].mAddress && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if ((!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && (!mExitRequiredRegs[CPU_REG_A] || !mExitRequiredRegs[CPU_REG_X]) && !mExitRequiredRegs[CPU_REG_Z])
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[0]);
prevBlock->mIns.Push(mIns[1]);
if (mEntryRequiredRegs[CPU_REG_A])
{
prevBlock->mIns[prevBlock->mIns.Size() - 2].mType = ASMIT_LDX;
prevBlock->mIns[prevBlock->mIns.Size() - 2].mLive |= LIVE_CPU_REG_X;
prevBlock->mIns[prevBlock->mIns.Size() - 1].mType = ASMIT_STX;
}
exitBlock->mIns.Insert(0, mIns[i + 0]);
exitBlock->mIns.Insert(1, mIns[i + 1]);
if (mExitRequiredRegs[CPU_REG_A])
{
exitBlock->mIns[0].mType = ASMIT_LDX;
exitBlock->mIns[0].mLive |= LIVE_CPU_REG_X;
exitBlock->mIns[1].mType = ASMIT_STX;
}
mIns.Remove(i + 1);
mIns.Remove(0); mIns.Remove(0);
prevBlock->CheckLive();
CheckLive();
return true;
}
}
}
}
int ai = 0;
while (ai < mIns.Size() && !mIns[ai].ChangesAccu())
ai++;
if (ai < mIns.Size() && !(mIns[ai].mLive & LIVE_CPU_REG_Z))
{
if (mIns[ai].mType == ASMIT_LDA && mIns[ai].mMode == ASMIM_IMMEDIATE)
{
int i = ai + 1;
while (i < mIns.Size() && !mIns[i].ChangesAccu())
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mEntryRequiredRegs += CPU_REG_A;
for(int i=0; i<mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
prevBlock->mIns.Push(mIns[ai]);
mIns.Remove(ai);
changed = true;
}
}
else if (mIns[ai].mType == ASMIT_LDA && mIns[ai].mMode == ASMIM_ZERO_PAGE)
{
int i = 0;
while (i < mIns.Size() && (i <= ai || !mIns[i].ChangesAccu()) && !mIns[i].ChangesZeroPage(mIns[ai].mAddress))
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[ai]);
mIns.Remove(ai);
mEntryRequiredRegs += CPU_REG_A;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
changed = true;
}
i = mIns.Size() - 1;
while (i >= 0 && !mIns[i].ChangesAccu() && mIns[i].mType != ASMIT_STA)
i--;
if (i >= 0 && mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[ai].mAddress)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[ai]);
mIns.Remove(ai);
mEntryRequiredRegs += CPU_REG_A;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
prevBlock->mExitRequiredRegs += CPU_REG_A;
changed = true;
}
}
}
ai = 0;
while (ai < mIns.Size() && !mIns[ai].ChangesYReg())
ai++;
if (ai < mIns.Size())
{
if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_IMMEDIATE)
{
int i = ai + 1;
while (i < mIns.Size() && !mIns[i].ChangesYReg())
i++;
if (i == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
prevBlock->mIns.Push(mIns[ai]);
mIns.Remove(ai);
mEntryRequiredRegs += CPU_REG_Y;
prevBlock->mExitRequiredRegs += CPU_REG_Y;
changed = true;
}
}
else if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_ZERO_PAGE && !(mIns[ai].mLive & LIVE_CPU_REG_Z))
{
int i = 0;
while (i < mIns.Size() && (i == ai || !mIns[i].ChangesYReg()))
i++;
if (i == mIns.Size())
{
int addr = mIns[ai].mAddress;
bool fail = false, changey = false, changev = false;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY)
changey = false;
else if (mIns[i].ReferencesYReg() && changey)
{
fail = true;
break;
}
else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
if (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_INC || mIns[i].mType == ASMIT_DEC)
{
changey = true;
changev = true;
}
else if (mIns[i].mType != ASMIT_LDA)
{
fail = true;
break;
}
}
}
if (!fail)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
changed = true;
prevBlock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
exitBlock->mEntryRequiredRegs += CPU_REG_Y;
prevBlock->mIns.Push(NativeCodeInstruction(mIns[ai].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
if (changev)
exitBlock->mIns.Push(NativeCodeInstruction(mIns[ai].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
for (int i = 0; i < mIns.Size(); i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
if (mIns[i].mType == ASMIT_LDA)
{
mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_STA)
{
mIns[i].mType = ASMIT_TAY; mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_LDY)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_INC)
{
mIns[i].mType = ASMIT_INY; mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_DEC)
{
mIns[i].mType = ASMIT_DEY; mIns[i].mMode = ASMIM_IMPLIED;
}
}
}
}
}
}
}
else
{
int i = 0;
while (i < mIns.Size() && !mIns[i].ReferencesYReg())
i++;
if (i < mIns.Size() && mIns[i].mMode == ASMIM_INDIRECT_Y && IsPointerIncAddrs(this, mIns[i].mAddress))
{
NativeCodeBasicBlock* oblock = mTrueJump == this ? mFalseJump : mTrueJump;
int reg = mIns[i].mAddress;
if (!oblock->mEntryRequiredRegs[CPU_REG_Y] &&
!oblock->mEntryRequiredRegs[reg] &&
!oblock->mEntryRequiredRegs[reg + 1])
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == reg)
{
if (mIns[i].mType == ASMIT_LDA)
{
mIns[i].mType = ASMIT_TYA;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_STA)
{
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
}
}
}
changed = true;
}
}
}
#if 1
if (mEntryRequiredRegs.Size() && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && (!mExitRequiredRegs[CPU_REG_A] || !mExitRequiredRegs[CPU_REG_X]) && !mExitRequiredRegs[CPU_REG_Z])
{
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < mIns.Size() &&
(j == i + 0 || !mIns[j].ChangesZeroPage(mIns[i + 0].mAddress)) &&
(j == i + 1 || !mIns[j].ChangesZeroPage(mIns[i + 1].mAddress)))
j++;
if (j == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
if (!mEntryRequiredRegs[CPU_REG_A])
{
assert(mIns[0].mType != ASMIT_STA);
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
else
{
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
else if (j > i && !(mIns[i + 0].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[mIns[i + 1].mAddress] && !ReferencesZeroPage(mIns[i + 0].mAddress, 0, i))
{
int j = mIns.Size() - 1;
while (j >= i + 2 && !mIns[j].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[j].ReferencesZeroPage(mIns[i + 1].mAddress))
j--;
if (j >= i + 2 && mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[i + 0].mAddress)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
mIns[j].mAddress = mIns[i + 1].mAddress;
if (!mEntryRequiredRegs[CPU_REG_A])
{
assert(mIns[0].mType != ASMIT_STA);
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
else
{
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
prevBlock->mExitRequiredRegs += mIns[i + 1].mAddress;
mEntryRequiredRegs += mIns[i + 1].mAddress;
mExitRequiredRegs += mIns[i + 1].mAddress;
if (!mExitRequiredRegs[CPU_REG_A])
{
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
}
else
{
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
}
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < mIns.Size() &&
(j == i + 1 || !mIns[j].ChangesZeroPage(mIns[i + 1].mAddress)))
j++;
if (j == mIns.Size())
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
int k = prevBlock->mIns.Size();
while (k > 0 && (prevBlock->mIns[k - 1].mLive & LIVE_CPU_REG_A))
k--;
if (!mEntryRequiredRegs[CPU_REG_A])
{
assert(mIns[0].mType != ASMIT_STA);
prevBlock->mIns.Insert(k, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 0].mAddress));
prevBlock->mIns.Insert(k + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
else
{
prevBlock->mIns.Insert(k, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, mIns[i + 0].mAddress));
prevBlock->mIns.Insert(k + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
}
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
}
}
}
#endif
#if 1
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1)
{
int treg = mIns[i + 3].mAddress;
int sreg = mIns[i + 1].mAddress;
int areg = mIns[i + 2].mAddress;
if (sreg != treg && areg != treg &&
!mExitRequiredRegs[treg] && !mExitRequiredRegs[treg + 1] &&
!ReferencesZeroPage(treg, 0, i) && !ReferencesZeroPage(treg + 1, 0, i) &&
!ChangesZeroPage(treg, i + 7) && !ChangesZeroPage(treg + 1, i + 7) &&
!ChangesZeroPage(sreg) && !ChangesZeroPage(sreg + 1))
{
int j = i + 7;
while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(treg) && !mIns[j].ReferencesZeroPage(treg + 1) && !mIns[j].ChangesZeroPage(areg))
j++;
if (j < mIns.Size() && mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == treg)
{
if (mIns[j - 1].mType == ASMIT_LDY && mIns[j - 1].mMode == ASMIM_IMMEDIATE && !(mIns[j].mLive & LIVE_CPU_REG_Y) && !ReferencesZeroPage(treg, j + 1) && !ReferencesZeroPage(treg + 1, j + 1))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_CLC));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_ADC, ASMIM_IMMEDIATE, mIns[j - 1].mAddress));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
prevBlock->mExitRequiredRegs += treg;
prevBlock->mExitRequiredRegs += treg + 1;
mIns[j - 1].mMode = ASMIM_ZERO_PAGE;
mIns[j - 1].mAddress = areg;
mEntryRequiredRegs += treg;
mEntryRequiredRegs += treg + 1;
mExitRequiredRegs += treg;
mExitRequiredRegs += treg + 1;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
}
}
#endif
#if 1
sz = mIns.Size();
if (sz >= 2 && mIns[sz - 2].mType == ASMIT_INX && mIns[sz - 1].mType == ASMIT_CPX && !mEntryRequiredRegs[CPU_REG_Y] && !mExitRequiredRegs[CPU_REG_Y])
{
int xtoy = -1;
for (int i = 0; i < sz - 2; i++)
{
if (mIns[i].ChangesXReg())
{
xtoy = -1;
break;
}
if (mIns[i].ChangesYReg())
{
if (xtoy >= 0)
{
xtoy = -1;
break;
}
if (i >= 3 &&
mIns[i - 0].mType == ASMIT_TAY &&
mIns[i - 1].mType == ASMIT_ADC &&
mIns[i - 2].mType == ASMIT_TXA &&
mIns[i - 3].mType == ASMIT_CLC &&
!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
xtoy = i - 3;
else
{
xtoy = -1;
break;
}
}
}
if (xtoy >= 0)
{
int i = 0;
while (i < sz && !mIns[xtoy + 1].MayBeChangedOnAddress(mIns[i]))
i++;
if (i == sz)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(mIns[xtoy + 0]);
prevBlock->mIns.Push(mIns[xtoy + 1]);
prevBlock->mIns.Push(mIns[xtoy + 2]);
prevBlock->mIns.Push(mIns[xtoy + 3]);
mIns.Insert(sz - 2, NativeCodeInstruction(mIns[xtoy].mIns, ASMIT_INY));
mIns.Remove(xtoy, 4);
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
}
}
}
#endif
#if 1
sz = mIns.Size();
if (sz >= 2 && (mBranch == ASMIT_BEQ && mFalseJump == this || mBranch == ASMIT_BNE && mTrueJump == this) &&
((mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && !mEntryRequiredRegs[CPU_REG_A]) ||
(mIns[sz - 2].mType == ASMIT_LDX && mIns[sz - 1].mType == ASMIT_CPX && !mEntryRequiredRegs[CPU_REG_X]) ||
(mIns[sz - 2].mType == ASMIT_LDY && mIns[sz - 1].mType == ASMIT_CPY && !mEntryRequiredRegs[CPU_REG_Y])) &&
mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
{
if (ChangesZeroPage(mIns[sz - 1].mAddress) && !ChangesZeroPage(mIns[sz - 2].mAddress))
{
int a = mIns[sz - 1].mAddress;
mIns[sz - 1].mAddress = mIns[sz - 2].mAddress;
mIns[sz - 2].mAddress = a;
changed = true;
}
}
#endif
if (sz >= 2 && (mIns[0].mType == ASMIT_ASL || mIns[0].mType == ASMIT_LSR) && mIns[0].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mIns[0]))
{
if (!ChangesZeroPage(mIns[0].mAddress, 1, sz - 1) && !ReferencesZeroPage(mIns[0].mAddress, 1, sz - 1) && !ReferencesAccu(0, sz - 1))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDA, mIns[0]));
prevBlock->mExitRequiredRegs += CPU_REG_A;
exitBlock->mEntryRequiredRegs += CPU_REG_A;
exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
mIns[0].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0;
for (int i = 0; i < sz; i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
changed = true;
}
}
if (sz >= 2 && (mIns[0].mType == ASMIT_DEC || mIns[0].mType == ASMIT_INC) && mIns[0].mMode == ASMIM_ZERO_PAGE &&
mIns[1].mType == ASMIT_LDY && mIns[1].SameEffectiveAddress(mIns[0]))
{
int i = 2;
int inc = 0;
while (i < mIns.Size())
{
if (mIns[i].ChangesYReg())
{
if (mIns[i].mType == ASMIT_INY)
inc++;
else if (mIns[i].mType == ASMIT_DEY)
inc--;
else if (mIns[i].mType == ASMIT_LDY && mIns[i].SameEffectiveAddress(mIns[0]))
inc = 0;
else
break;
}
else if (mIns[i].ChangesZeroPage(mIns[0].mAddress))
break;
i++;
}
if (i == mIns.Size() && inc == 0)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(NativeCodeInstruction(mIns[1].mIns, ASMIT_LDY, mIns[1]));
prevBlock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
mIns[1].mType = ASMIT_STY;
mIns[0].mLive |= LIVE_CPU_REG_Y;
if (mIns[0].mType == ASMIT_DEC)
mIns[0].mType = ASMIT_DEY;
else
mIns[0].mType = ASMIT_INY;
mIns[0].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (mIns.Size() > 0 && (mIns.Last().mType == ASMIT_DEX || mIns.Last().mType == ASMIT_DEC || mIns.Last().mType == ASMIT_CPX))
{
bool yzero = false;
if (prevBlock)
yzero = prevBlock->RetrieveYValue(prevBlock->mIns.Size() - 1) == 0;
int nregs = 0;
int iregs[32];
for (int i = 0; i + 3 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
yzero = true;
else if (mIns[i].ChangesYReg())
{
nregs = 0;
break;
}
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
if (!yzero)
{
nregs = 0;
break;
}
int reg = mIns[i].mAddress;
if (ReferencesZeroPage(mIns[i].mAddress, 0, i) ||
ReferencesZeroPage(mIns[i].mAddress + 1, 0, i))
{
nregs = 0;
break;
}
if (exitBlock->mEntryRequiredRegs[reg] || exitBlock->mEntryRequiredRegs[reg + 1] || exitBlock->mEntryRequiredRegs[CPU_REG_Y])
{
nregs = 0;
break;
}
int j = i + 1;
while (j < mIns.Size() && (
mIns[j].mMode == ASMIM_INDIRECT ||
!(mIns[j].ReferencesZeroPage(reg) || mIns[j].ReferencesZeroPage(reg + 1))))
j++;
if (j == mIns.Size())
{
nregs = 0;
break;
}
int sreg, dreg, offset;
if (Is16BitAddSubImmediate(j - 1, sreg, dreg, offset) && sreg == reg && dreg == sreg && offset == 1)
{
if (ReferencesZeroPage(reg, j + 6) || ReferencesZeroPage(reg + 1, j + 6))
{
nregs = 0;
break;
}
iregs[nregs++] = sreg;
}
else
{
nregs = 0;
break;
}
}
}
if (nregs)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE)
{
int j = 0;
while (j < nregs && iregs[j] != mIns[i].mAddress && iregs[j] + 1 != mIns[i].mAddress)
j++;
if (j < nregs)
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
}
}
else if (mIns[i].mType == ASMIT_LDY)
{
mIns[i].mType = ASMIT_NOP;
mIns[i].mMode = ASMIM_IMPLIED;
}
mIns[i].mLive |= LIVE_CPU_REG_Y;
}
int j = mIns.Size();
while (j > 0 && (mIns[j - 1].mLive & LIVE_CPU_REG_Z))
j--;
mIns.Insert(j, NativeCodeInstruction(mIns[0].mIns, ASMIT_INY));
prevBlock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
changed = true;
}
}
sz = mIns.Size();
if (sz >= 3 &&
mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
!mIns[0].SameEffectiveAddress(mIns[sz - 2]) && mIns[sz - 1].mType == ASMIT_CMP &&
!exitBlock->mEntryRequiredRegs[mIns[0].mAddress] && !exitBlock->mEntryRequiredRegs[mIns[sz - 2].mAddress] &&
!ChangesZeroPage(mIns[0].mAddress, 1))
{
int ai = mIns[sz - 2].mAddress;
int aj = mIns[0].mAddress;
int i = 1;
while (i < sz - 2 && mIns[i].mMode == ASMIM_ZERO_PAGE || !mIns[i].ReferencesZeroPage(ai))
i++;
if (i == sz - 2)
{
int index;
NativeCodeBasicBlock* block = this;
if (IsExitARegZP(ai, index, block))
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
for (int i = 1; i < sz; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == ai)
mIns[i].mAddress = aj;
}
prevBlock->mIns.Push(mIns[0]);
mIns.Remove(0);
mExitRequiredRegs += aj;
mEntryRequiredRegs += aj;
CheckLive();
return true;
}
}
}
if (sz >= 3 &&
mIns[0].mType == ASMIT_TAY &&
mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 2].mType == ASMIT_TXA && mIns[sz - 3].mType == ASMIT_INX &&
!mExitRequiredRegs[CPU_REG_Y] &&
!ChangesXReg(0, sz - 3) && !ChangesYReg(1, sz - 3))
{
bool canX = true, canY = false;
for (int i = 0; i < sz - 3; i++)
{
if (mIns[i].mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
canY = false;
else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
canX = false;
else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
canX = false;
else if (mIns[i].mMode == ASMIM_INDIRECT_X)
canY = false;
}
if (canX)
{
for (int i = 0; i < sz - 3; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
mIns[i].mMode = ASMIM_ABSOLUTE_X;
}
return true;
}
}
CheckLive();
#if 1
// Exchange Y against low byte of pointer
if (!ChangesYReg() && !mEntryRequiredRegs[CPU_REG_A] && !mExitRequiredRegs[CPU_REG_A])
{
int rind = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
{
if (rind == -1)
rind = mIns[i].mAddress;
else if (rind != mIns[i].mAddress)
{
rind = -2;
break;
}
}
else if (mIns[i].ReferencesYReg())
{
rind = -2;
break;
}
}
if (rind >= 0)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == rind)
{
if (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA)
;
else
{
rind = -2;
break;
}
}
else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
;
else if (mIns[i].ReferencesZeroPage(rind))
{
rind = -2;
break;
}
}
if (rind >= 0)
{
if (!prevBlock)
return OptimizeSimpleLoopInvariant(proc, full);
prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, rind));
prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, rind));
prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TAY));
exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, rind));
exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, rind));
exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TAY));
for (int i = 0; i < mIns.Size(); i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == rind)
{
if (mIns[i].mType == ASMIT_LDA)
{
mIns[i].mType = ASMIT_TYA;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (mIns[i].mType == ASMIT_STA)
{
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
}
}
}
prevBlock->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
exitBlock->mEntryRequiredRegs += CPU_REG_Y;
changed = true;
}
}
}
#endif
return changed;
}
bool NativeCodeBasicBlock::SimpleLoopReversal(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 1 &&
mTrueJump->mBranch == ASMIT_BNE)
{
NativeCodeBasicBlock* lb = mTrueJump;
int lbs = lb->mIns.Size();
if ((lb->mIns[lbs - 2].mType == ASMIT_ROL || lb->mIns[lbs - 2].mType == ASMIT_ROR) && lb->mIns[lbs - 2].mMode == ASMIM_ZERO_PAGE &&
lb->mIns[lbs - 1].mType == ASMIT_DEC && lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE && !(lb->mIns[lbs - 1].mLive & LIVE_CPU_REG_C))
{
if (!lb->ReferencesZeroPage(lb->mIns[lbs - 1].mAddress, 0, lbs - 1) && !lb->ReferencesZeroPage(lb->mIns[lbs - 2].mAddress, 0, lbs - 2) &&
!lb->mFalseJump->mEntryRequiredRegs[lb->mIns[lbs - 1].mAddress])
{
int lcount = RetrieveZPValue(lb->mIns[lbs - 1].mAddress, mIns.Size() - 1);
int lshift = RetrieveZPValue(lb->mIns[lbs - 2].mAddress, mIns.Size() - 1);
if (lcount <= 8 && lshift == 0)
{
if (!mExitRequiredRegs[CPU_REG_A])
{
if (lb->mIns[lbs - 2].mType == ASMIT_ROR)
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (lcount - 1)));
else
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (8 - lcount)));
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, lb->mIns[lbs - 2].mAddress));
lb->mBranch = ASMIT_BCC;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_C;
changed = true;
}
}
}
}
}
if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 1 &&
mTrueJump->mBranch == ASMIT_BCC && !mExitRequiredRegs[CPU_REG_C])
{
NativeCodeBasicBlock* lb = mTrueJump;
NativeCodeBasicBlock* eb = mTrueJump->mFalseJump;
int lbs = lb->mIns.Size();
if (lb->mIns[lbs-1].mType == ASMIT_CPX)
{
int li = mIns.Size() - 1;
while (li >= 0 && !mIns[li].ChangesXReg())
li--;
if (li >= 0 && lb->mIns[lbs-2].mType == ASMIT_INX && mIns[li].mType == ASMIT_LDX && mIns[li].mMode == ASMIM_IMMEDIATE)
{
if (lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE && mIns[li].mAddress == 0)
{
int a = lb->mIns[lbs - 1].mAddress;
int i = 0;
while (i + 2 < lbs && !(lb->mIns[i].RequiresXReg() || lb->mIns[i].ChangesZeroPage(a)))
i++;
if (i + 2 == lbs)
{
mIns[li].mMode = ASMIM_ZERO_PAGE;
mIns[li].mAddress = a;
lb->mIns[lbs - 2].mType = ASMIT_DEX; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BNE;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, mIns[li]));
changed = true;
CheckLive();
}
}
else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
{
int finalx = lb->mIns[lbs - 1].mAddress;
int a = lb->mIns[lbs - 1].mAddress - mIns[li].mAddress;
if (lbs == 3 && lb->mIns[0].mType == ASMIT_STA && lb->mIns[0].mMode == ASMIM_ABSOLUTE_X && lb->mIns[0].mLinkerObject && a < 128)
{
lb->mIns[0].mAddress += mIns[li].mAddress;
mIns[li].mAddress = a - 1;
lb->mIns[1].mType = ASMIT_DEX; lb->mIns[1].mLive |= LIVE_CPU_REG_Z;
lb->mIns[2].mType = ASMIT_NOP; lb->mIns[2].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BPL;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, finalx));
changed = true;
}
else
{
int i = 0;
while (i + 2 < lbs && !lb->mIns[i].RequiresXReg())
i++;
if (i + 2 == lbs)
{
mIns[li].mAddress = a;
lb->mIns[lbs - 2].mType = ASMIT_DEX; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BNE;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, finalx));
changed = true;
CheckLive();
}
}
}
}
}
else if (lb->mIns[lbs - 1].mType == ASMIT_CPY)
{
int li = mIns.Size() - 1;
while (li >= 0 && !mIns[li].ReferencesYReg())
li--;
if (li >= 0 && lb->mIns[lbs - 2].mType == ASMIT_INY && mIns[li].mType == ASMIT_LDY && mIns[li].mMode == ASMIM_IMMEDIATE && mIns[li].mAddress == 0)
{
if (lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE)
{
int a = lb->mIns[lbs - 1].mAddress;
int i = 0;
while (i + 2 < lbs && !(lb->mIns[i].RequiresYReg() || lb->mIns[i].ChangesZeroPage(a)))
i++;
if (i + 2 == lbs)
{
mIns[li].mMode = ASMIM_ZERO_PAGE;
mIns[li].mAddress = a;
lb->mIns[lbs - 2].mType = ASMIT_DEY; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BNE;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, mIns[li]));
changed = true;
CheckLive();
}
}
else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
{
int finaly = lb->mIns[lbs - 1].mAddress;
int a = lb->mIns[lbs - 1].mAddress - mIns[li].mAddress;
if (lbs == 3 && lb->mIns[0].mType == ASMIT_STA && lb->mIns[0].mMode == ASMIM_ABSOLUTE_Y && lb->mIns[0].mLinkerObject && a < 128)
{
lb->mIns[0].mAddress += mIns[li].mAddress;
mIns[li].mAddress = a - 1;
lb->mIns[1].mType = ASMIT_DEY; lb->mIns[1].mLive |= LIVE_CPU_REG_Z;
lb->mIns[2].mType = ASMIT_NOP; lb->mIns[2].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BPL;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
changed = true;
CheckLive();
}
else
{
int i = 0;
while (i + 2 < lbs && !lb->mIns[i].RequiresYReg())
i++;
if (i + 2 == lbs)
{
mIns[li].mAddress = a;
lb->mIns[lbs - 2].mType = ASMIT_DEY; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mBranch = ASMIT_BNE;
eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
changed = true;
CheckLive();
}
}
}
}
}
}
if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 2 &&
mTrueJump->mBranch == ASMIT_BCC)
{
NativeCodeBasicBlock* lb = mTrueJump;
int lbs = lb->mIns.Size();
if ((lb->mIns[lbs - 3].mType == ASMIT_ROL || lb->mIns[lbs - 3].mType == ASMIT_ROR) && lb->mIns[lbs - 3].mMode == ASMIM_ZERO_PAGE &&
lb->mIns[lbs - 2].mType == ASMIT_INY &&
lb->mIns[lbs - 1].mType == ASMIT_CPY && lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
{
if (!lb->ReferencesZeroPage(lb->mIns[lbs - 3].mAddress, 0, lbs - 3))
{
int ystart = RetrieveYValue(mIns.Size() - 1);
int lcount = lb->mIns[lbs - 1].mAddress - ystart;
int lshift = RetrieveZPValue(lb->mIns[lbs - 3].mAddress, mIns.Size() - 1);
if (ystart >= 0 && lcount <= 8 && lshift == 0)
{
if (!mExitRequiredRegs[CPU_REG_A])
{
if (lb->mIns[lbs - 2].mType == ASMIT_ROR)
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (lcount - 1)));
else
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (8 - lcount)));
mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, lb->mIns[lbs - 3].mAddress));
lb->mBranch = ASMIT_BCC;
lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_C;
lb->mIns[lbs - 3].mLive |= LIVE_CPU_REG_C;
changed = true;
}
}
}
}
}
if (mTrueJump && mTrueJump->SimpleLoopReversal(proc))
changed = true;
if (mFalseJump && mFalseJump->SimpleLoopReversal(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeXYSpilling(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && (mTrueJump == this || mFalseJump == this) && mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock* pblock = mEntryBlocks[0];
if (pblock == this)
pblock = mEntryBlocks[1];
NativeCodeBasicBlock* nblock = mTrueJump;
if (nblock == this)
nblock = mFalseJump;
if (nblock)
{
int ps = pblock->mIns.Size();
if (nblock->mEntryBlocks.Size() == 1 && !pblock->mFalseJump && ps > 0)
{
if (!ReferencesAccu())
{
if (!ReferencesXReg() && pblock->mIns.Size() > 0 && pblock->mIns[ps - 1].mType == ASMIT_TAX)
{
nblock->mIns.Insert(0, NativeCodeInstruction(pblock->mIns[ps - 1].mIns, ASMIT_TAX));
pblock->mIns.Remove(ps - 1);
ps--;
pblock->mExitRequiredRegs += CPU_REG_A;
nblock->mEntryRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
changed = true;
}
if (!ReferencesYReg() && pblock->mIns.Size() > 0 && pblock->mIns[ps - 1].mType == ASMIT_TAY)
{
nblock->mIns.Insert(0, NativeCodeInstruction(pblock->mIns[ps - 1].mIns, ASMIT_TAY));
pblock->mIns.Remove(ps - 1);
ps--;
pblock->mExitRequiredRegs += CPU_REG_A;
nblock->mEntryRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_A;
changed = true;
}
}
}
}
}
for (int i = 0; i < mIns.Size(); i++)
{
if (i + 2 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 3, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
mIns.Remove(i);
changed = true;
}
else if (mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 3, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY));
mIns.Remove(i);
changed = true;
}
}
if (i + 1 < mIns.Size())
{
if (mIns[i + 0].mType == ASMIT_TAX && !mIns[i + 1].ChangesAccu() && !mIns[i + 1].ReferencesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
mIns.Remove(i);
changed = true;
}
else if (mIns[i + 0].mType == ASMIT_TAY && !mIns[i + 1].ChangesAccu() && !mIns[i + 1].ReferencesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY));
mIns.Remove(i);
changed = true;
}
}
}
if (mTrueJump && mTrueJump->OptimizeXYSpilling())
changed = true;
if (mFalseJump && mFalseJump->OptimizeXYSpilling())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeXYSimpleLoop(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mTrueJump && mFalseJump && mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock * pblock, * eblock;
if (mTrueJump == this)
eblock = mFalseJump;
else
eblock = mTrueJump;
if (mEntryBlocks[0] == this)
pblock = mEntryBlocks[1];
else
pblock = mEntryBlocks[0];
int sz = mIns.Size();
if (sz > 2 && mIns[sz - 2].mType == ASMIT_STY && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mType == ASMIT_CPY)
{
int addr = mIns[sz - 2].mAddress;
int psz = pblock->mIns.Size();
if (psz > 0 && pblock->mIns[psz - 1].mType == ASMIT_STY && pblock->mIns[psz - 1].mMode == ASMIM_ZERO_PAGE && pblock->mIns[psz - 1].mAddress == addr)
{
int i = 0;
while (i + 2 < sz && !mIns[i].ChangesYReg() && !mIns[i].ChangesZeroPage(addr) && (mIns[i].mLive & LIVE_CPU_REG_Y))
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
{
mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == addr)
{
mIns[i + 1].CopyMode(mIns[i]);
mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
}
i++;
}
}
}
#if 1
if (sz > 2 && mIns[sz - 2].mType == ASMIT_INY && mIns[sz - 1].mType == ASMIT_CPY)
{
int i = 0;
while (i < sz - 2 && !mIns[i].ChangesYReg())
i++;
// y register is simple loop increment
if (i == sz - 2)
{
i = 0;
while (i < sz && !mIns[i].ReferencesXReg())
i++;
if (i < sz && i >= 3 && mIns[i].mType == ASMIT_TAX && mIns[i - 3].mType == ASMIT_TYA && mIns[i - 2].mType == ASMIT_CLC && mIns[i - 1].mType == ASMIT_ADC)
{
int j = i + 4;
while (j < sz && !mIns[j].ChangesXReg())
j++;
if (j == sz)
{
j = 0;
while (j < sz && !mIns[i - 1].MayBeChangedOnAddress(mIns[j]))
j++;
if (j == sz)
{
for (int j = 0; j < 4; j++)
{
pblock->mIns.Push(mIns[i - 3 + j]);
mIns[i - 3 + j].mType = ASMIT_NOP; mIns[i - 3 + j].mMode = ASMIM_IMPLIED;
}
for (int j = 0; j < sz; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
mIns.Insert(sz - 2, NativeCodeInstruction(mIns[i - 3].mIns, ASMIT_INX));
sz++;
changed = true;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
pblock->mExitRequiredRegs += CPU_REG_X;
}
}
}
}
}
#endif
}
if (mTrueJump && mTrueJump->OptimizeXYSimpleLoop())
changed = true;
if (mFalseJump && mFalseJump->OptimizeXYSimpleLoop())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool full)
{
if (!mVisited)
{
mVisited = true;
assert(mLocked || mNumEntries == mEntryBlocks.Size());
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
bool changed = false;
int sz = mIns.Size();
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
#if 1
if (sz > 3 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (mBranch == ASMIT_BCS && mIns[sz - 2].mAddress < 0xff)
{
int val = mIns[sz - 2].mAddress + 1;
mBranch = ASMIT_BCC;
mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
}
else if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff)
{
int val = mIns[sz - 2].mAddress + 1;
mBranch = ASMIT_BCS;
mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
}
else if ((mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
{
int val = mIns[sz - 2].mAddress;
mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
}
}
#endif
if (mFalseJump == this)
{
mBranch = InvertBranchCondition(mBranch);
mFalseJump = mTrueJump;
mTrueJump = this;
}
if (sz <= 3 && mTrueJump == this)
{
changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr, full);
CheckLive();
}
else if (sz > 3 && sz < 200 && mNumEntries >= 2 && mTrueJump == this)
{
bool simple = true;
for(int i=0; i<mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_JSR)
simple = false;
}
if (simple)
{
if ((mIns[sz - 3].mType == ASMIT_INC || mIns[sz - 3].mType == ASMIT_DEC) && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS || mBranch == ASMIT_BNE))
{
// check for usage of Y register
bool yother = false, yindex = false, xother = false, xindex = false;
int zreg = mIns[sz - 3].mAddress;
int limit = mIns[sz - 1].mAddress;
int yinc = 0, xinc = 0;
if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
xother = true;
if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
yother = true;
for (int i = 0; i < sz - 3; i++)
{
if (mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_INY)
yinc++;
else if (mIns[i].mType == ASMIT_DEY)
yinc--;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && yinc >= -1 && yinc <= 1)
{
yinc = 0;
yindex = true;
}
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
if (mIns[i].mType == ASMIT_TAX)
xother = true;
else if (mIns[i].mType == ASMIT_INX)
xinc++;
else if (mIns[i].mType == ASMIT_DEX)
xinc--;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && xinc >= -1 && xinc <= 1)
xindex = true;
else
xother = true;
}
else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
xother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
}
if (!yother)
{
int linc = yinc;
if (mIns[sz - 3].mType == ASMIT_INC)
linc--;
else
linc++;
const InterInstruction* iins(mIns[sz - 3].mIns);
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
yinc = 0;
for (int i = 0; i + 3 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType == ASMIT_LDY)
{
if (yinc > 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
else if (yinc < 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
yinc = 0;
}
else
{
lblock->mIns.Push(mIns[i]);
if (mIns[i].mType == ASMIT_INY)
yinc++;
else if (mIns[i].mType == ASMIT_DEY)
yinc--;
}
}
while (linc < 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
linc++;
}
while (linc > 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY, ASMIM_IMPLIED));
linc--;
}
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, limit));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_Y;
lblock->mEntryRequiredRegs += CPU_REG_Y;
lblock->mExitRequiredRegs += CPU_REG_Y;
eblock->mEntryRequiredRegs += CPU_REG_Y;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
else if (!xother)
{
int linc = xinc;
if (mIns[sz - 3].mType == ASMIT_INC)
linc--;
else
linc++;
const InterInstruction* iins(mIns[sz - 3].mIns);
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
xinc = 0;
for (int i = 0; i + 3 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
else if (mIns[i].mType == ASMIT_LDX)
{
if (xinc > 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
else if (xinc < 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
xinc = 0;
}
else
{
lblock->mIns.Push(mIns[i]);
if (mIns[i].mType == ASMIT_INX)
xinc++;
else if (mIns[i].mType == ASMIT_DEX)
xinc--;
}
}
while (linc < 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
linc++;
}
while (linc > 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX, ASMIM_IMPLIED));
linc--;
}
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, limit));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_X;
lblock->mEntryRequiredRegs += CPU_REG_X;
lblock->mExitRequiredRegs += CPU_REG_X;
eblock->mEntryRequiredRegs += CPU_REG_X;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->CheckLive();
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
}
else if (mIns[sz - 1].mType == ASMIT_DEC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mBranch == ASMIT_BNE)
{
// check for usage of Y register
bool yother = false, yindex = false, xother = false, xindex = false;
int zreg = mIns[sz - 1].mAddress;
int yinc = 0, xinc = 0;
const InterInstruction* iins(mIns[sz - 1].mIns);
if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
yother = true;
if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
xother = true;
for (int i = 0; i < sz - 1; i++)
{
if (mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_INY)
yinc++;
else if (mIns[i].mType == ASMIT_DEY)
yinc--;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && yinc >= -1 && yinc <= 1)
{
yinc = 0;
yindex = true;
}
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
if (mIns[i].mType == ASMIT_TAX)
xother = true;
else if (mIns[i].mType == ASMIT_INX)
xinc++;
else if (mIns[i].mType == ASMIT_DEX)
xinc--;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && xinc >= -1 && xinc <= 1)
{
xinc = 0;
xindex = true;
}
else
xother = true;
}
else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X))
xother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
}
if (!yother)
{
int linc = yinc + 1;
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
yinc = 0;
for (int i = 0; i + 1 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType == ASMIT_LDY)
{
if (yinc > 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
else if (yinc < 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
yinc = 0;
}
else
{
lblock->mIns.Push(mIns[i]);
if (mIns[i].mType == ASMIT_INY)
yinc++;
else if (mIns[i].mType == ASMIT_DEY)
yinc--;
}
}
if (linc == 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, 0));
}
else
{
while (linc < 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
linc++;
}
while (linc > 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY, ASMIM_IMPLIED));
linc--;
}
}
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_Y;
lblock->mEntryRequiredRegs += CPU_REG_Y;
lblock->mExitRequiredRegs += CPU_REG_Y;
eblock->mEntryRequiredRegs += CPU_REG_Y;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
else if (!xother)
{
int linc = xinc + 1;
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
yinc = 0;
for (int i = 0; i + 1 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
else if (mIns[i].mType == ASMIT_LDX)
{
if (yinc > 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
else if (yinc < 0)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
yinc = 0;
}
else
{
lblock->mIns.Push(mIns[i]);
if (mIns[i].mType == ASMIT_INX)
yinc++;
else if (mIns[i].mType == ASMIT_DEX)
yinc--;
}
}
if (linc == 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, 0));
}
else
{
while (linc < 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
linc++;
}
while (linc > 0)
{
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX, ASMIM_IMPLIED));
linc--;
}
}
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_X;
lblock->mEntryRequiredRegs += CPU_REG_X;
lblock->mExitRequiredRegs += CPU_REG_X;
eblock->mEntryRequiredRegs += CPU_REG_X;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
}
else if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && (mIns[sz - 1].mMode == ASMIM_ZERO_PAGE || mIns[sz - 1].mMode == ASMIM_ABSOLUTE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
mBranch == ASMIT_BCC)
{
// check for usage of Y register
bool yother = false, yindex = false, lchanged = false, xother = false, xindex = false;
NativeCodeInstruction lins = mIns[sz - 1];
const InterInstruction* iins(mIns[sz - 1].mIns);
int zreg = mIns[sz - 3].mAddress;
if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
xother = true;
if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
yother = true;
for (int i = 0; i < sz - 3; i++)
{
if (mIns[i].SameEffectiveAddress(lins) && mIns[i].ChangesAddress())
lchanged = true;
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
if (mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX || mIns[i].mType == ASMIT_TAX)
xother = true;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xindex = true;
else
xother = true;
}
else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
xother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
}
if (!yother && !lchanged)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, lins));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_Y;
lblock->mEntryRequiredRegs += CPU_REG_Y;
lblock->mExitRequiredRegs += CPU_REG_Y;
eblock->mEntryRequiredRegs += CPU_REG_Y;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
else if (!xother && !lchanged)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
mIns[i].mLive |= LIVE_CPU_REG_X;
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDX)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, lins));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.SetSize(0);
mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
lblock->mEntryRequiredRegs = mEntryRequiredRegs;
lblock->mExitRequiredRegs = mExitRequiredRegs;
eblock->mEntryRequiredRegs = mExitRequiredRegs;
eblock->mExitRequiredRegs = mExitRequiredRegs;
mExitRequiredRegs = mEntryRequiredRegs;
mExitRequiredRegs += CPU_REG_X;
lblock->mEntryRequiredRegs += CPU_REG_X;
lblock->mExitRequiredRegs += CPU_REG_X;
eblock->mEntryRequiredRegs += CPU_REG_X;
lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
lblock->CheckLive();
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
}
}
}
#if 1
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
if (!changed)
{
CheckLive();
changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr, full);
CheckLive();
}
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
#endif
}
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
CheckLive();
if (mTrueJump && mTrueJump->OptimizeSimpleLoop(proc, full))
changed = true;
if (mFalseJump && mFalseJump->OptimizeSimpleLoop(proc, full))
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
return changed;
}
return false;
}
bool NativeCodeBasicBlock::OptimizeSingleEntryLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prev, NativeCodeBasicBlock* tail, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
bool changed = false;
for (int bi = 0; bi < lblocks.Size(); bi++)
{
NativeCodeBasicBlock* block = lblocks[bi];
for (int i = 0; i + 1 < block->mIns.Size(); i++)
{
if (block->mIns[i].mType == ASMIT_LDA && (block->mIns[i].mMode == ASMIM_IMMEDIATE || block->mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
block->mIns[i + 1].mType == ASMIT_STA && block->mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int addr = block->mIns[i + 1].mAddress;
if (!mEntryRequiredRegs[addr] && !tail->mEntryRequiredRegs[addr] && !ReferencesZeroPage(addr) &&
!block->ReferencesZeroPage(addr, 0, i) && !block->ChangesZeroPage(addr, i + 2) && !prev->mExitRequiredRegs[CPU_REG_Z])
{
int j = 0;
while (j < lblocks.Size() && (j == bi || !lblocks[j]->ReferencesZeroPage(addr)))
j++;
if (j == lblocks.Size())
{
bool ok = true;
if (!prev->mExitRequiredRegs[CPU_REG_A])
{
prev->mIns.Push(block->mIns[i]);
prev->mIns.Push(block->mIns[i + 1]);
}
else if (!prev->mExitRequiredRegs[CPU_REG_X])
{
prev->mIns.Push(NativeCodeInstruction(block->mIns[i].mIns, ASMIT_LDX, block->mIns[i]));
prev->mIns.Push(NativeCodeInstruction(block->mIns[i + 1].mIns, ASMIT_STX, block->mIns[i + 1]));
}
else if (!prev->mExitRequiredRegs[CPU_REG_Y])
{
prev->mIns.Push(NativeCodeInstruction(block->mIns[i].mIns, ASMIT_LDY, block->mIns[i]));
prev->mIns.Push(NativeCodeInstruction(block->mIns[i + 1].mIns, ASMIT_STY, block->mIns[i + 1]));
}
else
ok = false;
if (ok)
{
block->mIns.Remove(i + 1);
changed = true;
prev->mExitRequiredRegs += addr;
mEntryRequiredRegs += addr;
mExitRequiredRegs += addr;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += addr;
lblocks[i]->mExitRequiredRegs += addr;
}
}
}
}
}
}
}
if (!changed)
{
if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (!ChangesAccu(1))
{
int i = 0;
while (i < lblocks.Size() && !lblocks[i]->ChangesAccu())
i++;
if (i == lblocks.Size())
{
prev->mIns.Push(mIns[0]);
mIns.Remove(0);
prev->mExitRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mExitRequiredRegs += CPU_REG_A;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += CPU_REG_A;
lblocks[i]->mExitRequiredRegs += CPU_REG_A;
}
changed = true;
}
}
}
if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (!ChangesYReg(1))
{
int i = 0;
while (i < lblocks.Size() && !lblocks[i]->ChangesYReg())
i++;
if (i == lblocks.Size())
{
prev->mIns.Push(mIns[0]);
mIns.Remove(0);
prev->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
}
changed = true;
}
}
}
int tz = tail->mIns.Size();
if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE &&
tz > 0 && (tail->mIns[tz - 1].mType == ASMIT_INC || tail->mIns[tz - 1].mType == ASMIT_DEC) && tail->mIns[tz - 1].SameEffectiveAddress(mIns[0]))
{
if (!ChangesYReg(1) && !ReferencesZeroPage(mIns[0].mAddress, 1) &&
!tail->ChangesYReg() && !tail->ReferencesZeroPage(mIns[0].mAddress, 0, tz - 1))
{
int i = 0;
while (i < lblocks.Size() && (lblocks[i] == tail || (!lblocks[i]->ChangesYReg() && !lblocks[i]->ReferencesZeroPage(mIns[0].mAddress))))
i++;
if (i == lblocks.Size())
{
if (lblocks.Contains(tail->mTrueJump))
{
tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
}
else
{
tail->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
tail->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
}
if (tail->mIns[tz - 1].mType == ASMIT_INC)
tail->mIns[tz - 1].mType = ASMIT_INY;
else
tail->mIns[tz - 1].mType = ASMIT_DEY;
tail->mIns[tz - 1].mMode = ASMIM_IMPLIED;
prev->mIns.Push(mIns[0]);
mIns.Remove(0);
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
prev->mExitRequiredRegs += CPU_REG_Y;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
}
changed = true;
}
}
}
if (!changed)
{
if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
{
int k = 1;
while (k < mIns.Size() && !(mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == mIns[0].mAddress))
k++;
if (k < mIns.Size() && !ChangesYReg(1) &&
!ReferencesZeroPage(mIns[0].mAddress, 1, k) &&
!ReferencesZeroPage(mIns[0].mAddress, k + 1) &&
(mIns[k].mType == ASMIT_INC || mIns[k].mType == ASMIT_DEC))
{
int i = 0;
while (i < lblocks.Size() && (lblocks[i] == this || (!lblocks[i]->ChangesYReg() && !lblocks[i]->ReferencesZeroPage(mIns[0].mAddress))))
i++;
if (i == lblocks.Size())
{
AsmInsType it, nit;
if (mIns[k].mType == ASMIT_INC)
{
it = ASMIT_INY;
nit = ASMIT_DEY;
}
else
{
it = ASMIT_DEY;
nit = ASMIT_INY;
}
if (lblocks.Contains(tail->mTrueJump))
{
tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
tail->mFalseJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
}
else
{
tail->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
tail->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
tail->mTrueJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
}
prev->mIns.Push(mIns[0]);
prev->mIns.Push(NativeCodeInstruction(mIns[0].mIns, nit));
mIns[0].mType = it;
mIns[0].mMode = ASMIM_IMPLIED;
mIns.Remove(k);
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
prev->mExitRequiredRegs += CPU_REG_Y;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
}
changed = true;
}
}
}
}
}
if (mEntryBlocks.Size() == 2)
{
if (tail->mExitRequiredRegs.Size() && !tail->mExitRequiredRegs[CPU_REG_X] && !mEntryRequiredRegs[CPU_REG_X])
{
int ei = tail->mIns.Size() - 1;
while (ei >= 0 && !tail->mIns[ei].ReferencesXReg())
ei--;
if (ei >= 0 && tail->mIns[ei].mType == ASMIT_STX && tail->mIns[ei].mMode == ASMIM_ZERO_PAGE)
{
int si = 0;
while (si < mIns.Size() && !mIns[si].ChangesXReg())
si++;
if (si < mIns.Size() && mIns[si].mType == ASMIT_LDX && mIns[si].SameEffectiveAddress(tail->mIns[ei]))
{
prev->mIns.Push(mIns[si]);
mIns.Remove(si);
tail->mIns.Remove(ei);
for (int i = 0; i < si; i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
for (int i = ei; i < tail->mIns.Size(); i++)
tail->mIns[i].mLive |= LIVE_CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
tail->mExitRequiredRegs += CPU_REG_X;
changed = true;
}
}
}
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeInnerLoop(NativeCodeProcedure* proc, NativeCodeBasicBlock* head, NativeCodeBasicBlock* tail, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
bool simple = true;
for (int j = 0; j < lblocks.Size(); j++)
{
NativeCodeBasicBlock* block = lblocks[j];
for (int i = 0; i < block->mIns.Size(); i++)
{
if (block->mIns[i].mType == ASMIT_JSR)
simple = false;
}
block->CheckLive();
}
int sz = tail->mIns.Size();
if (simple && sz >= 3)
{
if (tail->mIns[sz - 3].mType == ASMIT_INC && tail->mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
tail->mIns[sz - 2].mType == ASMIT_LDA && tail->mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && tail->mIns[sz - 3].mAddress == tail->mIns[sz - 2].mAddress &&
tail->mIns[sz - 1].mType == ASMIT_CMP && tail->mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(tail->mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
tail->mBranch == ASMIT_BCC && tail->mTrueJump == head)
{
// check for usage of Y register
bool yother = false, yindex = false, xother = false, xindex = false;
int zreg = tail->mIns[sz - 3].mAddress;
int limit = tail->mIns[sz - 1].mAddress;
for (int j = 0; j < lblocks.Size(); j++)
{
NativeCodeBasicBlock* block = lblocks[j];
int bz = block == tail ? block->mIns.Size() - 3 : block->mIns.Size();
for (int i = 0; i < bz; i++)
{
if (block->mIns[i].mType == ASMIT_INY || block->mIns[i].mType == ASMIT_DEY || block->mIns[i].mType == ASMIT_TAY)
yother = true;
else if (block->mIns[i].mType == ASMIT_LDY)
{
if (block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (!yindex && (block->mIns[i].mType == ASMIT_STY || block->mIns[i].mType == ASMIT_TYA || block->mIns[i].mMode == ASMIM_ABSOLUTE_Y || block->mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (block->mIns[i].mType == ASMIT_LDX && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg && xother && !yother && !(block->mIns[i].mLive & LIVE_CPU_REG_Y))
{
if (i + 1 < bz && !(block->mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && block->mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(block->mIns[i + 1].mType, ASMIM_ABSOLUTE_Y))
{
block->mIns[i].mType = ASMIT_LDY; block->mIns[i].mLive |= LIVE_CPU_REG_Y;
block->mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
yindex = true;
}
else
yother = true;
}
else if (block->mIns[i].mType != ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
yother = true;
if (block->mIns[i].mType == ASMIT_INX || block->mIns[i].mType == ASMIT_DEX || block->mIns[i].mType == ASMIT_TAX)
xother = true;
else if (block->mIns[i].mType == ASMIT_LDX)
{
if (block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
xindex = true;
else
xother = true;
}
else if (!xindex && (block->mIns[i].mType == ASMIT_STX || block->mIns[i].mType == ASMIT_TXA || block->mIns[i].mMode == ASMIM_ABSOLUTE_X || block->mIns[i].mMode == ASMIM_INDIRECT_X))
xother = true;
else if (block->mIns[i].mType != ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
xother = true;
}
}
#if 1
if (!yother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
const InterInstruction* iins(tail->mIns[sz - 1].mIns);
tail->mIns.Remove(sz - 3);
tail->mIns.Remove(sz - 3);
tail->mIns.Remove(sz - 3);
for (int j = 0; j < lblocks.Size(); j++)
{
NativeCodeBasicBlock* block = lblocks[j];
int bz = block->mIns.Size();
if (block == head)
{
for (int i = 0; i < bz; i++)
{
if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
else if (block->mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(block->mIns[i]);
}
for (int i = 0; i < lblock->mIns.Size(); i++)
lblock->mIns[i].mLive |= LIVE_CPU_REG_Y;
}
else
{
for (int i = 0; i < bz; i++)
{
if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
{
block->mIns[i].mType = ASMIT_TYA;
block->mIns[i].mMode = ASMIM_IMPLIED;
}
else if (block->mIns[i].mType == ASMIT_LDY)
{
block->mIns[i].mType = ASMIT_NOP; block->mIns[i].mMode = ASMIM_IMPLIED;
}
block->mIns[i].mLive |= LIVE_CPU_REG_Y;
}
}
block->mEntryRequiredRegs += CPU_REG_Y;
block->mExitRequiredRegs += CPU_REG_Y;
}
tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, limit));
lblock->mBranch = head->mBranch;
lblock->mTrueJump = head->mTrueJump;
lblock->mFalseJump = head->mFalseJump;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = tail->mFalseJump;
eblock->mFalseJump = nullptr;
tail->mTrueJump = lblock;
tail->mFalseJump = eblock;
head->mIns.SetSize(0);
head->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
head->mBranch = ASMIT_JMP;
head->mTrueJump = lblock;
head->mFalseJump = nullptr;
tail->mEntryRequiredRegs += CPU_REG_Y;
tail->mExitRequiredRegs += CPU_REG_Y;
head->mExitRequiredRegs += CPU_REG_Y;
eblock->mEntryRequiredRegs = tail->mExitRequiredRegs;
eblock->mEntryRequiredRegs += CPU_REG_Y;
lblock->CheckLive();
return true;
}
else
#endif
if (!xother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
const InterInstruction* iins(tail->mIns[sz - 1].mIns);
tail->mIns.Remove(sz - 3);
tail->mIns.Remove(sz - 3);
tail->mIns.Remove(sz - 3);
for (int j = 0; j < lblocks.Size(); j++)
{
NativeCodeBasicBlock* block = lblocks[j];
int bz = block->mIns.Size();
if (block == head)
{
for (int i = 0; i < bz; i++)
{
if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
else if (block->mIns[i].mType != ASMIT_LDX)
lblock->mIns.Push(block->mIns[i]);
}
for (int i = 0; i < lblock->mIns.Size(); i++)
lblock->mIns[i].mLive |= LIVE_CPU_REG_X;
}
else
{
for (int i = 0; i < bz; i++)
{
if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
{
block->mIns[i].mType = ASMIT_TXA;
block->mIns[i].mMode = ASMIM_IMPLIED;
}
else if (block->mIns[i].mType == ASMIT_LDX)
{
block->mIns[i].mType = ASMIT_NOP; block->mIns[i].mMode = ASMIM_IMPLIED;
}
block->mIns[i].mLive |= LIVE_CPU_REG_X;
}
}
block->mEntryRequiredRegs += CPU_REG_X;
block->mExitRequiredRegs += CPU_REG_X;
}
tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, limit));
lblock->mBranch = head->mBranch;
lblock->mTrueJump = head->mTrueJump;
lblock->mFalseJump = head->mFalseJump;
eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = tail->mFalseJump;
eblock->mFalseJump = nullptr;
tail->mTrueJump = lblock;
tail->mFalseJump = eblock;
head->mIns.SetSize(0);
head->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
head->mBranch = ASMIT_JMP;
head->mTrueJump = lblock;
head->mFalseJump = nullptr;
tail->mEntryRequiredRegs += CPU_REG_X;
tail->mExitRequiredRegs += CPU_REG_X;
head->mExitRequiredRegs += CPU_REG_X;
tail->CheckLive();
head->CheckLive();
eblock->CheckLive();
lblock->CheckLive();
return true;
}
}
}
return false;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::CollectInnerLoop(NativeCodeBasicBlock* head, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
if (mLoopHeadBlock != head)
{
mLoopHeadBlock = head;
lblocks.Push(this);
if (mTrueJump != head && mFalseJump != head)
{
if (mFalseJump && mTrueJump == this && mEntryBlocks.Size() == 2 && mIns.Size() == 1 && (mIns[0].mType == ASMIT_BIT || mIns[0].mType == ASMIT_LDA && !(mIns[0].mLive & LIVE_CPU_REG_A)))
{
mLoopTailBlock = mFalseJump->CollectInnerLoop(head, lblocks);
}
else
{
if (mTrueJump)
mLoopTailBlock = mTrueJump->CollectInnerLoop(head, lblocks);
if (mLoopTailBlock && mFalseJump)
{
NativeCodeBasicBlock* tail = mFalseJump->CollectInnerLoop(head, lblocks);
if (tail != mLoopTailBlock)
mLoopTailBlock = nullptr;
}
}
}
else
mLoopTailBlock = this;
}
return mLoopTailBlock;
}
bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
CheckLive();
if (mLoopHead)
{
ExpandingArray<NativeCodeBasicBlock*> lblocks;
NativeCodeBasicBlock* tail = CollectInnerLoop(this, lblocks);
if (tail && this != tail)
changed = OptimizeInnerLoop(proc, this, tail, lblocks);
}
CheckLive();
mVisited = true;
if (mTrueJump && mTrueJump->OptimizeInnerLoops(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeInnerLoops(proc))
changed = true;
}
return changed;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleEntry(NativeCodeProcedure* proc, NativeCodeBasicBlock* block)
{
if (block->mNumEntries > 1)
{
NativeCodeBasicBlock* nblock = proc->AllocateBlock();
nblock->mTrueJump = block;
nblock->mEntryRequiredRegs = block->mEntryRequiredRegs;
nblock->mExitRequiredRegs = block->mEntryRequiredRegs;
int k = block->mEntryBlocks.IndexOf(this);
block->mEntryBlocks[k] = nblock;
nblock->mEntryBlocks.Push(this);
nblock->mNumEntries = 1;
return nblock;
}
else
return block;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleExit(NativeCodeProcedure* proc, NativeCodeBasicBlock* block)
{
if (block->mFalseJump)
{
NativeCodeBasicBlock* nblock = proc->AllocateBlock();
if (block->mFalseJump == this)
block->mFalseJump = nblock;
if (block->mTrueJump == this)
block->mTrueJump = nblock;
nblock->mTrueJump = this;
nblock->mEntryRequiredRegs = this->mEntryRequiredRegs;
nblock->mExitRequiredRegs = this->mExitRequiredRegs;
int k = mEntryBlocks.IndexOf(block);
mEntryBlocks[k] = nblock;
nblock->mEntryBlocks.Push(block);
nblock->mNumEntries = 1;
return nblock;
}
else
return block;
}
bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
if (mLoopHead)
{
ExpandingArray<NativeCodeBasicBlock*> lblocks;
proc->ResetPatched();
if (CollectSingleEntryGenericLoop(proc, lblocks))
{
int yreg = -1, xreg = -1, areg = -1;
int zyreg[NUM_REGS], zxreg[NUM_REGS], zareg[NUM_REGS];
for (int i = 0; i < NUM_REGS; i++)
{
zyreg[i] = 0;
zxreg[i] = 0;
zareg[i] = 0;
}
if (mEntryRequiredRegs[CPU_REG_Y])
yreg = -2;
if (mEntryRequiredRegs[CPU_REG_X])
xreg = -2;
if (mEntryRequiredRegs[CPU_REG_A])
areg = -2;
for (int i = 0; i < lblocks.Size(); i++)
{
NativeCodeBasicBlock* block = lblocks[i];
int yoffset = 0, xoffset = 0, aoffset = 0;
int yskew = 0, xskew = 0;
for (int j = 0; j < block->mIns.Size(); j++)
{
const NativeCodeInstruction& ins(block->mIns[j]);
switch (ins.mType)
{
case ASMIT_LDY:
if (ins.mMode == ASMIM_ZERO_PAGE && (yreg == -1 || yreg == ins.mAddress))
yreg = ins.mAddress;
else
yreg = -2;
if (ins.mMode == ASMIM_ZERO_PAGE)
{
zxreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
yoffset = 0;
yskew = 0;
zareg[CPU_REG_Y] = -1;
break;
case ASMIT_LDX:
if (ins.mMode == ASMIM_ZERO_PAGE && (xreg == -1 || xreg == ins.mAddress))
xreg = ins.mAddress;
else
xreg = -2;
if (ins.mMode == ASMIM_ZERO_PAGE)
{
zyreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
xoffset = 0;
xskew = 0;
zareg[CPU_REG_X] = -1;
break;
case ASMIT_STY:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
zxreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
break;
case ASMIT_STX:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
zyreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
break;
case ASMIT_INY:
yoffset++;
zareg[CPU_REG_Y] = -1;
break;
case ASMIT_DEY:
yoffset--;
zareg[CPU_REG_Y] = -1;
break;
case ASMIT_INX:
xoffset++;
zareg[CPU_REG_X] = -1;
break;
case ASMIT_DEX:
xoffset--;
zareg[CPU_REG_X] = -1;
break;
case ASMIT_INC:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (zxreg[ins.mAddress] >= 0)
{
if (ins.mLive & LIVE_CPU_REG_X)
zxreg[ins.mAddress] = -1;
else
{
zxreg[ins.mAddress] += 3;
xskew++;
}
}
if (zyreg[ins.mAddress] >= 0)
{
if (ins.mLive & LIVE_CPU_REG_Y)
zyreg[ins.mAddress] = -1;
else
{
zyreg[ins.mAddress] += 3;
yskew++;
}
}
zareg[ins.mAddress] = -1;
}
break;
case ASMIT_DEC:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (zxreg[ins.mAddress] >= 0)
{
if (ins.mLive & LIVE_CPU_REG_X)
zxreg[ins.mAddress] = -1;
else
{
zxreg[ins.mAddress] += 3;
xskew--;
}
}
if (zyreg[ins.mAddress] >= 0)
{
if (ins.mLive & LIVE_CPU_REG_Y)
zyreg[ins.mAddress] = -1;
else
{
zyreg[ins.mAddress] += 3;
yskew--;
}
}
zareg[ins.mAddress] = -1;
}
break;
#if 0
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ROL:
case ASMIT_ROR:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (zareg[ins.mAddress] >= 0)
{
if (ins.mLive & LIVE_CPU_REG_A)
zareg[ins.mAddress] = -1;
else
zareg[ins.mAddress] += 3;
}
zxreg[ins.mAddress] = -1;
zyreg[ins.mAddress] = -1;
}
break;
#endif
case ASMIT_LDA:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if ((areg == -1 || areg == ins.mAddress) && !(ins.mLive & LIVE_CPU_REG_Z))
areg = ins.mAddress;
else
areg = -2;
if (ins.mAddress == yreg && yoffset != 0)
yreg = -2;
if (ins.mAddress == xreg && xoffset != 0)
xreg = -2;
if (zxreg[ins.mAddress] >= 0)
zxreg[ins.mAddress]++;
if (zyreg[ins.mAddress] >= 0)
zyreg[ins.mAddress]++;
}
else
areg = -2;
break;
case ASMIT_STA:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
if (ins.mAddress == yreg && (yoffset != 0 || (ins.mLive & LIVE_CPU_REG_Y)))
yreg = -2;
if (ins.mAddress == xreg && (xoffset != 0 || (ins.mLive & LIVE_CPU_REG_X)))
xreg = -2;
if (zxreg[ins.mAddress] >= 0)
zxreg[ins.mAddress]++;
if (zyreg[ins.mAddress] >= 0)
zyreg[ins.mAddress]++;
}
break;
case ASMIT_TYA:
if (yoffset)
yreg = -2;
else if ((areg == -1 || areg == CPU_REG_Y) && !(ins.mLive & LIVE_CPU_REG_Z))
areg = CPU_REG_Y;
else
areg = -2;
break;
case ASMIT_TXA:
if (xoffset)
xreg = -2;
else if ((areg == -1 || areg == CPU_REG_X) && !(ins.mLive & LIVE_CPU_REG_Z))
areg = CPU_REG_X;
else
areg = -2;
break;
case ASMIT_TAY:
yreg = -2;
zareg[CPU_REG_Y] = -1;
break;
case ASMIT_TAX:
xreg = -2;
zareg[CPU_REG_X] = -1;
break;
case ASMIT_JSR:
yreg = -2;
xreg = -2;
areg = -2;
zareg[CPU_REG_X] = -1;
zareg[CPU_REG_Y] = -1;
break;
case ASMIT_CMP:
if (ins.mMode == ASMIM_INDIRECT_Y && yoffset != 0 && yreg >= 0)
{
yreg = -2;
}
else if (ins.mMode == ASMIM_ZERO_PAGE)
{
zxreg[ins.mAddress] = -1;
zyreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
break;
default:
if (ins.mMode == ASMIM_ZERO_PAGE)
{
zxreg[ins.mAddress] = -1;
zyreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
}
if (ins.ChangesAccu())
areg = -2;
}
if (xreg >= 0 && ins.mMode == ASMIM_ABSOLUTE_X && xskew != xoffset)
zxreg[xreg] = -1;
if (yreg >= 0 && (ins.mMode == ASMIM_ABSOLUTE_Y || ins.mMode == ASMIM_INDIRECT_Y) && yskew != yoffset)
zyreg[yreg] = -1;
if (!(ins.mLive & LIVE_CPU_REG_Y))
yoffset = 0;
if (!(ins.mLive & LIVE_CPU_REG_X))
xoffset = 0;
if (!(ins.mLive & LIVE_CPU_REG_A))
aoffset = 0;
if (ins.mMode == ASMIM_INDIRECT_Y)
{
zxreg[ins.mAddress] = -1;
zyreg[ins.mAddress] = -1;
zareg[ins.mAddress] = -1;
zxreg[ins.mAddress + 1] = -1;
zyreg[ins.mAddress + 1] = -1;
zareg[ins.mAddress + 1] = -1;
}
}
#if 1
if (yoffset && block->mExitRequiredRegs[CPU_REG_Y])
yreg = -2;
if (xoffset && block->mExitRequiredRegs[CPU_REG_X])
xreg = -2;
if (aoffset && block->mExitRequiredRegs[CPU_REG_A])
areg = -2;
#endif
}
if (areg >= 0)
{
if (zareg[areg] < 0)
areg = -2;
else
{
zxreg[areg] = -1;
zyreg[areg] = -1;
}
}
if (xreg != -2)
{
if (xreg == -1)
{
int nx = 0;
for (int i = 0; i < 256; i++)
{
if (i != yreg && zxreg[i] > nx)
{
nx = zxreg[i];
xreg = i;
}
}
}
else if (zxreg[xreg] < 0)
xreg = -1;
}
if (yreg != -2)
{
if (yreg == -1)
{
int nx = 0;
for (int i = 0; i < 256; i++)
{
if (i != xreg && zyreg[i] > nx)
{
nx = zyreg[i];
yreg = i;
}
}
}
else if (zyreg[yreg] < 0)
yreg = -1;
}
if (yreg >= 0 || xreg >= 0 || areg >= 0)
{
ExpandingArray<NativeCodeBasicBlock*> entries;
ExpandingArray<NativeCodeBasicBlock*> exits;
for (int i = 0; i < lblocks.Size(); i++)
{
NativeCodeBasicBlock* block = lblocks[i];
if (yreg >= 0)
{
block->mEntryRequiredRegs += CPU_REG_Y;
block->mExitRequiredRegs += CPU_REG_Y;
}
if (xreg >= 0)
{
block->mEntryRequiredRegs += CPU_REG_X;
block->mExitRequiredRegs += CPU_REG_X;
}
if (areg >= 0)
{
block->mEntryRequiredRegs += CPU_REG_A;
block->mExitRequiredRegs += CPU_REG_A;
}
for (int j = 0; j < block->mEntryBlocks.Size(); j++)
{
if (!lblocks.Contains(block->mEntryBlocks[j]))
{
block->mEntryBlocks[j] = block->BuildSingleExit(proc, block->mEntryBlocks[j]);
if (areg >= 0 && mEntryRequiredRegs[areg])
{
if (areg == CPU_REG_X)
block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_TXA));
else if (areg == CPU_REG_Y)
block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_TYA));
else
block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_A;
}
if (yreg >= 0 && mEntryRequiredRegs[yreg])
{
block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDY, ASMIM_ZERO_PAGE, yreg));
block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Y;
}
if (xreg >= 0 && mEntryRequiredRegs[xreg])
{
block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDX, ASMIM_ZERO_PAGE, xreg));
block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_X;
}
}
}
int yoffset = 0, xoffset = 0, xskew = 0, yskew = 0;
for (int j = 0; j < block->mIns.Size(); j++)
{
NativeCodeInstruction& ins(block->mIns[j]);
switch (ins.mType)
{
case ASMIT_LDY:
case ASMIT_STY:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
yoffset = 0;
yskew = 0;
}
break;
case ASMIT_LDX:
case ASMIT_STX:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
xoffset = 0;
xskew = 0;
}
break;
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ROL:
case ASMIT_ROR:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
ins.mMode = ASMIM_IMPLIED;
break;
case ASMIT_INC:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
ins.mType = ASMIT_INY;
ins.mMode = ASMIM_IMPLIED;
yskew += 1;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
{
ins.mType = ASMIT_INX;
ins.mMode = ASMIM_IMPLIED;
xskew += 1;
}
break;
case ASMIT_DEC:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
yskew -= 1;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
{
ins.mType = ASMIT_DEX;
ins.mMode = ASMIM_IMPLIED;
xskew -= 1;
}
break;
case ASMIT_LDA:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
ins.mType = ASMIT_TYA;
ins.mMode = ASMIM_IMPLIED;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
{
ins.mType = ASMIT_TXA;
ins.mMode = ASMIM_IMPLIED;
}
break;
case ASMIT_STA:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
{
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
{
ins.mType = ASMIT_TAY;
ins.mMode = ASMIM_IMPLIED;
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
{
ins.mType = ASMIT_TAX;
ins.mMode = ASMIM_IMPLIED;
}
break;
case ASMIT_INY:
yoffset++;
break;
case ASMIT_DEY:
yoffset--;
break;
case ASMIT_INX:
xoffset++;
break;
case ASMIT_DEX:
xoffset--;
break;
case ASMIT_TXA:
if (areg == CPU_REG_X)
ins.mType = ASMIT_NOP;
break;
case ASMIT_TYA:
if (areg == CPU_REG_Y)
ins.mType = ASMIT_NOP;
break;
}
if (yoffset && yreg >= 0 && !(ins.mLive & LIVE_CPU_REG_Y))
{
while (yoffset > 0)
{
j++;
block->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_DEY));
yoffset--;
}
while (yoffset < 0)
{
j++;
block->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_INY));
yoffset++;
}
if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag())
{
ins.mLive |= LIVE_CPU_REG_A;
block->mIns.Push(NativeCodeInstruction(ins.mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
}
}
if (xoffset && xreg >= 0 && !(ins.mLive & LIVE_CPU_REG_X))
{
while (xoffset > 0)
{
j++;
block->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_DEX));
xoffset--;
}
while (xoffset < 0)
{
j++;
block->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_INX));
xoffset++;
}
if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag())
{
ins.mLive |= LIVE_CPU_REG_A;
block->mIns.Push(NativeCodeInstruction(ins.mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
}
}
if (yreg >= 0)
ins.mLive |= LIVE_CPU_REG_Y;
if (xreg >= 0)
ins.mLive |= LIVE_CPU_REG_X;
if (areg >= 0)
ins.mLive |= LIVE_CPU_REG_A;
}
if (block->mTrueJump && !lblocks.Contains(block->mTrueJump))
{
block->mTrueJump = block->BuildSingleEntry(proc, block->mTrueJump);
if (areg >= 0 && block->mTrueJump->mEntryRequiredRegs[areg])
{
if (areg < 256)
block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg));
block->mExitRequiredRegs += CPU_REG_A;
block->mTrueJump->mEntryRequiredRegs += CPU_REG_A;
}
if (yreg >= 0 && block->mTrueJump->mEntryRequiredRegs[yreg])
{
block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
block->mExitRequiredRegs += CPU_REG_Y;
block->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
}
if (xreg >= 0 && block->mTrueJump->mEntryRequiredRegs[xreg])
{
block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg));
block->mExitRequiredRegs += CPU_REG_X;
block->mTrueJump->mEntryRequiredRegs += CPU_REG_X;
}
}
if (block->mFalseJump && !lblocks.Contains(block->mFalseJump))
{
block->mFalseJump = block->BuildSingleEntry(proc, block->mFalseJump);
if (areg >= 0 && block->mFalseJump->mEntryRequiredRegs[areg])
{
if (areg < 256)
block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg));
block->mExitRequiredRegs += CPU_REG_A;
block->mFalseJump->mEntryRequiredRegs += CPU_REG_A;
}
if (yreg >= 0 && block->mFalseJump->mEntryRequiredRegs[yreg])
{
block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
block->mExitRequiredRegs += CPU_REG_Y;
block->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
}
if (xreg >= 0 && block->mFalseJump->mEntryRequiredRegs[xreg])
{
block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg));
block->mExitRequiredRegs += CPU_REG_X;
block->mFalseJump->mEntryRequiredRegs += CPU_REG_X;
}
}
block->CheckLive();
}
CheckLive();
changed = true;
}
}
}
mVisited = true;
if (mTrueJump && mTrueJump->OptimizeGenericLoop(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeGenericLoop(proc))
changed = true;
}
return changed;
}
void NativeCodeBasicBlock::CollectReachable(ExpandingArray<NativeCodeBasicBlock*>& lblock)
{
if (!mVisited && !mPatched)
{
lblock.Push(this);
mPatched = true;
if (mTrueJump) mTrueJump->CollectReachable(lblock);
if (mFalseJump) mFalseJump->CollectReachable(lblock);
}
}
bool NativeCodeBasicBlock::CollectGenericLoop(NativeCodeProcedure* proc, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
ExpandingArray<NativeCodeBasicBlock*> rblocks;
proc->ResetPatched();
CollectReachable(rblocks);
proc->ResetPatched();
bool changed;
do
{
changed = false;
for (int i = 0; i < rblocks.Size(); i++)
{
NativeCodeBasicBlock* block(rblocks[i]);
if (!block->mPatched &&
(block->mTrueJump && (block->mTrueJump->mPatched || block->mTrueJump == this) ||
block->mFalseJump && (block->mFalseJump->mPatched || block->mFalseJump == this)))
{
lblocks.Push(block);
block->mPatched = true;
changed = true;
}
}
} while (changed);
return lblocks.Size() > 0;
}
bool NativeCodeBasicBlock::CollectSingleEntryGenericLoop(NativeCodeProcedure* proc, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
if (CollectGenericLoop(proc, lblocks))
{
for (int i = 0; i < lblocks.Size(); i++)
{
NativeCodeBasicBlock* block = lblocks[i];
if (block != this)
{
for (int j = 0; j < block->mEntryBlocks.Size(); j++)
if (!lblocks.Contains(block->mEntryBlocks[j]))
return false;
}
}
return true;
}
else
return false;
}
bool NativeCodeBasicBlock::OptimizeFindLoop(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
if (mLoopHead && mNumEntries == 2)
{
if (mTrueJump && mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 1)
{
NativeCodeBasicBlock* succ = nullptr, * body = nullptr;
if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump == this)
{
succ = mTrueJump;
body = mFalseJump;
}
else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump == this)
{
succ = mFalseJump;
body = mTrueJump;
}
if (succ)
{
NativeCodeBasicBlock* pred = mEntryBlocks[0];
if (pred == body)
pred = mEntryBlocks[1];
if (!pred->mFalseJump)
{
if (mIns.Size() > 0 && body->mIns.Size() > 0)
{
int fsz = body->mIns.Size();
if (mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE &&
body->mIns[fsz - 1].mType == ASMIT_INC && body->mIns[fsz - 1].SameEffectiveAddress(mIns[0]))
{
int i = 1;
while (i < mIns.Size() && !mIns[i].ChangesYReg() && !mIns[i].ReferencesZeroPage(mIns[0].mAddress))
i++;
if (i == mIns.Size())
{
i = 0;
while (i + 1 < fsz && !body->mIns[i].ChangesYReg() && !body->mIns[i].ReferencesZeroPage(mIns[0].mAddress))
i++;
if (i + 1 == fsz)
{
pred->mIns.Push(mIns[0]);
succ->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
body->mIns[fsz - 1].mType = ASMIT_INY;
body->mIns[fsz - 1].mMode = ASMIM_IMPLIED;
mIns.Remove(0);
body->mEntryRequiredRegs += CPU_REG_Y;
body->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
succ->mEntryRequiredRegs += CPU_REG_Y;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
for (int i = 0; i < fsz; i++)
body->mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
}
}
}
}
if (!ReferencesYReg() && body->mIns.Size() > 0 && body->mIns[0].mType == ASMIT_LDY && body->mIns[0].mMode == ASMIM_ZERO_PAGE && !mExitRequiredRegs[CPU_REG_Y])
{
int incdec = 0;
bool fail = false;
int addr = body->mIns[0].mAddress;
if (!ReferencesZeroPage(addr))
{
for (int i = 1; i < body->mIns.Size(); i++)
{
const NativeCodeInstruction& bins(body->mIns[i]);
if (bins.mMode == ASMIM_ZERO_PAGE && bins.mAddress == addr)
{
if (bins.mType == ASMIT_INC)
incdec++;
else if (bins.mType == ASMIT_DEC)
incdec--;
else
{
fail = true;
break;
}
}
else if (bins.ReferencesZeroPage(addr))
fail = true;
else if (bins.ChangesYReg())
fail = true;
}
if (!fail)
{
pred->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
body->mIns.Remove(0);
while (incdec > 0)
{
body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_INY));
incdec--;
}
while (incdec < 0)
{
body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_DEY));
incdec++;
}
for (int i = 0; i < body->mIns.Size(); i++)
{
if (body->mIns[i].mMode == ASMIM_ZERO_PAGE && body->mIns[i].mAddress == addr)
{
body->mIns[i].mType = ASMIT_NOP; body->mIns[i].mMode = ASMIM_IMPLIED;
}
}
succ->mIns.Insert(0, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
body->mEntryRequiredRegs += CPU_REG_Y;
body->mExitRequiredRegs += CPU_REG_Y;
mEntryRequiredRegs += CPU_REG_Y;
mExitRequiredRegs += CPU_REG_Y;
succ->mEntryRequiredRegs += CPU_REG_Y;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_Y;
for (int i = 0; i < body->mIns.Size(); i++)
body->mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
}
}
}
else if (!ReferencesXReg() && body->mIns.Size() > 0 && body->mIns[0].mType == ASMIT_LDX && body->mIns[0].mMode == ASMIM_ZERO_PAGE && !mExitRequiredRegs[CPU_REG_X])
{
int incdec = 0;
bool fail = false;
int addr = body->mIns[0].mAddress;
if (!ReferencesZeroPage(addr))
{
for (int i = 1; i < body->mIns.Size(); i++)
{
const NativeCodeInstruction& bins(body->mIns[i]);
if (bins.mMode == ASMIM_ZERO_PAGE && bins.mAddress == addr)
{
if (bins.mType == ASMIT_INC)
incdec++;
else if (bins.mType == ASMIT_DEC)
incdec--;
else
{
fail = true;
break;
}
}
else if (bins.ReferencesZeroPage(addr))
fail = true;
else if (bins.ChangesXReg())
fail = true;
}
if (!fail)
{
pred->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, addr));
body->mIns.Remove(0);
while (incdec > 0)
{
body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_INX));
incdec--;
}
while (incdec < 0)
{
body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_DEX));
incdec++;
}
for (int i = 0; i < body->mIns.Size(); i++)
{
if (body->mIns[i].mMode == ASMIM_ZERO_PAGE && body->mIns[i].mAddress == addr)
{
body->mIns[i].mType = ASMIT_NOP; body->mIns[i].mMode = ASMIM_IMPLIED;
}
}
succ->mIns.Insert(0, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr));
body->mEntryRequiredRegs += CPU_REG_X;
body->mExitRequiredRegs += CPU_REG_X;
mEntryRequiredRegs += CPU_REG_X;
mExitRequiredRegs += CPU_REG_X;
succ->mEntryRequiredRegs += CPU_REG_X;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].mLive |= LIVE_CPU_REG_X;
for (int i = 0; i < body->mIns.Size(); i++)
body->mIns[i].mLive |= LIVE_CPU_REG_X;
changed = true;
}
}
}
}
}
}
}
CheckLive();
if (mTrueJump && mTrueJump->OptimizeFindLoop(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeFindLoop(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeSelect(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
CheckLive();
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
if (mFalseJump && mIns.Size() > 0 && mIns.Last().ChangesAccuAndFlag() &&
mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump &&
mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ)
{
uint8 vt = mTrueJump->mIns[0].mAddress, vf = mFalseJump->mIns[0].mAddress;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
if (mBranch == ASMIT_BEQ)
{
char t = vt; vt = vf; vf = t;
}
mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_A;
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_CMP, ASMIM_IMMEDIATE, 1));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_AND, ASMIM_IMMEDIATE, vt ^ vf));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, vt));
changed = true;
mBranch = ASMIT_JMP;
}
}
CheckLive();
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
if (mTrueJump && mTrueJump->OptimizeSelect(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeSelect(proc))
changed = true;
}
return changed;
}
static bool CheckBlockCopySequence(const ExpandingArray<NativeCodeInstruction>& ins, int si, int n)
{
if (si + 2 * n <= ins.Size() &&
ins[si + 0].mType == ASMIT_LDA && (ins[si + 0].mMode == ASMIM_ZERO_PAGE || ins[si + 0].mMode == ASMIM_ABSOLUTE) &&
ins[si + 1].mType == ASMIT_STA && (ins[si + 1].mMode == ASMIM_ZERO_PAGE || ins[si + 1].mMode == ASMIM_ABSOLUTE))
{
for (int i = 1; i < n; i++)
{
if (!(ins[si + 2 * i + 0].mType == ASMIT_LDA && ins[si + 2 * i + 0].mMode == ins[si + 0].mMode && ins[si + 2 * i + 0].mAddress == ins[si + 0].mAddress + i &&
ins[si + 2 * i + 1].mType == ASMIT_STA && ins[si + 2 * i + 1].mMode == ins[si + 1].mMode && ins[si + 2 * i + 1].mAddress == ins[si + 1].mAddress + i))
return false;
}
if (ins[si + 2 * n - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
return false;
return true;
}
else
return false;
}
bool NativeCodeBasicBlock::BlockSizeCopyReduction(NativeCodeProcedure* proc, int& si, int& di)
{
if ((proc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
{
if (si + 1 < mIns.Size() &&
mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE))
{
int i = 1;
while (si + 2 * i + 1 < mIns.Size() &&
mIns[si + 2 * i + 0].mType == ASMIT_LDA && mIns[si + 2 * i + 0].mMode == mIns[si + 0].mMode && mIns[si + 2 * i + 0].mAddress == mIns[si + 0].mAddress + i &&
mIns[si + 2 * i + 1].mType == ASMIT_STA && mIns[si + 2 * i + 1].mMode == mIns[si + 1].mMode && mIns[si + 2 * i + 1].mAddress == mIns[si + 1].mAddress + i &&
!(mIns[si + 2 * i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
i++;
}
if (i > 2)
{
if (!(mIns[si + 0].mLive & LIVE_CPU_REG_X))
{
int k = 1;
while (CheckBlockCopySequence(mIns, si + 2 * k * i, i))
k++;
int sz = 3 + 4 * k;
for (int j = 0; j < k; j++)
{
NativeCodeInstruction lins = mIns[si + 2 * i * j + 0];
NativeCodeInstruction sins = mIns[si + 2 * i * j + 1];
if (lins.mMode == ASMIM_ZERO_PAGE || (lins.mLinkerObject && (lins.mLinkerObject->mFlags & LOBJF_ZEROPAGE)))
lins.mMode = ASMIM_ZERO_PAGE_X;
else
{
lins.mMode = ASMIM_ABSOLUTE_X;
sz++;
}
if (sins.mMode == ASMIM_ZERO_PAGE || (sins.mLinkerObject && (sins.mLinkerObject->mFlags & LOBJF_ZEROPAGE)))
sins.mMode = ASMIM_ZERO_PAGE_X;
else
{
sins.mMode = ASMIM_ABSOLUTE_X;
sz++;
}
if (j == 0)
mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_LDX, ASMIM_IMMEDIATE, i - 1);
mIns[di++] = lins;
mIns[di++] = sins;
}
mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_DEX, ASMIM_IMPLIED);
mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_BPL, ASMIM_RELATIVE, -sz);
si += 2 * i * k;
return true;
}
}
}
if (si + 2 < mIns.Size() &&
mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE))
{
int i = 1;
while (si + 3 * i + 2 < mIns.Size() &&
mIns[si + 3 * i + 0].mType == ASMIT_LDA && mIns[si + 3 * i + 0].mMode == mIns[si + 0].mMode && mIns[si + 3 * i + 0].mAddress == mIns[si + 0].mAddress + i &&
mIns[si + 3 * i + 1].mType == ASMIT_STA && mIns[si + 3 * i + 1].mMode == mIns[si + 1].mMode && mIns[si + 3 * i + 1].mAddress == mIns[si + 1].mAddress + i &&
mIns[si + 3 * i + 2].mType == ASMIT_STA && mIns[si + 3 * i + 2].mMode == mIns[si + 2].mMode && mIns[si + 3 * i + 2].mAddress == mIns[si + 2].mAddress + i &&
!(mIns[si + 3 * i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
i++;
}
if (i > 2)
{
if (!(mIns[si + 0].mLive & LIVE_CPU_REG_X))
{
NativeCodeInstruction lins = mIns[si + 0];
NativeCodeInstruction sins0 = mIns[si + 1];
NativeCodeInstruction sins1 = mIns[si + 2];
int sz = 9;
if (lins.mMode == ASMIM_ZERO_PAGE)
lins.mMode = ASMIM_ZERO_PAGE_X;
else
{
lins.mMode = ASMIM_ABSOLUTE_X;
sz++;
}
if (sins0.mMode == ASMIM_ZERO_PAGE)
sins0.mMode = ASMIM_ZERO_PAGE_X;
else
{
sins0.mMode = ASMIM_ABSOLUTE_X;
sz++;
}
if (sins1.mMode == ASMIM_ZERO_PAGE)
sins1.mMode = ASMIM_ZERO_PAGE_X;
else
{
sins1.mMode = ASMIM_ABSOLUTE_X;
sz++;
}
mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_LDX, ASMIM_IMMEDIATE, i - 1);
mIns[di++] = lins;
mIns[di++] = sins0;
mIns[di++] = sins1;
mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_DEX, ASMIM_IMPLIED);
mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_BPL, ASMIM_RELATIVE, -sz);
si += 3 * i;
return true;
}
}
}
}
return false;
}
// Size reduction violating various assumptions such as no branches in basic blocks
// must be last step before actual assembly
void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc, int xenter, int yenter)
{
if (!mVisited)
{
mVisited = true;
CheckLive();
int i = 0;
int j = 0;
if (mEntryBlocks.Size() == 1 &&
mEntryBlocks[0]->mIns.Size() > 0 && mIns.Size() > 0 &&
mIns[0].mType == ASMIT_CMP && mIns[0].mMode == ASMIM_IMMEDIATE &&
mEntryBlocks[0]->mIns.Last().mType == ASMIT_CMP && mEntryBlocks[0]->mIns.Last().mMode == ASMIM_IMMEDIATE &&
mIns[0].mAddress == mEntryBlocks[0]->mIns.Last().mAddress)
{
// Skip initial compare if same as last of entry block
i++;
}
while (i < mIns.Size())
{
if (mIns[i].mType == ASMIT_NOP)
{
i++;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
j += 3;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ZERO_PAGE; mIns[j + 3].mAddress = mIns[j + 0].mAddress;
j += 4;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_TAX &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_TXA; mIns[j + 0].mMode = ASMIM_IMPLIED;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
mIns[j + 3].mType = ASMIT_DEX; mIns[j + 3].mMode = ASMIM_IMPLIED;
j += 4;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 1].mLinkerObject;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;
if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 1].mAddress = 2;
else
mIns[j + 1].mAddress = 3;
mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
j += 3;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 1].mLinkerObject;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;
if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 1].mAddress = 2;
else
mIns[j + 1].mAddress = 3;
mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ABSOLUTE; mIns[j + 3].mAddress = mIns[j + 0].mAddress; mIns[j + 3].mLinkerObject = mIns[j + 0].mLinkerObject;
j += 4;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 0].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 0].mLinkerObject;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;
if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 1].mAddress = 2;
else
mIns[j + 1].mAddress = 3;
mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
j += 3;
i += 7;
}
else if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 0].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 0].mLinkerObject;
mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;
if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 1].mAddress = 2;
else
mIns[j + 1].mAddress = 3;
mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ABSOLUTE; mIns[j + 3].mAddress = mIns[j + 0].mAddress; mIns[j + 2].mLinkerObject = mIns[j + 0].mLinkerObject;
j += 4;
i += 7;
}
else if (i + 4 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 &&
mIns[i + 3].mType == ASMIT_CLC &&
mIns[i + 4].mType == ASMIT_ADC && !(mIns[i + 4].mLive & LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
{
mIns[j + 0] = mIns[i + 0]; mIns[j + 0].mType = ASMIT_SEC;
mIns[j + 1] = mIns[i + 1];
mIns[j + 2] = mIns[i + 4];
j += 3;
i += 5;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_INX &&
mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_INC;
j += 1;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_DEX &&
mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_DEC;
j += 1;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 2;
mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 2].mAddress;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE;
if (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 0].mAddress = 2;
else
mIns[j + 0].mAddress = 3;
mIns[j + 1] = mIns[i + 2];
mIns[j + 1].mType = ASMIT_INC;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 1;
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 2;
mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 2].mAddress;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE;
if (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
mIns[j + 0].mAddress = 2;
else
mIns[j + 0].mAddress = 3;
mIns[j + 1] = mIns[i + 2];
mIns[j + 1].mType = ASMIT_DEC;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 1;
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
j += 2;
i += 3;
}
#if 1
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_AND; mIns[j + 0].mMode = ASMIM_IMMEDIATE; mIns[j + 0].mAddress = 0x80;
mIns[j + 1].mType = ASMIT_BPL; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = 0xff;
j += 3;
i += 4;
}
#endif
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_INC;
j += 1;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_DEC;
j += 1;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_DEC;
j += 1;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_INC;
j += 1;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
j += 3;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_INX; mIns[j + 2].mMode = ASMIM_IMPLIED;
mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].CopyMode(mIns[i + 3]);
j += 4;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_DEX; mIns[j + 2].mMode = ASMIM_IMPLIED;
mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].CopyMode(mIns[i + 3]);
j += 4;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = nullptr;
mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 3].mAddress; mIns[j + 1].mLinkerObject = nullptr;
j += 2;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_DEC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = nullptr;
mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 3].mAddress; mIns[j + 1].mLinkerObject = nullptr;
j += 2;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].CopyMode(mIns[i + 0]);
mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].CopyMode(mIns[i + 0]);
j += 2;
i += 4;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[j + 0].mType = ASMIT_DEC; mIns[j + 0].CopyMode(mIns[i + 0]);
mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].CopyMode(mIns[i + 0]);
j += 2;
i += 4;
}
else if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[j] = mIns[i];
mIns[j].mType = ASMIT_LDY;
mIns[j].mLive |= LIVE_CPU_REG_Y;
j++;
i += 2;
}
else if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[j] = mIns[i];
mIns[j].mType = ASMIT_LDX;
mIns[j].mLive |= LIVE_CPU_REG_Y;
j++;
i += 2;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDY && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 1] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDX;
mIns[j + 0].mLive |= LIVE_CPU_REG_X;
mIns[j + 1].mType = ASMIT_LDY;
mIns[j + 1].mMode = ASMIM_ABSOLUTE_X;
mIns[j + 1].mLive |= LIVE_CPU_REG_Y;
j += 2;
i += 3;
}
else if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDX && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 1] = mIns[i + 1];
mIns[j + 0].mType = ASMIT_LDY;
mIns[j + 0].mLive |= LIVE_CPU_REG_Y;
mIns[j + 1].mType = ASMIT_LDX;
mIns[j + 1].mMode = ASMIM_ABSOLUTE_Y;
mIns[j + 1].mLive |= LIVE_CPU_REG_X;
j += 2;
i += 3;
}
else if (i + 5 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_EOR && mIns[i + 5].mMode == ASMIM_IMMEDIATE)
{
char veq = mIns[i + 4].mAddress ^ mIns[i + 5].mAddress, vne = mIns[i + 5].mAddress;
mIns[j + 0] = mIns[i + 0];
mIns[j + 1].mType = ASMIT_BEQ; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = veq != 0 ? 4 : 2;
mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = vne; mIns[j + 2].mFlags = 0;
j += 3;
if (veq != 0)
{
if (vne)
mIns[j + 0].mType = ASMIT_BNE;
else
mIns[j + 0].mType = ASMIT_BEQ;
mIns[j + 0].mMode = ASMIM_RELATIVE;
mIns[j + 0].mAddress = 2;
mIns[j + 1].mType = ASMIT_LDA; mIns[j + 1].mMode = ASMIM_IMMEDIATE; mIns[j + 1].mAddress = veq; mIns[j + 1].mFlags = 0;
j += 2;
}
i += 6;
}
else if (i + 3 < mIns.Size() &&
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED)
{
mIns[j + 0] = mIns[i + 0];
mIns[j + 1].mType = ASMIT_BEQ; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = 1;
j += 3;
i += 4;
}
#if 1
else if (i + 3 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC)
{
mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_SEC);
mIns[j + 1] = mIns[i + 3];
j += 2;
i += 4;
}
else if (i + 4 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_SBC &&
mIns[i + 3].mType == ASMIT_SEC &&
mIns[i + 4].mType == ASMIT_SBC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01)
{
mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_CLC);
j += 3;
i += 5;
}
#endif
else if (i + 1 < mIns.Size() &&
mIns[i + 0].ChangesZFlag() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[j++] = mIns[i++];
i++;
}
else if (BlockSizeCopyReduction(proc, i, j))
{
}
else
mIns[j++] = mIns[i++];
}
mIns.SetSize(j);
#if 1
bool yimm = false, ximm = false, aimm = false, afail = false;
int yval = 0, xval = 0, aval = 0;
if (mNumEntries == 1)
{
if (yenter >= 0)
{
yval = yenter;
yimm = true;
}
if (xenter >= 0)
{
xval = xenter;
ximm = true;
}
}
for(int i = 0; i < mIns.Size(); i++)
{
if (afail)
aimm = false;
if (mIns[i].mType == ASMIT_LDA)
{
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (yimm && mIns[i].mAddress == yval)
{
mIns[i].mType = ASMIT_TYA;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (ximm && mIns[i].mAddress == xval)
{
mIns[i].mType = ASMIT_TXA;
mIns[i].mMode = ASMIM_IMPLIED;
}
aimm = true;
aval = mIns[i].mAddress;
}
else
aimm = false;
}
else if (mIns[i].mType == ASMIT_TYA)
{
if (yimm)
{
aimm = true;
aval = yval;
}
else
aimm = false;
}
else if (mIns[i].mType == ASMIT_TXA)
{
if (ximm)
{
aimm = true;
aval = xval;
}
else
aimm = false;
}
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (yimm && mIns[i].mAddress == ((yval + 1) & 0xff))
{
yval = mIns[i].mAddress;
mIns[i].mType = ASMIT_INY;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (yimm && mIns[i].mAddress == ((yval - 1) & 0xff))
{
yval = mIns[i].mAddress;
mIns[i].mType = ASMIT_DEY;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (aimm && mIns[i].mAddress == aval)
{
mIns[i].mType = ASMIT_TAY;
mIns[i].mMode = ASMIM_IMPLIED;
yimm = true;
yval = aval;
}
else
{
yimm = true;
yval = mIns[i].mAddress;
}
}
else
yimm = false;
}
else if (yimm && mIns[i].mType == ASMIT_INY)
{
yval = (yval + 1) & 0xff;
}
else if (yimm && mIns[i].mType == ASMIT_DEY)
{
yval = (yval - 1) & 0xff;
}
else if (mIns[i].mType == ASMIT_TAY)
{
if (aimm)
{
yimm = true;
yval = aval;
}
else
yimm = false;
}
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (ximm && mIns[i].mAddress == ((xval + 1) & 0xff))
{
xval = mIns[i].mAddress;
mIns[i].mType = ASMIT_INX;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (ximm && mIns[i].mAddress == ((xval - 1) & 0xff))
{
xval = mIns[i].mAddress;
mIns[i].mType = ASMIT_DEX;
mIns[i].mMode = ASMIM_IMPLIED;
}
else if (aimm && mIns[i].mAddress == aval)
{
mIns[i].mType = ASMIT_TAX;
mIns[i].mMode = ASMIM_IMPLIED;
ximm = true;
xval = aval;
}
else
{
ximm = true;
xval = mIns[i].mAddress;
}
}
else
ximm = false;
}
else if (ximm && mIns[i].mType == ASMIT_INX)
{
xval = (xval + 1) & 0xff;
}
else if (ximm && mIns[i].mType == ASMIT_DEX)
{
xval = (xval - 1) & 0xff;
}
else if (mIns[i].mType == ASMIT_TAX)
{
if (aimm)
{
ximm = true;
xval = aval;
}
else
ximm = false;
}
else if (mIns[i].mType == ASMIT_JSR)
yimm = ximm = aimm = false;
else if (mIns[i].mMode == ASMIM_RELATIVE)
{
if (mIns[i].mAddress < 0)
yimm = ximm = aimm = false;
else
afail = true;
}
else if (mIns[i].ChangesAccu())
aimm = false;
}
#endif
bool carrySet = false, carryClear = false;
if (mEntryBlocks.Size() > 0)
{
carrySet = true;
carryClear = true;
}
for (int i = 0; i < mEntryBlocks.Size(); i++)
{
if (mEntryBlocks[i]->mBranch == ASMIT_BCC)
{
if (mEntryBlocks[i]->mTrueJump == this)
carrySet = false;
else
carryClear = false;
}
else if (mEntryBlocks[i]->mBranch == ASMIT_BCS)
{
if (mEntryBlocks[i]->mTrueJump == this)
carryClear = false;
else
carrySet = false;
}
else
carryClear = carrySet = false;
}
#if 1
i = 0;
j = 0;
int accuVal = 0, accuMask = 0;
bool accuFlags = false;
while (i < mIns.Size())
{
bool skip = false;
switch (mIns[i].mType)
{
case ASMIT_CLC:
if (carryClear)
skip = true;
else if (carrySet && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress > 0)
{
// convert CLC before const add into SEC and reduce immediate
skip = true;
mIns[i + 2].mAddress--;
}
else
{
carryClear = true;
carrySet = false;
}
break;
case ASMIT_SEC:
if (carrySet)
skip = true;
else
{
carryClear = false;
carrySet = true;
}
break;
case ASMIT_ADC:
case ASMIT_SBC:
accuMask = 0;
accuFlags = true;
carryClear = false;
carrySet = false;
break;
case ASMIT_CMP:
carryClear = false;
carrySet = false;
accuFlags = false;
break;
case ASMIT_AND:
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
int clear = mIns[i].mAddress ^ 0xff;
if (mIns[i].mAddress == 0xff && accuFlags)
skip = true;
else if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && !(clear & (accuMask ^ 0xff)) && !(accuVal & clear))
skip = true;
else
accuFlags = true;
accuVal &= ~clear;
accuMask |= clear;
}
else
{
accuMask = 0;
accuFlags = true;
}
break;
case ASMIT_ORA:
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
int set = mIns[i].mAddress;
if (mIns[i].mAddress == 0 && accuFlags)
skip = true;
else if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && !(set & (accuMask ^ 0xff)) && !(~accuVal & set))
skip = true;
else
accuFlags = true;
accuVal |= set;
accuMask |= set;
}
else
{
accuMask = 0;
accuFlags = true;
}
break;
case ASMIT_LDA:
if (mIns[i].mMode == ASMIM_IMMEDIATE)
{
accuVal = mIns[i].mAddress;
accuMask = 0xff;
}
else
accuMask = 0x00;
accuFlags = true;
break;
case ASMIT_ASL:
if (mIns[i].mMode == ASMIM_IMPLIED)
{
accuVal <<= 1;
accuMask = (accuMask << 1) | 1;
if (accuMask & 0x100)
{
if (accuVal & 0x100)
{
carryClear = false;
carrySet = true;
}
else
{
carryClear = true;
carrySet = false;
}
}
else
{
carryClear = false;
carrySet = false;
}
accuMask &= 0xff;
accuVal &= 0xff;
}
else
{
carryClear = false;
carrySet = false;
}
accuFlags = mIns[i].mMode == ASMIM_IMPLIED;
break;
case ASMIT_LSR:
if (mIns[i].mMode == ASMIM_IMPLIED)
{
if (accuMask & 0x01)
{
if (accuVal & 0x01)
{
carryClear = false;
carrySet = true;
}
else
{
carryClear = true;
carrySet = false;
}
}
else
{
carryClear = false;
carrySet = false;
}
accuVal >>= 1;
accuMask = (accuMask >> 1) | 0x80;
}
else
{
carryClear = false;
carrySet = false;
}
accuFlags = mIns[i].mMode == ASMIM_IMPLIED;
break;
case ASMIT_ROL:
if (mIns[i].mMode == ASMIM_IMPLIED)
{
accuVal <<= 1;
accuMask <<= 1;
if (accuMask & 0x100)
{
if (accuVal & 0x100)
{
carryClear = false;
carrySet = true;
}
else
{
carryClear = true;
carrySet = false;
}
}
else
{
carryClear = false;
carrySet = false;
}
accuVal &= 0xff;
accuMask &= 0xff;
}
else
{
carryClear = false;
carrySet = false;
}
accuFlags = mIns[i].mMode == ASMIM_IMPLIED;
break;
case ASMIT_ROR:
if (mIns[i].mMode == ASMIM_IMPLIED)
{
if (accuMask & 0x01)
{
if (accuVal & 0x01)
{
carryClear = false;
carrySet = true;
}
else
{
carryClear = true;
carrySet = false;
}
}
else
{
carryClear = false;
carrySet = false;
}
accuVal >>= 1;
accuMask >>= 1;
}
else
{
carryClear = false;
carrySet = false;
}
accuFlags = mIns[i].mMode == ASMIM_IMPLIED;
break;
case ASMIT_TAX:
case ASMIT_TAY:
accuFlags = true;
break;
default:
if (mIns[i].ChangesCarry())
{
carryClear = false;
carrySet = false;
}
if (mIns[i].ChangesAccu())
{
accuMask = 0;
accuFlags = false;
}
else if (mIns[i].ChangesZFlag())
{
accuFlags = false;
}
}
if (!skip)
{
if (i != j)
mIns[j] = mIns[i];
j++;
}
i++;
}
mIns.SetSize(j);
#endif
if (mTrueJump)
mTrueJump->BlockSizeReduction(proc, ximm ? xval : -1, yimm ? yval: -1);
if (mFalseJump)
mFalseJump->BlockSizeReduction(proc, ximm ? xval : -1, yimm ? yval : -1);
}
}
bool NativeCodeBasicBlock::ReferencesAccu(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ReferencesAccu())
return true;
return false;
}
bool NativeCodeBasicBlock::ReferencesYReg(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ReferencesYReg())
return true;
return false;
}
bool NativeCodeBasicBlock::ReferencesXReg(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ReferencesXReg())
return true;
return false;
}
bool NativeCodeBasicBlock::ChangesAccu(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ChangesAccu())
return true;
return false;
}
bool NativeCodeBasicBlock::ChangesYReg(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ChangesYReg())
return true;
return false;
}
bool NativeCodeBasicBlock::ChangesXReg(int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ChangesXReg())
return true;
return false;
}
bool NativeCodeBasicBlock::ChangesZeroPage(int address, int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ChangesZeroPage(address))
return true;
return false;
}
bool NativeCodeBasicBlock::UsesZeroPage(int address, int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].UsesZeroPage(address))
return true;
return false;
}
bool NativeCodeBasicBlock::ReferencesZeroPage(int address, int from, int to) const
{
if (to > mIns.Size()) to = mIns.Size();
for (int i = from; i < to; i++)
if (mIns[i].ReferencesZeroPage(address))
return true;
return false;
}
bool NativeCodeBasicBlock::RemoveNops(void)
{
bool changed = false;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
int i = 0;
int j = 0;
while (i < mIns.Size())
{
if (mIns[i].mType == ASMIT_NOP)
;
else
{
if (i != j)
mIns[j] = mIns[i];
j++;
}
i++;
}
if (j != i)
changed = true;
mIns.SetSize(j);
mIns.Reserve(2 * j);
return changed;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerShuffle(int pass)
{
bool changed = false;
#if 1
#if 1
// move load store pairs up to initial store
for (int i = 2; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
if (MoveLoadStoreUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// replace zero page up
for (int i = 1; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !(mIns[i + 0].mLive & LIVE_MEM))
{
if (ReplaceZeroPageUp(i))
changed = true;
}
}
CheckLive();
#endif
// Move LDX/LDY up to STA of same address
#if 1
if (pass >= 9)
{
for (int i = 2; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (MoveLDXUp(i))
changed = true;
}
else if (mIns[i].mType == ASMIT_LDY && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (MoveLDYUp(i))
changed = true;
}
}
CheckLive();
}
#endif
#if 1
// move ORA #imm up a shift chain to an LDA #imm
for (int i = 1; i + 1 < mIns.Size(); i++)
{
if (mIns[i].IsShift() && mIns[i].mMode == ASMIM_IMPLIED && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
if (FoldShiftORAIntoLoadImmUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move ORA #imm up a shift chain to an LDA #imm
for (int i = 1; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
{
if (MoveLDXBeforeZ(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// Combine ADC with immediate
for (int i = 4; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (CombineImmediateADCUp(i))
changed = true;
}
else if (mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_X) &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (CombineImmediateADCUpX(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load store pairs up to initial store
for (int i = 2; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
if (MoveLoadStoreXUp(i))
changed = true;
}
}
CheckLive();
#endif
// move sta zp, tax, lda abs,x , sta zp down to use
#if 1
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
if (MoveStaTaxLdaStaDown(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - store (),y up to initial store
//
for (int i = 2; i + 2 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y)
{
if (MoveIndirectLoadStoreUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load (),y store zp down to potential user
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mFlags & NICT_ZPFLIPPED) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (MoveLoadIndirectTempStoreUp(i))
changed = true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (MoveIndirectLoadStoreDown(i))
changed = true;
}
#if 1
if (pass > 0 &&
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (MoveIndirectLoadStoreDownY(i))
changed = true;
}
#endif
}
CheckLive();
#endif
#if 1
// move load (),y store zp up to potential user
for (int i = 4; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y)))
{
if (MoveLoadIndirectBypassYUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (MoveTYADCStoreDown(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - store abs up to initial store
//
for (int i = 2; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA &&
(mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_INDIRECT_Y))
{
if (MoveAbsoluteLoadStoreUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move ldx/stx down and convert to accu
//
for (int i = mIns.Size() - 2; i >= 0; i--)
{
if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS) && mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
if (MoveLDSTXOutOfRange(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - add # - store up to initial store
//
for (int i = 2; i + 3 < mIns.Size(); i++)
{
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
{
if (MoveLoadAddImmStoreUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - ora/and/eor # - store up to initial store
//
for (int i = 2; i + 2 < mIns.Size(); i++)
{
if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
(mIns[i + 1].mType == ASMIT_ORA || mIns[i + 1].mType == ASMIT_AND || mIns[i + 1].mType == ASMIT_EOR) && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
{
if (MoveLoadEorImmStoreUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - add # - store with absolute,x up as far possible
//
for (int i = 2; i + 3 < mIns.Size(); i++)
{
if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
if (MoveLoadAddImmStoreAbsXUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// move load - add ZP - store up to initial store
//
for (int i = 2; i + 3 < mIns.Size(); i++)
{
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE)
{
if (MoveCLCLoadAddZPStoreUp(i))
changed = true;
}
#if 1
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
{
if (MoveLoadAddZPStoreUp(i))
changed = true;
}
#endif
#if 1
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
{
if (MoveLoadShiftStoreUp(i))
changed = true;
}
#endif
#if 1
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
(mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL) && mIns[i + 1].mMode == ASMIM_IMPLIED &&
(mIns[i + 2].mType == ASMIT_ROL || mIns[i + 2].mType == ASMIT_ROR) && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
if (MoveLoadShiftRotateUp(i))
changed = true;
}
#endif
}
CheckLive();
#endif
#if 1
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].IsShift() && mIns[i].mMode == ASMIM_ZERO_PAGE)
{
if (MoveShiftZeroPageUp(i))
{
CheckLive();
changed = true;
}
}
}
CheckLive();
#endif
#if 1
// move simple add down to consumer
if (!changed)
{
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && (mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)) == 0)
{
if (MoveCLCLoadAddZPStoreDown(i))
changed = true;
}
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 3 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (MoveTAXADCSTADown(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i < mIns.Size(); i++)
{
if ((mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_LDY) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM))
{
if (MoveSimpleADCToINCDECDown(i))
changed = true;
}
}
#endif
//
// shorten x/y register lifetime
#if 1
//
// move ldx/y down
for (int i = 0; i + 1 < mIns.Size(); i++)
{
#if 1
if (mIns[i].mType == ASMIT_LDY)
{
if (!mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
{
if (mIns[i].mMode != ASMIM_ABSOLUTE_X || !mIns[i + 1].ChangesXReg())
{
if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
{
if (mIns[i + 1].SameEffectiveAddress(mIns[i]))
mIns[i + 1].mLive |= LIVE_MEM;
NativeCodeInstruction ins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive &= ~LIVE_CPU_REG_Y;
mIns[i + 1] = ins;
mIns[i + 1].mLive |= mIns[i].mLive;
if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X)
mIns[i].mLive |= LIVE_CPU_REG_X;
}
}
}
}
else if (mIns[i].mType == ASMIT_LDX)
{
if (!mIns[i + 1].RequiresXReg() && !mIns[i + 1].ChangesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
{
if (mIns[i].mMode != ASMIM_ABSOLUTE_Y || !mIns[i + 1].ChangesYReg())
{
if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
{
if (mIns[i + 1].SameEffectiveAddress(mIns[i]))
mIns[i + 1].mLive |= LIVE_MEM;
NativeCodeInstruction ins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive &= ~LIVE_CPU_REG_X;
mIns[i + 1] = ins;
mIns[i + 1].mLive |= mIns[i].mLive;
if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y)
mIns[i].mLive |= LIVE_CPU_REG_Y;
}
}
}
}
#endif
}
CheckLive();
#endif
#if 1
// move stx up
for (int i = 1; i < mIns.Size(); i++)
{
if (!(mIns[i].mFlags & NCIF_VOLATILE))
{
if (mIns[i].mType == ASMIT_STX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
{
if (MoveStoreXUp(i))
changed = true;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
{
if (MoveLoadXUp(i))
changed = true;
}
else if (mIns[i].mType == ASMIT_STY && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
{
if (i > 1 || mIns[0].mType != ASMIT_STX)
{
if (MoveStoreYUp(i))
changed = true;
}
}
else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
{
if (MoveLoadYUp(i))
changed = true;
}
}
}
CheckLive();
#endif
#if 1
// move ldy, sty down if live
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
int j = i;
while (j + 2 < mIns.Size() &&
!mIns[j + 2].ReferencesYReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[j + 0].mLive |= mIns[j + 2].mLive;
mIns[j + 1].mLive |= mIns[j + 2].mLive;
mIns[j + 2].mLive &= ~LIVE_CPU_REG_Y;
mIns.Insert(j, mIns[j + 2]);
mIns.Remove(j + 3);
j++;
}
}
else if (mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
int j = i;
while (j + 2 < mIns.Size() &&
!mIns[j + 2].ReferencesXReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[j + 0].mLive |= mIns[j + 2].mLive;
mIns[j + 1].mLive |= mIns[j + 2].mLive;
mIns[j + 2].mLive &= ~LIVE_CPU_REG_X;
mIns.Insert(j, mIns[j + 2]);
mIns.Remove(j + 3);
j++;
}
}
}
#endif
#if 1
// move clc and sec down
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if ((mIns[i].mType == ASMIT_CLC || mIns[i].mType == ASMIT_SEC) && !mIns[i + 1].RequiresCarry() && !mIns[i + 1].ChangesCarry())
{
if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && mIns[i + 2].RequiresCarry())
;
else if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mMode == ASMIM_INDIRECT_Y)
;
else
{
NativeCodeInstruction pins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i + 1] = pins;
mIns[i + 1].mLive |= mIns[i].mLive;
// changed = true;
}
}
}
CheckLive();
#endif
#if 1
// move iny/dey/inx/dex down
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if ((mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY) && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
if (i + 3 == mIns.Size() && mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_CPX)
; // Avoid bypassing loop iterator
else if (!mIns[i + 1].RequiresYReg())
{
NativeCodeInstruction pins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1] = pins;
mIns[i + 1].mLive |= mIns[i].mLive;
}
else if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y)
{
if (mIns[i].mType == ASMIT_INY)
mIns[i + 1].mAddress++;
else
mIns[i + 1].mAddress--;
NativeCodeInstruction pins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1] = pins;
mIns[i + 1].mLive |= mIns[i].mLive;
}
}
else if ((mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX) && !mIns[i + 1].ChangesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
if (i + 3 == mIns.Size() && mIns[i + 1].mType == ASMIT_INY && mIns[i + 2].mType == ASMIT_CPY)
; // Avoid bypassing loop iterator
else if (!mIns[i + 1].RequiresXReg())
{
NativeCodeInstruction pins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i + 1] = pins;
mIns[i + 1].mLive |= mIns[i].mLive;
}
else if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X)
{
if (mIns[i].mType == ASMIT_INX)
mIns[i + 1].mAddress++;
else
mIns[i + 1].mAddress--;
NativeCodeInstruction pins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i + 1] = pins;
mIns[i + 1].mLive |= mIns[i].mLive;
}
}
}
CheckLive();
#endif
#if 1
// move tya/clc/adc/tay down
for (int i = 0; i + 5 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[i + 4].mType == ASMIT_LDA && (mIns[i + 4].mMode == ASMIM_IMMEDIATE || mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 4].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode != ASMIM_INDIRECT_Y && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 5].mMode == ASMIM_ABSOLUTE_Y)
mIns[i + 5].mAddress += mIns[i + 2].mAddress;
mIns.Insert(i + 0, mIns[i + 4]); mIns.Remove(i + 5);
mIns.Insert(i + 1, mIns[i + 5]); mIns.Remove(i + 6);
}
#if 1
else if (i + 6 < mIns.Size() &&
mIns[i + 4].mType == ASMIT_LDA && (mIns[i + 4].mMode == ASMIM_IMMEDIATE || mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 4].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode != ASMIM_INDIRECT_Y &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode != ASMIM_INDIRECT_Y && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
mIns[i + 6].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 5].mMode == ASMIM_ABSOLUTE_Y)
mIns[i + 5].mAddress += mIns[i + 2].mAddress;
if (mIns[i + 6].mMode == ASMIM_ABSOLUTE_Y)
mIns[i + 6].mAddress += mIns[i + 2].mAddress;
mIns.Insert(i + 0, mIns[i + 4]); mIns.Remove(i + 5);
mIns.Insert(i + 1, mIns[i + 5]); mIns.Remove(i + 6);
mIns.Insert(i + 2, mIns[i + 6]); mIns.Remove(i + 7);
}
#endif
}
}
CheckLive();
#endif
#if 1
// reverse "sta t,lda abs,clc,adc t" to "sta t,clc,adc abs,nop"
for (int i = 1; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 2].IsCommutative() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mType == ASMIT_CLC || mIns[i + 1].mType == ASMIT_SEC) && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE)
{
if (ReverseLoadCommutativeOpUp(i, i + 2))
changed = true;
}
else if (mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE)
{
if (ReverseLoadCommutativeOpUp(i, i + 1))
changed = true;
}
}
CheckLive();
#endif
// shortcut index
#if 1
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_TAY)
{
int j = i + 2, k = i, n = i;
while (j < mIns.Size() && !mIns[j].ChangesXReg() && !mIns[j].ChangesYReg())
{
if (mIns[j].mMode == ASMIM_ABSOLUTE_Y)
{
assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_X));
mIns[j].mMode = ASMIM_ABSOLUTE_X;
mIns[j].mFlags |= NICT_INDEXFLIPPED;
n = j;
changed = true;
}
j++;
}
while (k < n)
{
mIns[k].mLive |= LIVE_CPU_REG_X;
k++;
}
}
else if (mIns[i].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_TAX)
{
int j = i + 2, k = i, n = i;
while (j < mIns.Size() && !mIns[j].ChangesXReg() && !mIns[j].ChangesYReg())
{
if (mIns[j].mMode == ASMIM_ABSOLUTE_X)
{
assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_Y));
mIns[j].mMode = ASMIM_ABSOLUTE_Y;
mIns[j].mFlags |= NICT_INDEXFLIPPED;
n = j;
changed = true;
}
j++;
}
while (k < n)
{
mIns[k].mLive |= LIVE_CPU_REG_Y;
k++;
}
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
{
if (MoveLoadStoreOutOfXYRangeUp(i))
changed = true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
{
if (MoveLoadStoreOutOfXYRangeUp(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
if (ReverseReplaceTAX(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
// Move TAX and TAY down
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TAX)
{
int j = i + 1;
while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ChangesAccu())
j++;
if (j < mIns.Size() && mIns[j].mType == ASMIT_CPX && !(mIns[j].mLive & LIVE_CPU_REG_X))
{
mIns[j].mType = ASMIT_CMP;
while (j > i)
{
j--;
mIns[j].mLive |= LIVE_CPU_REG_A;
}
changed = true;
}
}
else if (mIns[i].mType == ASMIT_TAY)
{
int j = i + 1;
while (j < mIns.Size() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesAccu())
j++;
if (j < mIns.Size() && mIns[j].mType == ASMIT_CPY && !(mIns[j].mLive & LIVE_CPU_REG_Y))
{
mIns[j].mType = ASMIT_CMP;
while (j > i)
{
j--;
mIns[j].mLive |= LIVE_CPU_REG_A;
}
changed = true;
}
}
}
CheckLive();
#endif
#if 1
int taxPos = -1, tayPos = -1;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TAX)
{
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
taxPos = i;
else
taxPos = -1;
}
else if (mIns[i].mType == ASMIT_TAY)
{
if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
tayPos = i;
else
tayPos = -1;
}
else if (mIns[i].ChangesXReg())
taxPos = -1;
else if (mIns[i].ChangesYReg())
tayPos = -1;
else if (mIns[i].mType == ASMIT_TXA)
{
if (taxPos >= 0 && !(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
if (JoinTAXARange(taxPos, i))
changed = true;
taxPos = -1; tayPos = -1;
}
else
taxPos = -1;
}
else if (mIns[i].mType == ASMIT_TYA)
{
if (tayPos >= 0 && !(mIns[i].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
if (JoinTAYARange(tayPos, i))
changed = true;
taxPos = -1; tayPos = -1;
}
else
tayPos = -1;
}
else if (mIns[i].RequiresXReg())
taxPos = -1;
else if (mIns[i].RequiresYReg())
tayPos = -1;
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_TAY ||
mIns[i].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_TAX)
{
if (MergeXYSameValue(i + 2))
changed = true;
}
}
CheckLive();
#endif
#if 1
if (pass > 1)
{
// move high byte load down, if low byte is immediatedly needed afterwards
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress != mIns[i + 3].mAddress && mIns[i + 2].mAddress + 1 != mIns[i + 3].mAddress &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z))
{
if (MoveStoreHighByteDown(i))
changed = true;
}
}
CheckLive();
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z))
{
if (MoveAddHighByteDown(i))
changed = true;
}
}
CheckLive();
}
#endif
#if 1
for (int i = 2; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
{
if (MoveLoadImmStoreAbsoluteUp(i + 0))
changed = true;
}
}
CheckLive();
#endif
#if 1
for (int i = 2; i < mIns.Size(); i++)
{
if ((mIns[i].mType == ASMIT_ASL || mIns[i].mType == ASMIT_LSR) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (MoveASLMemUp(i))
changed = true;
}
}
CheckLive();
#endif
if (pass > 1)
{
#if 1
// replace zero page down
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && (mIns[i + 0].mLive & LIVE_MEM))
{
if (ReplaceZeroPageDown(i))
changed = true;
}
}
CheckLive();
#endif
}
#endif
CheckLive();
#if 1
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 2].mAddress &&
mIns[i + 3].mType == ASMIT_ROR && mIns[i + 3].mMode == ASMIM_IMPLIED)
{
int j = 2;
while (i + 3 + j < mIns.Size() &&
mIns[i + 2 + j].mType == ASMIT_LSR && mIns[i + 2 + j].mMode == ASMIM_ZERO_PAGE && mIns[i + 2 + j].mAddress == mIns[i + 1].mAddress &&
mIns[i + 3 + j].mType == ASMIT_ROR && mIns[i + 3 + j].mMode == ASMIM_IMPLIED)
{
j += 2;
}
if (i + 2 + j < mIns.Size() && mIns[i + 2 + j].mType == ASMIT_STA && mIns[i + 2 + j].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2 + j].mAddress == mIns[i + 2].mAddress && !(mIns[i + 2 + j].mLive & LIVE_CPU_REG_A))
{
int addrl = mIns[i + 2].mAddress, addrh = mIns[i + 1].mAddress;
const InterInstruction* iins(mIns[i + 1].mIns);
for (int k = 0; k < j; k += 2)
{
mIns[i + k + 0] = NativeCodeInstruction(iins, ASMIT_LSR, ASMIM_IMPLIED);
mIns[i + k + 1] = NativeCodeInstruction(iins, ASMIT_ROR, ASMIM_ZERO_PAGE, addrl);
}
mIns[i + j] = NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, addrh);
mIns[i + j + 1].mType = ASMIT_NOP; mIns[i + j + 1].mMode = ASMIM_IMPLIED;
mIns[i + j + 2].mType = ASMIT_NOP; mIns[i + j + 2].mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 4 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress >= -2 && mIns[i + 2].mAddress <= 2 || mIns[i + 2].mAddress >= 254 && mIns[i + 2].mAddress < 256) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
if (MoveTXADCDown(i))
changed = true;
}
}
CheckLive();
#endif
#if 1
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
int j = 1;
while (i >= j && i + j + 1 < mIns.Size() &&
mIns[i - j].mType == ASMIT_ASL && mIns[i - j].mMode == ASMIM_IMPLIED &&
mIns[i + 1 + j].mType == ASMIT_LSR && mIns[i + 1 + j].mMode == ASMIM_IMPLIED && !(mIns[i + 1 + j].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
j++;
mIns[i + 1 - j].mType = ASMIT_AND;
mIns[i + 1 - j].mMode = ASMIM_IMMEDIATE;
mIns[i + 1 - j].mAddress = 0xff >> j;
while (j > 1)
{
mIns[i + j].mType = ASMIT_NOP;
mIns[i + j].mMode = ASMIM_IMPLIED;
j--;
mIns[i + 1 - j].mType = ASMIT_NOP;
mIns[i + 1 - j].mMode = ASMIM_IMPLIED;
}
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
CheckLive();
#endif
return changed;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate1(int i, int pass)
{
if (mIns[i].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
{
mIns[i].mType = ASMIT_LDA;
return true;
}
else if (mIns[i].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0xff && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
return true;
}
else if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0xff)
{
mIns[i].mType = ASMIT_LDA;
return true;
}
else if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x00 && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
return true;
}
else if (mIns[i].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x00 && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
return true;
}
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;
return true;
}
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;
return true;
}
else if (mIns[i].mType == ASMIT_TAY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
{
mIns[i].mType = ASMIT_ORA;
mIns[i].mMode = ASMIM_IMMEDIATE;
mIns[i].mAddress = 0;
return true;
}
else if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & LIVE_CPU_REG_X))
{
mIns[i].mType = ASMIT_ORA;
mIns[i].mMode = ASMIM_IMMEDIATE;
mIns[i].mAddress = 0;
return true;
}
int apos;
if (mIns[i].mMode == ASMIM_INDIRECT_Y && FindGlobalAddress(i, mIns[i].mAddress, apos))
{
mIns[i].mMode = ASMIM_ABSOLUTE_Y;
mIns[i].mAddress = mIns[apos].mAddress;
mIns[i].mLinkerObject = mIns[apos].mLinkerObject;
return true;
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate2(int i, int pass)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_LDA)
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
return true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && mIns[i].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;;
return true;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0)
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0)
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_AND && mIns[i + 1].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{
mIns[i].mAddress &= mIns[i + 1].mAddress;
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_ORA && mIns[i + 1].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{
mIns[i].mAddress |= mIns[i + 1].mAddress;
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_EOR && mIns[i + 1].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{
mIns[i].mAddress ^= mIns[i + 1].mAddress;
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff)
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ROR)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LSR;
return true;
}
else if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x80 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_EOR;
return true;
}
else if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x80 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_EOR;
return true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0 && mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED)
{
mIns[i + 1].mType = ASMIT_CLC;
return true;
}
else if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_CLC;
mIns[i + 1].mAddress++;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]))
{
mIns[i + 1].mType = ASMIT_ROL;
mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesAccuAndFlag())
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesAccuAndFlag() && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_CMP && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDA;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED)
{
int aval = mIns[i + 0].mAddress << 1;
mIns[i + 0].mAddress = aval & 0xff;
if (aval & 0x100)
mIns[i + 1].mType = ASMIT_SEC;
else
mIns[i + 1].mType = ASMIT_CLC;
mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass >= 3 &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
NativeCodeInstruction ins(mIns[i + 1]);
mIns[i + 1].CopyMode(mIns[i + 0]);
mIns[i + 0].CopyMode(ins);
if (mIns[i + 1].RequiresXReg())
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 1].RequiresYReg())
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress &&
(mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR) && !(mIns[i + 0].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = mIns[i + 1].mType;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_LDA;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_ASL;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
mIns[i + 2].mLive = mIns[i + 1].mLive;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]))
{
mIns[i + 1].mType = ASMIT_TAY;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA &&
mIns[i + 1].mType == ASMIT_LDX && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]))
{
mIns[i + 1].mType = ASMIT_TAX;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_STX)
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1] = ins;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_STY)
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1] = ins;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_STA && !mIns[i + 1].RequiresXReg())
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1] = ins;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_STA && !mIns[i + 1].RequiresYReg())
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1] = ins;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CPX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_CMP;
return true;
}
else if (mIns[i + 0].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_CPY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_CMP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_AND;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xfe;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED)
{
mIns[i + 0].mType = ASMIT_AND;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xfe;
mIns[i + 0].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_TAX)
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_TAY)
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_TXA)
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_TYA)
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mType == ASMIT_DEX && !(mIns[i + 1].mLive & 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_DEX &&
mIns[i + 1].mType == ASMIT_INX && !(mIns[i + 1].mLive & 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mType == ASMIT_DEY && !(mIns[i + 1].mLive & 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_DEY &&
mIns[i + 1].mType == ASMIT_INY && !(mIns[i + 1].mLive & 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_DEX)
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_INX)
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_DEY)
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_INY)
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X) &&
mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y) &&
mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= mIns[i + 1].mLive;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y) &&
mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CMP && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 1].mType = ASMIT_CPX;
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CMP && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
{
mIns[i + 1].mType = ASMIT_CPY;
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY &&
mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_LDY) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 1].SameEffectiveAddress(mIns[i + 0]))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= ins.mLive;
mIns[i + 1] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mAddress++;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mAddress++;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mAddress & 0x01) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_ASL;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mAddress & 0x80) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_LSR;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x01) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0] = mIns[i + 1];
mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 0].mAddress = (mIns[i + 0].mAddress >> 1) & 0x7f;
mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x80) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0] = mIns[i + 1];
mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 0].mAddress = (mIns[i + 0].mAddress << 1) & 0xfe;
mIns[i + 1].mType = ASMIT_ROR; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = mIns[i + 1].mType; mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
mIns[i + 0].mLive &= ~LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
{
mIns[i + 1].mType = mIns[i + 0].mType;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 0].mType = ASMIT_LDA;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 1].mType == ASMIT_INX)
{
if (mIns[i + 0].mFlags & NCIF_UPPER)
mIns[i + 0].mAddress += 0x100;
else
mIns[i + 0].mAddress++;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_CPX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_CMP;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_CPY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_CMP;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
{
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
{
mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
{
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
{
mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
{
if (!(mIns[i + 0].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INX));
mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INY));
mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_C))
{
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_CLC));
mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
return true;
}
}
else if ((mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_TAX || mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
mIns[i + 1].mType == ASMIT_CPX && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if ((mIns[i + 0].mType == ASMIT_LDY || mIns[i + 0].mType == ASMIT_TAY || mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
mIns[i + 1].mType == ASMIT_CPY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 0].mLinkerObject == mIns[i + 1].mLinkerObject &&
mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
!(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
!(mIns[i + 1].mFlags & NCIF_VOLATILE))
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 0].mLinkerObject == mIns[i + 1].mLinkerObject &&
mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
!(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
!(mIns[i + 1].mFlags & NCIF_VOLATILE))
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = ins;
return true;
}
#if 0
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int val = mIns[i + 0].mAddress;
mIns[i + 0].CopyMode(mIns[i + 1]);
mIns[i + 1].mMode = ASMIM_IMMEDIATE;
mIns[i + 1].mAddress = val;
progress = true;
}
#endif
else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
const NativeCodeInstruction* ains, * iins;
int sreg = mIns[i + 1].mAddress;
int apos, addr;
uint32 flags;
if (FindGlobalAddressSumY(i, sreg, true, apos, ains, iins, flags, addr))
{
if (iins || (flags & LIVE_CPU_REG_Y) || (flags & LIVE_CPU_REG_X)) //!(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
RepairLoadYImmediate(i + 1, mIns[i + 0].mAddress);
if (flags & LIVE_CPU_REG_Y)
{
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
}
else if (flags & LIVE_CPU_REG_X)
{
mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
}
else
{
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
}
if (ains->mMode == ASMIM_IMMEDIATE)
{
mIns[i + 1].mLinkerObject = 0;
mIns[i + 1].mAddress = addr + mIns[i + 0].mAddress;
}
else
{
mIns[i + 1].mLinkerObject = ains->mLinkerObject;
mIns[i + 1].mAddress = ains->mAddress + mIns[i + 0].mAddress;
}
if (!iins)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
if (flags & LIVE_CPU_REG_Y)
{
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
}
else
{
PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX, ASMIM_IMPLIED));
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
}
}
else if (iins->mMode != ASMIM_ZERO_PAGE)
{
mIns[i + 0].mMode = iins->mMode;
mIns[i + 0].mAddress = iins->mAddress;
mIns[i + 0].mLinkerObject = iins->mLinkerObject;
mIns[i + 0].mFlags = iins->mFlags;
if (!(flags & LIVE_CPU_REG_Y) && (flags & LIVE_CPU_REG_X))
mIns[i + 0].mType = ASMIT_LDX;
}
else if (iins->mAddress == sreg)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
if (flags & LIVE_CPU_REG_Y)
{
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
mIns[apos].mLive |= LIVE_MEM;
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
}
else
{
PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, iins->mAddress));
mIns[apos].mLive |= LIVE_MEM;
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
}
}
else
{
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = iins->mAddress;
if (!(flags & LIVE_CPU_REG_Y) && (flags & LIVE_CPU_REG_X))
mIns[i + 0].mType = ASMIT_LDX;
}
CheckLive();
return true;
}
}
}
CheckLive();
if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
int addr;
if (FindPageStartAddress(i, mIns[i + 1].mAddress, addr))
{
if (mIns[i + 1].mLive & LIVE_CPU_REG_Y)
{
mIns.Insert(i + 2, mIns[i + 0]);
mIns[i + 2].mLive |= mIns[i + 1].mLive;
}
int absaddr = addr + mIns[i + 0].mAddress;
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 0].mAddress = mIns[i + 1].mAddress;
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 1].mAddress = absaddr;
mIns[i + 1].mLinkerObject = nullptr;
CheckLive();
return true;
}
}
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
int sreg = mIns[i + 1].mAddress;
int apos, breg, ireg;
if (FindAddressSumY(i, sreg, apos, breg, ireg))
{
if (PatchAddressSumY(i, sreg, apos, breg, ireg))
{
CheckLive();
return true;
}
}
}
if (
mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO) &&
mIns[i + 1].mMode == ASMIM_INDIRECT_Y && mIns[i + 0].mAddress == mIns[i + 1].mAddress)
{
int sreg = mIns[i + 0].mAddress;
int apos, breg, ireg;
if (FindAddressSumY(i, sreg, apos, breg, ireg))
{
if (!(breg == sreg || ireg == sreg) || !(mIns[i + 1].mLive & LIVE_MEM))
{
if (breg == sreg || ireg == sreg)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i + 1, 0);
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
mIns[i + 1].mAddress = breg; mIns[i + 1].mFlags &= ~NCIF_YZERO;
mIns[i + 2].mAddress = breg; mIns[i + 2].mFlags &= ~NCIF_YZERO;
CheckLive();
return true;
}
}
}
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 3 &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
int apos, breg, ireg;
if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
{
if (breg != mIns[i + 1].mAddress && ireg != mIns[i + 1].mAddress)// || !(mIns[i + 1].mLive & LIVE_MEM))
{
int yoffset = mIns[i + 0].mAddress;
if (breg == mIns[i + 1].mAddress)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i + 1, 0);
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = ireg;
mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mAddress = breg;
mIns[i + 1].mFlags &= ~NCIF_YZERO;
for (int j = 0; j < yoffset; j++)
{
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_INY, ASMIM_IMPLIED));
mIns[i + 1].mLive = mIns[i + 0].mLive;
}
CheckLive();
return true;
}
}
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate3(int i, int pass)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_LDA && (mIns[i + 1].mType == ASMIT_CLC || mIns[i + 1].mType == ASMIT_SEC))
{
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
mIns[i + 1].mType == ASMIT_INC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && (mIns[i + 2].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_CLC;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_ADC;
mIns[i + 1].mMode = ASMIM_IMMEDIATE;
mIns[i + 1].mAddress = 1;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA &&
mIns[i + 1].IsShiftOrInc() &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!mIns[i + 2].SameEffectiveAddress(mIns[i + 1]) &&
!(mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 2].mAddress || mIns[i + 1].mAddress == mIns[i + 2].mAddress + 1)) &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode != ASMIM_ZERO_PAGE &&
mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
mIns[i + 2].IsCommutative() && HasAsmInstructionMode(mIns[i + 2].mType, mIns[i + 1].mMode) &&
(mIns[i + 2].mLive & LIVE_MEM) == 0)
{
mIns[i + 1].mType = mIns[i + 2].mType;
mIns[i + 1].mLive |= mIns[i + 2].mLive;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 2].mType == ASMIT_LDA && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
{
mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_LDA && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
mIns[i + 0].SameEffectiveAddress(mIns[i + 2]))
{
mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
!mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !mIns[i + 1].ChangesAccu())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_TAY;
mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
!mIns[i + 1].ChangesAccu() && !mIns[i + 1].RequiresAccu() && !mIns[i + 1].RequiresYReg())
{
mIns[i + 0].mType = ASMIT_LDY;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
if (mIns[i + 1].ChangesYReg())
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
mIns[i + 1].mType == ASMIT_DEC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_SEC; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_SBC; mIns[i + 1].mMode = ASMIM_IMMEDIATE; mIns[i + 1].mAddress = 1; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_ROR && mIns[i + 2].mMode == ASMIM_IMPLIED)
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 1].mType == ASMIT_LDY &&
mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
{
mIns[i + 2] = mIns[i + 0];
mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 0].RequiresCarry())
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X) &&
mIns[i + 1].IsShift() &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 2].mType = mIns[i + 1].mType;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].UsesAccu() &&
mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_STA;
mIns[i + 2].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress)
{
mIns[i + 0] = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = mIns[i + 0];
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_STA;
mIns[i + 2].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
return true;
}
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 + 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;
mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[i + 0].mType = ASMIT_CMP; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0x80;
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_INX &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_CLC;
mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_DEX &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_SEC;
mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_SBC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].UsesAccu() &&
mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_STA;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].UsesAccu() &&
mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_STA;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_X)))
{
mIns[i + 0].mType = ASMIT_DEX;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_DEY;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
int t = (mIns[i + 2].mAddress ^ 0xff) + mIns[i + 1].mAddress + 1;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mAddress = t & 0xff;
if (t < 256)
mIns[i + 0].mType = ASMIT_CLC;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
int t = mIns[i + 2].mAddress + mIns[i + 1].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mAddress = t & 0xff;
if (t >= 256)
mIns[i + 0].mType = ASMIT_SEC;
return true;
}
else if (pass > 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_ADC)
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_LDA;
return true;
}
else if (pass > 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC)
{
mIns[i + 1] = mIns[i + 0];
mIns[i + 0].mType = ASMIT_CLC;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
if (mIns[i + 1].mFlags & NCIF_UPPER)
mIns[i + 1].mAddress += 0x0100 * mIns[i + 2].mAddress;
else
mIns[i + 1].mAddress += mIns[i + 2].mAddress;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_SBC)
{
mIns[i + 2].mType = ASMIT_EOR;
return 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;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
{
int t = mIns[i + 2].mAddress;
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
if (t > 1)
{
mIns[i + 1].mType = ASMIT_INY;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
}
else
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
{
int t = mIns[i + 2].mAddress;
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
if (t > 1)
{
mIns[i + 1].mType = ASMIT_INY;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
}
else
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
}
mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mAddress += mIns[i + 2].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SBC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mAddress += mIns[i + 2].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return 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_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 2].mAddress ^= 0x80;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1)
{
mIns[i + 0].mType = ASMIT_SEC; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
!mIns[i + 1].ChangesAddress() && !mIns[i + 1].ChangesGlobalMemory() &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesXReg() &&
!(mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDX &&
mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDY &&
mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDX &&
mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY &&
mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM))
{
mIns[i + 0] = mIns[i + 2];
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM) &&
(!mIns[i + 1].ChangesZFlag() || !(mIns[i + 2].mLive & LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_ROL; mIns[i + 2].mAddress = mIns[i + 1].mAddress; mIns[i + 2].mLive |= LIVE_MEM;
mIns[i + 1].mType = ASMIT_ASL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ROR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_AND && 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].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
int addr = mIns[i + 0].mAddress;
mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr));
mIns.Insert(i + 4, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, addr));
mIns[i + 0].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_A;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 4].mLive = mIns[i + 3].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() && mIns[i + 1].ChangesZFlag() &&
mIns[i + 2].mType == ASMIT_TXA && (mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
mIns[i + 2] = mIns[i + 0]; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_TAY &&
mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && (mIns[i + 2].mLive & LIVE_CPU_REG_X) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 2].mType, ASMIM_ABSOLUTE_X))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_X;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && (mIns[i + 2].mLive & LIVE_CPU_REG_X) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 2].mType, ASMIM_ABSOLUTE_X))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_X;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mMode = ASMIM_ABSOLUTE_X; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
mIns[i + 1].mType == ASMIT_STX &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
mIns[i + 1].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
mIns[i + 1].mType == ASMIT_STY &&
mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
mIns[i + 1].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
mIns[i + 1].mType == ASMIT_STA && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1], true) &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mFlags & NCIF_VOLATILE))
{
mIns[i + 0].mLive |= mIns[i + 2].mLive;
mIns[i + 1].mLive |= mIns[i + 2].mLive;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE) &&
mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE) &&
mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !(mIns[i + 1].ChangesYReg()) &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !(mIns[i + 1].ChangesXReg()) &&
mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM) &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && !mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 2].IsShift() && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
{
AsmInsType type = mIns[i + 2].mType;
uint32 live = mIns[i + 2].mLive;
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = mIns[i + 0];
mIns[i + 0].mType = type;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mLive |= live;
mIns[i + 1].mLive |= live;
mIns[i + 2].mLive |= live;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & LIVE_CPU_REG_A) &&
mIns[i + 2].mType == ASMIT_CPX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 2].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
{
mIns[i + 1] = mIns[i + 0];
mIns[i + 1].mType = ASMIT_CMP;
mIns[i + 1].mLive |= mIns[i + 2].mLive;
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && !mIns[i + 0].RequiresXReg() &&
mIns[i + 1].mType == ASMIT_LDX &&
mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X) && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 2]))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A | mIns[i + 2].mLive;
mIns[i + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= mIns[i + 2].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) &&
mIns[i + 2].mType == ASMIT_STA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 2]) &&
!mIns[i + 1].MayBeChangedOnAddress(mIns[i + 2]))
{
NativeCodeInstruction ins = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = mIns[i + 0];
mIns[i + 0] = ins;
mIns[i + 1].mType = ASMIT_LDA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | mIns[i + 0].mLive;
mIns[i + 2].mType = ASMIT_STA; mIns[i + 2].mLive |= mIns[i + 0].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_STX &&
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY &&
mIns[i + 1].mType == ASMIT_STY &&
mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
mIns[i + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesZFlag())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesZFlag())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 0x03) && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_ASL;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 0xc0) && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_LSR;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
mIns[i + 0].mAddress &= (mIns[i + 2].mAddress << 1) | 1;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
{
mIns[i + 0].mAddress &= (mIns[i + 2].mAddress >> 1) | 0x80;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 1].mType = ASMIT_AND; mIns[i + 1].mAddress = 1;
mIns[i + 0].mAddress &= (mIns[i + 2].mAddress << 1) | 1;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].ReferencesAccu() && (mIns[i + 1].mMode != ASMIM_ZERO_PAGE || mIns[i + 1].mAddress != mIns[i + 0].mAddress) &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
{
NativeCodeInstruction ins = mIns[i + 2];
mIns.Remove(i + 2);
mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i, ins);
return true;
}
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && (mIns[i + 0].mAddress & 0x3f) == 0x3f &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mAddress = (mIns[i + 1].mAddress << 1) & 0xff;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mType == ASMIT_INY &&
mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
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].mAddress += 2;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mType == ASMIT_INX &&
mIns[i + 2].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
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].mAddress += 2;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_STX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TAY &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 1].mType == ASMIT_INX || mIns[i + 1].mType == ASMIT_DEX) &&
mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 2].mType = mIns[i + 1].mType == ASMIT_INX ? ASMIT_INC : ASMIT_DEC;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 1].mType == ASMIT_INY || mIns[i + 1].mType == ASMIT_DEY) &&
mIns[i + 2].mType == ASMIT_STY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 2].mType = mIns[i + 1].mType == ASMIT_INY ? ASMIT_INC : ASMIT_DEC;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
(mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) &&
mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
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;
}
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_CPX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_CMP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].mType == ASMIT_CPY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_CMP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_DEX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_CPY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 1].mAddress &&
!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
{
mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].CopyMode(mIns[i + 0]); mIns[i + 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
mIns[i + 0].mType = ASMIT_TYA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress - mIns[i + 2].mAddress) & 0xff;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
!mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
{
NativeCodeInstruction ins(mIns[i + 2]);
mIns.Remove(i + 2);
mIns.Insert(i, ins);
mIns[i + 1].mLive |= ins.mLive & LIVE_CPU_REG_A;
mIns[i + 2].mLive |= ins.mLive & LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) &&
mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
!mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
{
NativeCodeInstruction ins(mIns[i + 2]);
mIns.Remove(i + 2);
mIns.Insert(i, ins);
mIns[i + 1].mLive |= ins.mLive & LIVE_CPU_REG_A;
mIns[i + 2].mLive |= ins.mLive & LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
(mIns[i + 1].mType == ASMIT_INC || mIns[i + 1].mType == ASMIT_DEC) &&
mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
mIns[i + 1].MayBeMovedBefore(mIns[i + 0]))
{
mIns.Insert(i, mIns[i + 1]);
mIns[i].mLive |= LIVE_CPU_REG_A;
if (mIns[i + 1].RequiresYReg())
mIns[i].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 1].RequiresXReg())
mIns[i].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
mIns.Remove(i + 2);
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 0].mMode == ASMIM_IMPLIED &&
(mIns[i + 1].mType == ASMIT_INX || mIns[i + 1].mType == ASMIT_DEX || mIns[i + 1].mType == ASMIT_INY || mIns[i + 1].mType == ASMIT_DEY) &&
mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
{
mIns[i + 2] = mIns[i + 0];
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
!(mIns[i + 0].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 0].mAddress || mIns[i + 1].mAddress + 1 == mIns[i + 0].mAddress)))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_CPX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_CPY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && !(mIns[i + 1].ReferencesYReg()) &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
{
mIns[i + 2] = mIns[i + 1];
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_TAY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 2].ReferencesXReg())
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].IsShift() && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 1 &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & LIVE_MEM))
{
int apos, breg, ireg;
if (FindAddressSumY(i, mIns[i + 2].mAddress, apos, breg, ireg))
{
int yoffset = mIns[i + 0].mAddress;
if (breg == mIns[i + 2].mAddress || ireg == mIns[i + 2].mAddress)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i + 2, yoffset);
int ypos = i;
if (mIns[i + 1].mMode != ASMIM_INDIRECT_Y && mIns[i + 1].mMode != ASMIM_ABSOLUTE_Y)
{
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = ireg;
mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 2].mAddress = breg;
}
else
{
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
mIns[i + 2].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
ypos = i + 2;
mIns[i + 3].mAddress = breg;
}
if (yoffset == 1)
{
mIns.Insert(ypos + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_INY, ASMIM_IMPLIED));
mIns[ypos + 1].mLive = mIns[ypos].mLive;
}
CheckLive();
return true;
}
}
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
const NativeCodeInstruction* ains;
if (FindImmediateStore(i, mIns[i + 2].mAddress + 1, ains))
{
mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 2].mAddress));
mIns[i + 2].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_X;
mIns[i + 3].mMode = ASMIM_ABSOLUTE_X;
if (ains->mMode == ASMIM_IMMEDIATE)
mIns[i + 3].mAddress = (ains->mAddress << 8) + mIns[i + 0].mAddress;
else
{
mIns[i + 3].mLinkerObject = ains->mLinkerObject;
mIns[i + 3].mAddress = mIns[i + 0].mAddress + ains->mAddress;
mIns[i + 3].mFlags |= NCIF_UPPER;
mIns[i + 3].mFlags &= ~NCIF_LOWER;
}
CheckLive();
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate4(int i, int pass)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_INC; mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_DEC; mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 0].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INC; mIns[i + 1].mLive |= LIVE_MEM;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 0].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEC; mIns[i + 1].mLive |= LIVE_MEM;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_DEC; mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_INC; mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 0].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEC; mIns[i + 1].mLive |= LIVE_MEM;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 0].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INC; mIns[i + 1].mLive |= LIVE_MEM;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC)
{
mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 2].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_CMP && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 3].CopyMode(mIns[i + 0]);
if (mIns[i + 3].RequiresYReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
else if (mIns[i + 3].RequiresXReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
}
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == mIns[i + 1].mType && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].UsesZeroPage(mIns[i + 3].mAddress))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 3].mAddress));
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress)
{
mIns[i + 2].mType = mIns[i + 3].mType;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && mIns[i + 3].mMode != ASMIM_IMMEDIATE)
{
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_ORA; mIns[i + 2].mLive |= mIns[i + 3].mLive & LIVE_CPU_REG_Z;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
(mIns[i + 2].mType == ASMIT_SEC || mIns[i + 2].mType == ASMIT_CLC) &&
mIns[i + 3].mType == ASMIT_ADC)
{
mIns.Insert(i + 4, mIns[i + 0]);
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 + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_C;
mIns[i + 4].mType = ASMIT_SBC; mIns[i + 4].mLive |= LIVE_CPU_REG_C;
if (mIns[i + 4].RequiresYReg())
{
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 4].RequiresXReg())
{
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mLive |= LIVE_CPU_REG_X;
}
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
mIns[i + 2].mType == ASMIT_SEC &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 0].mType = ASMIT_EOR;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xff;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 3].mAddress = mIns[i + 1].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 2].mAddress &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 0].mType = ASMIT_EOR;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xff;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 3].mAddress = mIns[i + 2].mAddress;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 2].mAddress || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 3].CopyMode(mIns[i + 1]);
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_ADC &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mAddress += mIns[i + 3].mAddress;
mIns[i + 1].mLive |= (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x00 &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x01)
{
mIns[i + 1].mAddress = 0x00;
mIns[i + 1].mLive |= (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
(mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
{
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_SEC;
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mType = ASMIT_ROL;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & LIVE_MEM) &&
(mIns[i + 2].mType == ASMIT_ASL || mIns[i + 2].mType == ASMIT_LSR || mIns[i + 2].mType == ASMIT_ROL || mIns[i + 2].mType == ASMIT_ROR) &&
(mIns[i + 3].mType == ASMIT_ORA || mIns[i + 3].mType == ASMIT_AND || mIns[i + 3].mType == ASMIT_EOR || mIns[i + 3].mType == ASMIT_ADC || mIns[i + 3].mType == ASMIT_SBC))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 3].mMode = mIns[i + 0].mMode;
mIns[i + 3].mAddress = mIns[i + 0].mAddress;
mIns[i + 3].mLinkerObject = mIns[i + 0].mLinkerObject;
mIns[i + 3].mFlags = mIns[i + 0].mFlags;
if (mIns[i + 3].RequiresYReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 3].RequiresXReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
}
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_EOR && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | 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;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_INY;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_DEY;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_INX;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_DEX;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_INX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
mIns[i + 3].mType = ASMIT_TXA;
else
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 0xfe)
mIns[i + 2].mType = ASMIT_DEX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
mIns[i + 3].mType = ASMIT_TXA;
else
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_DEX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
mIns[i + 3].mType = ASMIT_TXA;
else
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_INY;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 0xfe)
mIns[i + 2].mType = ASMIT_DEY;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
mIns[i + 3].mType = ASMIT_TYA;
else
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 3].mType = ASMIT_DEY;
else
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_INX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_DEX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
{
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_DEY;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_STY;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_STX;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) &&
mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDX;
mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 2].mMode) &&
mIns[i + 3].mType == ASMIT_TYA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDY;
mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_LDA, mIns[i + 1].mMode) &&
mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) &&
mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x00 && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = mIns[i + 1].mType;
mIns[i + 0].mLive |= LIVE_MEM | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_INX &&
mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_INC;
mIns[i + 3].mType = ASMIT_INC;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_DEX && mIns[i + 2].mType == ASMIT_DEX &&
mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_DEC;
mIns[i + 3].mType = ASMIT_DEC;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_INC;
mIns[i + 3].mType = ASMIT_INC;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 10 &&
mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_DEC;
mIns[i + 3].mType = ASMIT_DEC;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 1].ChangesYReg() || mIns[i + 1].mMode == ASMIM_INDIRECT_Y || mIns[i + 1].RequiresXReg()) &&
mIns[i + 2].mType == ASMIT_TYA &&
mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y)))
{
mIns[i + 0].mType = ASMIT_LDX;
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].ReplaceYRegWithXReg();
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_LDA && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress) &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 3] = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1].mType = mIns[i + 0].mType;
mIns[i + 0].mType = ASMIT_LDA;
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_LDA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 0].mType = ASMIT_EOR;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xff;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_ADC;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress < 4 &&
mIns[i + 2].mType == ASMIT_TAX &&
mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
{
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 + 3].mAddress += mIns[i + 1].mAddress;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_SEC;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_SBC &&
mIns[i + 2].mType == ASMIT_SEC &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_CLC;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
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 + 3].mAddress = (mIns[i + 3].mAddress - mIns[i + 1].mAddress) & 0xff;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
int val = mIns[i + 2].mAddress;
mIns[i + 0].mType = ASMIT_SEC;
mIns[i + 2].CopyMode(mIns[i + 1]);
mIns[i + 2].mType = ASMIT_SBC;
mIns[i + 1].mMode = ASMIM_IMMEDIATE;
mIns[i + 1].mAddress = -(1 + val) & 255;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x40 &&
mIns[i + 2].mType == ASMIT_SEC &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x40 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_CMP;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0x80;
mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_ROR;
mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC)
{
mIns[i + 0].mAddress = 0xff;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 0].mLinkerObject != mIns[i + 2].mLinkerObject &&
mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
int val = mIns[i + 2].mAddress;
mIns[i + 3].mType = ASMIT_LDA;
mIns[i + 3].CopyMode(mIns[i + 0]);
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress)
{
int addr = mIns[i + 0].mAddress;
mIns[i + 0].mAddress = mIns[i + 2].mAddress;
mIns[i + 3].mAddress = mIns[i + 1].mAddress;
mIns[i + 2].mAddress = addr;
mIns[i + 2].mType = ASMIT_LDX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]) &&
mIns[i + 3].mType == ASMIT_CMP && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 3].mAddress = mIns[i + 2].mAddress;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED && HasAsmInstructionMode(ASMIT_ROL, mIns[i + 0].mMode) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
{
mIns[i + 2].CopyMode(mIns[i + 0]);
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && !(mIns[i + 0].mLive & LIVE_CPU_REG_A) &&
!mIns[i + 1].ReferencesAccu() && !mIns[i + 0].MayBeSameAddress(mIns[i + 1]) &&
!mIns[i + 2].ReferencesAccu() && !mIns[i + 0].MayBeSameAddress(mIns[i + 2]) &&
mIns[i + 3].IsShift() && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
NativeCodeInstruction ins = mIns[i + 0];
mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1] = mIns[i + 2]; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3] = ins; mIns[i + 3].mLive |= mIns[i + 2].mLive;
return true;
}
else if (
mIns[i + 0].IsShift() && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_MEM) &&
!mIns[i + 1].ChangesCarry() && !mIns[i + 2].ChangesCarry() &&
!mIns[i + 1].RequiresCarry() && !mIns[i + 2].RequiresCarry() &&
!mIns[i + 1].MayBeSameAddress(mIns[i + 0]) && !mIns[i + 2].MayBeSameAddress(mIns[i + 0]))
{
mIns.Insert(i + 4, NativeCodeInstruction(mIns[i + 0].mIns, mIns[i + 0].mType, ASMIM_IMPLIED));
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mLive |= LIVE_CPU_REG_C;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
if (!(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
}
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
if (!(mIns[i + 3].mLive & LIVE_MEM))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
}
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STY &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
mIns[i + 3].CopyMode(mIns[i + 2]);
mIns[i + 2].mType = ASMIT_TYA;
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STX &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
mIns[i + 3].CopyMode(mIns[i + 2]);
mIns[i + 2].mType = ASMIT_TXA;
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0xff &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC &&
mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
{
mIns[i + 1].mType = ASMIT_SEC;
mIns[i + 2].mType = ASMIT_SBC;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX &&
mIns[i + 1].mType == ASMIT_DEX &&
mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_DEC;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mLive = mIns[i + 3].mLive;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_CMP && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_CMP; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_A) &&
!mIns[i + 1].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].ChangesCarry() &&
!mIns[i + 2].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 2].ChangesCarry() &&
mIns[i + 3].IsShift() && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
AsmInsType type = mIns[i + 3].mType;
mIns[i + 3] = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = mIns[i + 0];
mIns[i + 0] = NativeCodeInstruction(mIns[i + 0].mIns, type);
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mLive |= LIVE_CPU_REG_C;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].MayBeMovedBefore(mIns[i + 1]) && mIns[i + 2].MayBeMovedBefore(mIns[i + 0]) &&
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0)
{
NativeCodeInstruction ins(mIns[i + 2]);
mIns.Remove(i + 2);
mIns.Insert(i, ins);
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= mIns[i + 3].mLive;
mIns[i + 2].mLive |= mIns[i + 3].mLive;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].ChangesAccuAndFlag() &&
(mIns[i + 1].mType == ASMIT_LDY && !mIns[i + 0].RequiresYReg() ||
mIns[i + 1].mType == ASMIT_LDX && !mIns[i + 0].RequiresXReg()) &&
mIns[i + 2].mType == ASMIT_STA &&
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0)
{
NativeCodeInstruction ins(mIns[i + 1]);
mIns.Remove(i + 1);
mIns.Insert(i, ins);
mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= mIns[i + 3].mLive | mIns[i + 0].mLive;
mIns[i + 2].mLive |= mIns[i + 3].mLive;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_TXA &&
mIns[i + 3].IsCommutative() && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress)
{
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mAddress = mIns[i + 0].mAddress;
return true;
}
if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 2].mType == ASMIT_LDX && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) && !mIns[i + 1].ChangesYReg() &&
mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
{
if (!(mIns[i + 3].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_X))
{
mIns[i + 0].mType = ASMIT_LDX;
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (!(mIns[i + 3].mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(mIns[i + 3].mType, ASMIM_ABSOLUTE_Y))
{
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mMode = ASMIM_ABSOLUTE_Y;
return true;
}
}
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
!mIns[i + 2].ChangesYReg() && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
{
int apos, breg, ireg;
if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
{
if (breg == mIns[i + 1].mAddress || ireg == mIns[i + 1].mAddress)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i + 3, 0);
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = ireg;
mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mAddress = breg;
mIns[i + 3].mAddress = breg;
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate5(int i, int pass)
{
if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_LDA)
{
// Flip arguments of ADC if second parameter in accu at entry
mIns[i + 3].CopyMode(mIns[i + 2]);
mIns[i + 2].CopyMode(mIns[i + 0]);
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_LDA)
{
// change sbc to adc to reverse order
mIns[i + 3].CopyMode(mIns[i + 2]);
mIns[i + 2].mType = ASMIT_EOR; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff;
mIns[i + 3].mType = ASMIT_ADC;
if (mIns[i + 3].ReferencesYReg())
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 3].ReferencesXReg())
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
mIns[i + 2].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_LDA)
{
// change sbc to adc to reverse order
mIns[i + 3].CopyMode(mIns[i + 1]);
mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mMode = ASMIM_IMMEDIATE; mIns[i + 1].mAddress = 0xff;
mIns[i + 3].mType = ASMIT_ADC;
if (mIns[i + 3].ReferencesYReg())
{
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 3].ReferencesXReg())
{
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress == 1 || mIns[i + 2].mAddress == 2) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mType = ASMIT_NOP;
if (mIns[i + 2].mAddress == 2)
{
mIns.Insert(i + 3, mIns[i + 2]);
}
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_SEC &&
mIns[i + 3].mType == ASMIT_LDA && !mIns[i + 3].UsesZeroPage(mIns[i + 1].mAddress) &&
mIns[i + 4].mType == ASMIT_SBC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & LIVE_MEM))
{
mIns[i + 4].CopyMode(mIns[i + 0]);
if (mIns[i + 4].RequiresYReg())
{
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 4].RequiresXReg())
{
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
!mIns[i + 1].ChangesAccu() &&
mIns[i + 2].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_CLC &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress)
{
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 3].CopyMode(mIns[i + 2]);
mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= mIns[i + 1].mLive;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 4].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_ROR; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mAddress = 0x80; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_STA;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_SBC &&
mIns[i + 3].mType == ASMIT_CLC &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
!(mIns[i + 4].mLive & LIVE_CPU_REG_C))
{
mIns[i + 1].mAddress = (mIns[i + 1].mAddress + mIns[i + 4].mAddress) & 255;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].IsCommutative() && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == mIns[i + 0].mAddress)
{
int addr = mIns[i + 1].mAddress;
mIns[i + 1].mAddress = mIns[i + 3].mAddress;
mIns[i + 3].mAddress = addr;
mIns[i + 0].mAddress = mIns[i + 2].mAddress;
mIns[i + 2].mAddress = mIns[i + 4].mAddress;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
!mIns[i + 2].ChangesYReg() && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress) &&
!mIns[i + 3].ChangesYReg() && (mIns[i + 3].mMode == ASMIM_IMMEDIATE || mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 1].mAddress) &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mAddress == mIns[i + 4].mAddress && !(mIns[i + 4].mLive & LIVE_MEM))
{
int apos, breg, ireg;
if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
{
if (breg == mIns[i + 1].mAddress)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i + 4, 0);
mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = ireg;
mIns[i + 0].mLive |= LIVE_MEM;
mIns[i + 1].mAddress = breg;
mIns[i + 4].mAddress = breg;
return true;
}
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress == 1 || mIns[i + 2].mAddress == 2) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (!(mIns[i + 4].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_INX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
mIns[i + 4].mType = ASMIT_STX;
return true;
}
else if (!(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_INY;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mType = ASMIT_STY;
return true;
}
}
else if (
mIns[i + 0].mType == ASMIT_SEC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress == 1 || mIns[i + 2].mAddress == 2) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (!(mIns[i + 4].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_DEX;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
mIns[i + 4].mType = ASMIT_STX;
return true;
}
else if (!(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
if (mIns[i + 2].mAddress == 2)
mIns[i + 2].mType = ASMIT_DEY;
else
mIns[i + 2].mType = ASMIT_NOP;
mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mType = ASMIT_STY;
return true;
}
}
else if (
pass > 2 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && !mIns[i + 3].MayBeSameAddress(mIns[i + 1]) && !mIns[i + 3].RequiresYReg() &&
mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mType = ASMIT_DEY; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 1].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
!mIns[i + 0].ReferencesZeroPage(mIns[i + 3].mAddress) &&
!mIns[i + 2].ReferencesZeroPage(mIns[i + 1].mAddress) &&
!(mIns[i + 0].mFlags & NCIF_VOLATILE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE))
{
NativeCodeInstruction ins(mIns[i + 0]);
mIns[i + 0] = mIns[i + 2];
mIns[i + 2] = ins;
mIns[i + 1].mAddress = mIns[i + 3].mAddress;
mIns[i + 3].mAddress = mIns[i + 4].mAddress;
if (mIns[i + 2].RequiresYReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 2].RequiresXReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 0].mLive |= mIns[i + 2].mLive;
mIns[i + 2].mLive |= mIns[i + 4].mLive;
mIns[i + 3].mLive |= mIns[i + 4].mLive;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAY &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_TYA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].CopyMode(mIns[i + 3]);
mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_TXA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].CopyMode(mIns[i + 3]);
mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
(mIns[i + 1].mType == ASMIT_TAY || mIns[i + 1].mType == ASMIT_TAX) &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
if (mIns[i + 1].mType == ASMIT_TAY)
{
mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
}
else
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
}
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mIns[i + 3].mAddress == 0x01)
mIns[i + 4].mType = ASMIT_INC;
else
mIns[i + 4].mType = ASMIT_DEC;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mIns[i + 3].mAddress == 0x01)
mIns[i + 4].mType = ASMIT_INC;
else
mIns[i + 4].mType = ASMIT_DEC;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mIns[i + 3].mAddress == 0x01)
mIns[i + 4].mType = ASMIT_INC;
else
mIns[i + 4].mType = ASMIT_DEC;
return true;
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate4b(int i, int pass)
{
if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mType == ASMIT_TYA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 3].mAddress++;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_TAY &&
mIns[i + 3].mType == ASMIT_INY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 1].mAddress++;
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 3].mAddress++;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_TAX &&
mIns[i + 3].mType == ASMIT_INX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 1].mAddress++;
mIns[i + 3].mType = ASMIT_NOP;
return true;
}
else if (pass > 8 &&
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) < 4 &&
mIns[i + 3].mType == ASMIT_TAY &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
int n = mIns[i + 2].mAddress & 0xff;
for (int k = 0; k < n; k++)
{
mIns[i + k].mType = ASMIT_INY; mIns[i + k].mMode = ASMIM_IMPLIED; mIns[i + k].mLive |= LIVE_CPU_REG_Y;
}
for (int k = n; k < 4; k++)
{
mIns[i + k].mType = ASMIT_NOP; mIns[i + k].mMode = ASMIM_IMPLIED;
}
return true;
}
else if (pass > 8 &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) < 4 &&
mIns[i + 3].mType == ASMIT_TAX &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
int n = mIns[i + 2].mAddress & 0xff;
for (int k = 0; k < n; k++)
{
mIns[i + k].mType = ASMIT_INX; mIns[i + k].mMode = ASMIM_IMPLIED; mIns[i + k].mLive |= LIVE_CPU_REG_X;
}
for (int k = n; k < 4; k++)
{
mIns[i + k].mType = ASMIT_NOP; mIns[i + k].mMode = ASMIM_IMPLIED;
}
return true;
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate5b(int i, int pass)
{
if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode != ASMIM_ABSOLUTE_X &&
mIns[i + 3].mType == ASMIT_TXA &&
mIns[i + 4].mType == ASMIT_STA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{
mIns[i + 0] = mIns[i + 4];
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_INC;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_DEC;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
mIns[i + 4].mType == ASMIT_STA && (mIns[i + 4].mMode == ASMIM_ZERO_PAGE || mIns[i + 4].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_STX; mIns[i + 4].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 5, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
return true;
}
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress != mIns[i + 0].mAddress &&
!(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
int a0 = mIns[i + 0].mAddress;
int a1 = mIns[i + 4].mAddress;
mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, a1));
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, a0));
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mMode = ASMIM_ZERO_PAGE; mIns[i + 5].mAddress = a1;
mIns[i + 6].mAddress = a0;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mType = ASMIT_ROR;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress <= 2 &&
mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mIns[i + 3].mAddress > 1)
mIns[i + 4].mType = ASMIT_INY;
else
mIns[i + 4].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode))
{
mIns[i + 4].mType = ASMIT_INC;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 255 &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode))
{
mIns[i + 4].mType = ASMIT_DEC;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
return true;
}
else if (
pass > 8 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_CLC &&
mIns[i + 4].mType == ASMIT_ADC &&
!(mIns[i + 4].mLive & LIVE_CPU_REG_C))
{
mIns[i + 3].mType = ASMIT_SEC;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
mIns[i + 4].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
!(mIns[i + 4].mLive & LIVE_CPU_REG_A))
{
mIns.Insert(i + 5, mIns[i + 0]);
mIns.Remove(i);
mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mLive |= mIns[i + 3].mLive;
return true;
}
#if 0
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
{
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_LDX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mMode = ASMIM_ABSOLUTE_X; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
#endif
if (pass > 2)
{
if (
mIns[i + 0].mType == ASMIT_INY &&
mIns[i + 1].mType == ASMIT_INY &&
mIns[i + 2].mType == ASMIT_INY &&
mIns[i + 3].mType == ASMIT_INY &&
mIns[i + 4].mType == ASMIT_INY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TYA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_CLC; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 5; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_TAY;
mIns[i + 4].mType = ASMIT_NOP;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_INX &&
mIns[i + 1].mType == ASMIT_INX &&
mIns[i + 2].mType == ASMIT_INX &&
mIns[i + 3].mType == ASMIT_INX &&
mIns[i + 4].mType == ASMIT_INX && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mType = ASMIT_CLC; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 5; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
mIns[i + 3].mType = ASMIT_TAX;
mIns[i + 4].mType = ASMIT_NOP;
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate6(int i, int pass)
{
if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
mIns[i + 3].mType == ASMIT_TXA &&
mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress == mIns[i + 5].mAddress &&
!(mIns[i + 5].mFlags & NCIF_VOLATILE) && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 3] = mIns[i + 0];
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED;
int a = mIns[i + 1].mAddress; mIns[i + 1].mAddress = mIns[i + 4].mAddress; mIns[i + 4].mAddress = a;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && !mIns[i + 0].RequiresYReg() &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 1]) &&
mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && mIns[i + 4].mAddress != mIns[i + 1].mAddress && mIns[i + 4].mAddress != mIns[i + 1].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 5].mLive & LIVE_MEM) &&
!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 4]))
{
mIns[i + 5] = mIns[i + 0];
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 1 &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_CLC &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress && !(mIns[i + 5].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_LSR; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mType = ASMIT_ROL;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
return true;
}
else if (pass > 0 &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
mIns[i + 3].IsShift() && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].IsShift() && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mAddress == mIns[i + 0].mAddress && !(mIns[i + 5].mLive & LIVE_CPU_REG_A) &&
mIns[i + 5].mAddress != mIns[i + 1].mAddress && mIns[i + 5].mAddress != mIns[i + 3].mAddress)
{
mIns[i + 2].CopyMode(mIns[i + 0]); mIns[i + 2].mLive |= LIVE_MEM;
mIns[i + 4].CopyMode(mIns[i + 0]); mIns[i + 4].mLive |= LIVE_MEM;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
return true;
}
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 3].mFlags & NCIF_UPPER) && (mIns[i + 3].mLinkerObject == mIns[i + 1].mLinkerObject) &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
{
assert(mIns[i + 3].mAddress == mIns[i + 1].mAddress);
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 + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress + mIns[i + 4].mAddress * 256))
return true;
}
}
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
{
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 + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, mIns[i + 1].mAddress + (mIns[i + 3].mAddress + mIns[i + 4].mAddress) * 256))
return true;
}
}
else if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
{
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, 256 * mIns[i + 3].mAddress))
return true;
}
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterateN(int i, int pass)
{
if (i + 5 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_INY && mIns[i + 3].mType == ASMIT_DEY &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y &&
!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
{
if (mIns[i + 5].mType == ASMIT_TAX)
{
if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 4].mAddress && mIns[i + 2].mAddress != mIns[i + 4].mAddress + 1)
{
mIns[i + 5] = mIns[i + 2];
mIns[i + 2].mType = ASMIT_TAX; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mLive |= LIVE_CPU_REG_X;
mIns[i + 4].mLive |= LIVE_CPU_REG_X;
mIns[i + 5].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_INY;
mIns.Insert(i + 6, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_DEY));
return true;
}
}
}
if (i + 7 < mIns.Size() && pass > 3 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 6].mType == ASMIT_LDY && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
mIns[i + 7].mMode == ASMIM_INDIRECT_Y && mIns[i + 7].mAddress == mIns[i + 2].mAddress && !(mIns[i + 7].mLive & LIVE_MEM))
{
int total = mIns[i + 1].mAddress + mIns[i + 6].mAddress + 256 * mIns[i + 4].mAddress;
if (!(mIns[i + 7].mLive & LIVE_CPU_REG_Y) || !(mIns[i + 7].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i + 7].mLive & LIVE_CPU_REG_Y)
mIns.Insert(i + 8, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[i + 6].mAddress));
mIns[i + 6].mAddress = total & 255;
mIns[i + 4].mAddress = total >> 8;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
}
if (i + 6 < mIns.Size())
{
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 1].mAddress = mIns[i + 4].mAddress = mIns[i + 1].mAddress + mIns[i + 2].mAddress + 256 * mIns[i + 5].mAddress;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 1].mAddress &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
mIns[i + 1].mAddress = mIns[i + 5].mAddress = mIns[i + 1].mAddress + mIns[i + 2].mAddress + 256 * mIns[i + 4].mAddress;
mIns[i + 5].mType = ASMIT_LDA;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
return true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 1 &&
mIns[i + 5].mType == ASMIT_CLC &&
mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress && !(mIns[i + 6].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
{
int addr = mIns[i + 0].mAddress;
mIns[i + 0].mAddress = mIns[i + 3].mAddress;
mIns[i + 3].mAddress = addr;
mIns[i + 1].mType = ASMIT_LSR; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mLive |= LIVE_CPU_REG_C;
mIns[i + 5].mType = ASMIT_ROL;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
return true;
}
#if 1
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_ADC &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
{
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_LDA;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress + mIns[i + 5].mAddress * 256))
return true;
}
else if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress)
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1))
{
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress + mIns[i + 5].mAddress * 256))
return true;
}
}
}
#endif
#if 1
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 2].mFlags & NCIF_LOWER) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 2].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 2].mAddress &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 4].mAddress * 256))
return true;
}
else if (mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 3].mAddress)
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, i + 7, -1))
{
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, i + 7, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 4].mAddress * 256))
return true;
}
}
}
#endif
#if 1
if (pass == 0 && i + 7 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 0].mFlags & NCIF_LOWER) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 0].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 4].mAddress + 1 &&
!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 4].mAddress, mIns[i + 4].mAddress, i + 8, mIns[i + 2].mAddress))
{
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 + 3].mType = ASMIT_LDA;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 4].mAddress, mIns[i + 4].mAddress, i + 8, mIns[i + 2].mAddress, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress + mIns[i + 6].mAddress * 256))
return true;
}
}
#endif
#if 1
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_ADC &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
{
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_LDA;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, nullptr, mIns[i + 1].mAddress + 256 * mIns[i + 4].mAddress + mIns[i + 5].mAddress * 25))
return true;
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 2].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 5].mAddress &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (pass == 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 3].mFlags & NCIF_UPPER) && (mIns[i + 3].mLinkerObject == mIns[i + 1].mLinkerObject) &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 4].mAddress &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
bool subs1 = mIns[i + 3].mAddress != mIns[i + 1].mAddress;
bool subs2 = mIns[i + 3].mAddress != mIns[i + 2].mAddress;
if (subs1 && subs2)
{
if (mLoopHead)
{
if (ChangesZeroPage(mIns[i + 1].mAddress))
subs2 = false;
else if (ChangesZeroPage(mIns[i + 2].mAddress))
subs1 = false;
}
}
mProc->ResetPatched();
if (subs1 && CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_LDA;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
else if (subs2)
{
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && /*mIns[i + 3].mAddress != mIns[i + 1].mAddress && mIns[i + 3].mAddress != mIns[i + 2].mAddress && */
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval))
{
if (mIns[i + 3].mAddress == mIns[i + 1].mAddress || mIns[i + 3].mAddress == mIns[i + 2].mAddress)
{
for (int j = 0; j < 7; j++)
{
mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
}
}
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 2].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
else if (mIns[i + 3].mAddress != mIns[i + 1].mAddress)
{
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 3], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 3], i + 7, yval))
{
mIns[i + 1].CopyMode(mIns[i + 2]);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
}
#endif
#if 1
if (
mIns[i + 0].mType == ASMIT_STA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval))
{
if (mIns[i + 3].mAddress == mIns[i + 2].mAddress)
{
for (int j = 1; j < 7; j++)
{
mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
}
}
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
mIns[i + 2].mAddress != mIns[i + 3].mAddress &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
mIns[i + 3].mAddress != BC_REG_STACK &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 2].mAddress != BC_REG_STACK &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 && !(mIns[i + 3].mLive & LIVE_MEM) &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 5].mAddress = mIns[i + 3].mAddress;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 3))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1)
{
int yval = RetrieveYValue(i);
int reg = FindFreeAccu(i);
if (reg >= 0)
{
NativeCodeInstruction iins(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval, 3))
{
mIns[i + 0] = iins;
for (int j = 1; j < 6; j++)
{
mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
}
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval))
{
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
}
#endif
#if 1
if (
mLoopHead &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_LDA &&
mIns[i + 4].mType == ASMIT_ADC &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
{
mProc->ResetPatched();
if (PatchForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
{
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
{
int j = i + 5;
while (j < mIns.Size() && !mIns[j].ChangesYReg())
j++;
if (j < mIns.Size() && mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE && mIns[j].mAddress == mIns[i + 0].mAddress)
{
int reg = mIns[i + 1].mAddress; mIns[i + 1].mAddress = mIns[i + 4].mAddress; mIns[i + 4].mAddress = reg;
int yr = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 3].mAddress; mIns[i + 3].mAddress = yr;
mIns[i + 1].mLive |= LIVE_MEM;
mIns[i + 4].mLive |= LIVE_MEM;
mIns[j].mType = ASMIT_NOP; mIns[j].mMode = ASMIM_IMPLIED;
while (j > i)
{
j--;
mIns[j].mLive |= LIVE_CPU_REG_Y;
}
return true;
}
}
#endif
}
#if 1
if (i + 7 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_CLC &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 3].mAddress &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress != mIns[i + 0].mAddress &&
mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 7].mAddress &&
!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
{
int yval = RetrieveYValue(i);
mProc->ResetPatched();
if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 8, yval, 0))
{
mProc->ResetPatched();
if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 8, yval))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return true;
}
}
}
#endif
#if 1
if (pass == 0 &&
i + 7 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && (mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject) &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 8, -1))
{
NativeCodeInstruction ins(mIns[i + 2]);
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = ins;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
return true;
}
else
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 8, -1))
{
NativeCodeInstruction ins(mIns[i + 3]);
mIns[i + 3] = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = ins;
mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
return true;
}
}
}
if (pass == 0 &&
i + 8 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && (mIns[i + 5].mLinkerObject == mIns[i + 1].mLinkerObject) &&
mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 3].mAddress + 1 &&
mIns[i + 8].mType == ASMIT_STA && mIns[i + 8].mMode == ASMIM_ZERO_PAGE && mIns[i + 8].mAddress == mIns[i + 4].mAddress + 1 &&
!(mIns[i + 8].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 9, -1))
{
NativeCodeInstruction ins(mIns[i + 3]);
mIns[i + 3] = mIns[i + 1];
mIns[i + 1] = mIns[i + 2];
mIns[i + 2] = ins;
mIns[i + 1].mType = ASMIT_LDA;
mIns[i + 3].mType = ASMIT_ADC;
mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 9, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress + mIns[i + 6].mAddress * 256))
return true;
}
#if 0
else
{
proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 8, -1))
{
NativeCodeInstruction ins(mIns[i + 3]);
mIns[i + 3] = mIns[i + 2];
mIns[i + 2] = mIns[i + 1];
mIns[i + 1] = ins;
mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
progress = true;
}
}
#endif
}
#endif
if (i + 5 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED &&
mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_LSR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].mMode == ASMIM_IMPLIED && !(mIns[i + 5].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
mIns[i + 2].mType = ASMIT_ROL;
mIns[i + 3].mType = ASMIT_NOP;
mIns[i + 4].mType = ASMIT_NOP;
mIns[i + 5].mType = ASMIT_AND; mIns[i + 5].mMode = ASMIM_IMMEDIATE; mIns[i + 5].mAddress = 3;
return true;
}
if (i + 6 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_TXA &&
mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_MEM) &&
mIns[i + 5].mType == ASMIT_LDY && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress != mIns[i + 5].mAddress &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_INDIRECT_Y && mIns[i + 3].mAddress == mIns[i + 6].mAddress && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{
int t = mIns[i + 5].mAddress;
mIns[i + 5].mAddress = mIns[i + 2].mAddress;
mIns[i + 2].mAddress = t;
mIns[i + 4] = mIns[i + 1];
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].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mLive |= LIVE_CPU_REG_X;
return true;
}
if (i + 9 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 4].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) &&
mIns[i + 6].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 8].mLive & LIVE_MEM) &&
mIns[i + 9].mType == ASMIT_STA && mIns[i + 9].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 9].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_LSR; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_ROR;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].CopyMode(mIns[i + 0]);
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mIns[i + 7].mType = ASMIT_ROR;
mIns[i + 8].mType = ASMIT_NOP; mIns[i + 8].mMode = ASMIM_IMPLIED;
mIns[i + 9].mType = ASMIT_NOP; mIns[i + 9].mMode = ASMIM_IMPLIED;
return true;
}
if (i + 9 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 4].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) &&
mIns[i + 6].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_IMPLIED &&
mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].SameEffectiveAddress(mIns[i + 3]) &&
mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 8].mLive & LIVE_MEM) &&
mIns[i + 9].mType == ASMIT_STA && mIns[i + 9].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 9].mLive & LIVE_CPU_REG_A))
{
mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_ROL;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].CopyMode(mIns[i + 0]);
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
mIns[i + 7].mType = ASMIT_ROL;
mIns[i + 8].mType = ASMIT_NOP; mIns[i + 8].mMode = ASMIM_IMPLIED;
mIns[i + 9].mType = ASMIT_NOP; mIns[i + 9].mMode = ASMIM_IMPLIED;
return true;
}
return false;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerIterate(int pass)
{
bool changed = false;
bool progress = false;
do {
progress = false;
mIns.Reserve(mIns.Size() * 2 + 32);
if (RemoveNops())
changed = true;
CheckLive();
// Replace (a & 0x80) != 0 with bpl/bmi
int sz = mIns.Size();
if (sz > 1 &&
mIns[sz - 2].ChangesAccuAndFlag() &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (mBranch == ASMIT_BEQ)
{
mBranch = ASMIT_BPL;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
changed = true;
}
else if (mBranch == ASMIT_BNE)
{
mBranch = ASMIT_BMI;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (sz > 4 &&
mIns[sz - 4].mType == ASMIT_ASL && mIns[sz - 4].mMode == ASMIM_IMPLIED &&
mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
mIns[sz - 1].mType == ASMIT_EOR && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0xff && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
{
if (mBranch == ASMIT_BEQ)
{
mBranch = ASMIT_BPL;
mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0;
changed = true;
}
else if (mBranch == ASMIT_BNE)
{
mBranch = ASMIT_BMI;
mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0;
changed = true;
}
}
if (sz > 2 &&
mIns[sz - 3].mType == ASMIT_STA &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 3]) && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
{
if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff)
{
mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
mIns[sz - 1].mAddress = mIns[sz - 2].mAddress + 1;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_BCS;
changed = true;
}
else if (mBranch == ASMIT_BCS && mIns[sz - 2].mAddress < 0xff)
{
mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
mIns[sz - 1].mAddress = mIns[sz - 2].mAddress + 1;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_BCC;
changed = true;
}
}
for (int i = 0; i < mIns.Size(); i++)
{
if (PeepHoleOptimizerIterate1(i, pass)) progress = true;
if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO))
{
const NativeCodeInstruction* ains, * iins;
int sreg = mIns[i + 0].mAddress;
int apos, breg, ireg, addr;
uint32 flags;
if (FindAddressSumY(i, sreg, apos, breg, ireg))
{
if (!(breg == sreg || ireg == sreg) || !(mIns[i + 0].mLive & LIVE_MEM))
{
if (breg == sreg || ireg == sreg)
{
mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
}
RepairLoadYImmediate(i, 0);
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
mIns[i + 1].mAddress = breg;
mIns[i + 1].mFlags &= ~NCIF_YZERO;
progress = true;
CheckLive();
}
}
else if (FindGlobalAddressSumY(i, sreg, true, apos, ains, iins, flags, addr))
{
if (iins || (flags & LIVE_CPU_REG_Y) || (flags & LIVE_CPU_REG_X)) //!(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
RepairLoadYImmediate(i, 0);
if (flags & LIVE_CPU_REG_Y)
{
mIns[i + 0].mMode = ASMIM_ABSOLUTE_Y;
}
else if (flags & LIVE_CPU_REG_X)
{
mIns[i + 0].mMode = ASMIM_ABSOLUTE_X;
}
else
{
mIns[i + 0].mMode = ASMIM_ABSOLUTE_Y;
}
if (ains->mMode == ASMIM_IMMEDIATE)
{
mIns[i + 0].mLinkerObject = nullptr;
mIns[i + 0].mAddress = addr;
}
else
{
mIns[i + 0].mLinkerObject = ains->mLinkerObject;
mIns[i + 0].mAddress = ains->mAddress;
}
mIns[i + 0].mFlags &= ~NCIF_YZERO;
if (!iins)
{
if (flags & LIVE_CPU_REG_Y)
{
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
for (int j = apos; j < i + 1; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
}
else
{
PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX, ASMIM_IMPLIED));
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
}
}
else
{
if (iins->mMode != ASMIM_ZERO_PAGE)
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, iins->mMode, iins->mAddress, iins->mLinkerObject, iins->mFlags));
else if (iins->mAddress == sreg)
{
if (flags & LIVE_CPU_REG_Y)
{
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
mIns[apos].mLive |= LIVE_MEM;
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_Y;
}
else
{
PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, iins->mAddress));
mIns[apos].mLive |= LIVE_MEM;
for (int j = apos; j < i + 2; j++)
mIns[j].mLive |= LIVE_CPU_REG_X;
}
i++;
}
else
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
if (i > 0)
mIns[i + 0].mLive |= mIns[i - 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
}
progress = true;
CheckLive();
}
}
else if (FindExternAddressSumY(i, sreg, breg, ireg))
{
RepairLoadYImmediate(i, 0);
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
mIns[i + 1].mAddress = breg;
mIns[i + 1].mFlags &= ~NCIF_YZERO;
progress = true;
CheckLive();
}
else if (FindSharedGlobalAddressSumY(i, sreg, ains, iins))
{
RepairLoadYImmediate(i, 0);
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, *iins));
mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 1].mLinkerObject = ains->mLinkerObject;
mIns[i + 1].mAddress = ains->mAddress;
mIns[i + 1].mFlags &= ~NCIF_YZERO;
progress = true;
CheckLive();
}
else if (!(mIns[i + 0].mLive & LIVE_MEM) && FindLoadAddressSumY(i, sreg, apos, ireg))
{
RepairLoadYImmediate(i, 0);
PatchLoadAddressSumY(i, sreg, apos, ireg);
mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
mIns[i + 1].mFlags &= ~NCIF_YZERO;
progress = true;
CheckLive();
}
if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO) && !(mIns[i + 0].mLive & LIVE_CPU_REG_X))
{
const NativeCodeInstruction* ains;
if (FindImmediateStore(i, mIns[i].mAddress + 1, ains))
{
mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i].mAddress));
mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
if (ains->mMode == ASMIM_IMMEDIATE)
mIns[i + 1].mAddress = ains->mAddress << 8;
else
{
mIns[i + 1].mLinkerObject = ains->mLinkerObject;
mIns[i + 1].mAddress = ains->mAddress;
mIns[i + 1].mFlags |= NCIF_UPPER;
mIns[i + 1].mFlags &= ~NCIF_LOWER;
}
progress = true;
CheckLive();
}
}
}
CheckLive();
if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
const NativeCodeInstruction* ains, * iins;
int sreg = mIns[i + 1].mAddress;
int yimm = mIns[i + 0].mAddress;
if (FindSharedGlobalAddressSumY(i, sreg, ains, iins))
{
RepairLoadYImmediate(i + 1, yimm);
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDY, *iins));
mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 2].mLinkerObject = ains->mLinkerObject;
mIns[i + 2].mAddress = ains->mAddress + yimm;
mIns[i + 2].mFlags &= ~NCIF_YZERO;
progress = true;
CheckLive();
}
}
if (i + 1 < mIns.Size() && PeepHoleOptimizerIterate2(i, pass)) progress = true;
if (i + 2 < mIns.Size() && PeepHoleOptimizerIterate3(i, pass)) progress = true;
CheckLive();
if (i + 3 < mIns.Size() && PeepHoleOptimizerIterate4(i, pass)) progress = true;
CheckLive();
if (i + 4 < mIns.Size() && PeepHoleOptimizerIterate5(i, pass)) progress = true;
CheckLive();
if (i + 3 < mIns.Size() && PeepHoleOptimizerIterate4b(i, pass)) progress = true;
CheckLive();
if (i + 4 < mIns.Size() && PeepHoleOptimizerIterate5b(i, pass)) progress = true;
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
#if 1
if (pass < 10 && i + 1 < mIns.Size())
{
if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_INDIRECT_Y) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int n = 3;
if (mIns[i + 0].mLinkerObject && (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
n = 100;
if (mIns[i + 0].mFlags & NCIF_VOLATILE)
n = 1;
if (mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
n--;
if (n > 0 && (mIns[i + 0].mMode != ASMIM_INDIRECT_Y || (mIns[i + 1].mAddress != mIns[i + 0].mAddress && mIns[i + 1].mAddress != mIns[i + 0].mAddress + 1 && pass > 1)))
{
mProc->ResetPatched();
if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n))
{
mProc->ResetPatched();
if (PatchSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i]))
{
if (mIns[i + 0].mMode == ASMIM_ABSOLUTE_X)
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mLive |= LIVE_CPU_REG_X;
}
else if (mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_INDIRECT_Y)
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
}
progress = true;
}
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
}
}
}
else if (
mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
int n = 3;
if (mIns[i + 0].mLinkerObject && (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
n = 100;
if (mIns[i + 0].mFlags & NCIF_VOLATILE)
n = 1;
if (mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))
n--;
if (n > 0)
{
mProc->ResetPatched();
if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n))
{
mProc->ResetPatched();
if (PatchSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i]))
progress = true;
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
}
}
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
{
int n = 2;
if (mIns[i + 1].mLinkerObject && (mIns[i + 1].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
n = 100;
mProc->ResetPatched();
if (CheckSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1], n))
{
mProc->ResetPatched();
if (PatchSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1]))
progress = true;
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
}
}
}
#endif
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
if (i + 5 < mIns.Size() && PeepHoleOptimizerIterate6(i, pass)) progress = true;
CheckLive();
if (i + 2 < mIns.Size() && pass == 0 &&
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1))
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1, nullptr, 256 * mIns[i + 1].mAddress))
progress = true;
}
}
#if 1
if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 0].mFlags & NCIF_UPPER) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
mProc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1))
{
mProc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress, NCIF_UPPER))
progress = true;
}
}
#endif
if (PeepHoleOptimizerIterateN(i, pass)) progress = true;
#if 1
if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
{
int apos, breg;
if (FindDirectAddressSumY(i, mIns[i + 1].mAddress, apos, breg))
{
if (PatchDirectAddressSumY(i, mIns[i + 1].mAddress, apos, breg))
progress = true;
}
}
#if 1
if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y)))
{
int apos, breg;
if (FindBypassAddressSumY(i, mIns[i + 1].mAddress, apos, breg))
{
if (PatchBypassAddressSumY(i, mIns[i + 1].mAddress, apos, breg))
progress = true;
}
}
#endif
#if 1
if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO))
{
int apos, breg;
if (FindDirectAddressSumY(i, mIns[i].mAddress, apos, breg))
{
if (PatchDirectAddressSumY(i, mIns[i].mAddress, apos, breg))
progress = true;
}
}
#endif
#endif
#if 0
if (i + 13 < mIns.Size())
{
if (mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1)
{
printf("CHECK\n");
}
if (mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_LDA &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 7].mType == ASMIT_CLC &&
mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].mMode == ASMIM_ZERO_PAGE && mIns[i + 8].mAddress == mIns[i + 3].mAddress && !(mIns[i + 8].mLive & LIVE_MEM) &&
mIns[i + 9].mType == ASMIT_ADC &&
mIns[i + 10].mType == ASMIT_STA &&
mIns[i + 11].mType == ASMIT_LDA && mIns[i + 11].mMode == ASMIM_ZERO_PAGE && mIns[i + 11].mAddress == mIns[i + 6].mAddress && !(mIns[i + 11].mLive & LIVE_MEM) &&
mIns[i + 12].mType == ASMIT_ADC &&
mIns[i + 12].mType == ASMIT_STA)
{
mIns[i + 7].CopyMode(mIns[i + 0]);
mIns[i + 11].CopyMode(mIns[i + 4]);
mIns[i + 8].mType = ASMIT_SEC;
for (int j = 0; j < 7; j++)
{
mIns[i + j].mType = ASMIT_NOP;
mIns[i + j].mMode = ASMIM_IMPLIED;
mIns[i + j + 7].mLive |= mIns[i + 0].mLive;
}
progress = true;
}
}
#endif
#if 1
if (i + 7 < mIns.Size() && pass > 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 2].mAddress &&
mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
mIns[i + 6].mType == ASMIT_LDY && mIns[i + 6].mMode == ASMIM_IMMEDIATE && mIns[i + 6].mAddress == 0 &&
mIns[i + 7].mMode == ASMIM_INDIRECT_Y && mIns[i + 7].mAddress == mIns[i + 2].mAddress &&
!(mIns[i + 7].mLive & LIVE_MEM))
{
if (mIns[i + 7].mLive & LIVE_CPU_REG_Y)
mIns.Insert(i + 8, mIns[i + 6]);
mIns[i + 1] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY);
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
progress = true;
}
#endif
#if 1
if (i + 8 < mIns.Size() && pass > 0 &&
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 3].mAddress &&
mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
mIns[i + 7].mType == ASMIT_LDY && mIns[i + 7].mMode == ASMIM_IMMEDIATE && mIns[i + 7].mAddress == 0 &&
mIns[i + 8].mMode == ASMIM_INDIRECT_Y && mIns[i + 8].mAddress == mIns[i + 3].mAddress &&
!(mIns[i + 8].mLive & LIVE_MEM))
{
if (mIns[i + 8].mLive & LIVE_CPU_REG_Y)
mIns.Insert(i + 9, mIns[i + 7]);
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
mIns[i + 6].mLive |= LIVE_CPU_REG_Y;
mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
progress = true;
}
#endif
CheckLive();
#if 1
if (pass > 1 && mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i].mLinkerObject && (mIns[i].mFlags & NCIF_LOWER) && !(mIns[i].mAddress & 0xff) && !(mIns[i].mLinkerObject->mAlignment & 0xff))
{
mIns[i].mMode = ASMIM_IMMEDIATE;
mIns[i].mAddress = 0;
mIns[i].mLinkerObject = nullptr;
mIns[i].mFlags &= ~NCIF_LOWER;
progress = true;
}
#endif
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
}
if (progress)
changed = true;
} while (progress);
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
return changed;
}
bool NativeCodeBasicBlock::PeepHoleOptimizerExits(int pass)
{
bool changed = false;
#if 1
int sz = mIns.Size();
if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_CMP)
{
if (mBranch == ASMIT_BNE)
{
if (mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
{
mTrueJump = mTrueJump->mTrueJump;
changed = true;
}
else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCS)
{
mTrueJump = mTrueJump->mFalseJump;
changed = true;
}
}
else if (mBranch == ASMIT_BEQ)
{
if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BCS)
{
mFalseJump = mFalseJump->mTrueJump;
changed = true;
}
else if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BCC)
{
mFalseJump = mFalseJump->mFalseJump;
changed = true;
}
}
}
else if (sz >= 2 &&
mIns[sz - 2].ChangesAccuAndFlag() &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 &&
(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BEQ;
else
mBranch = ASMIT_BNE;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
#if 1
else if (sz >= 2 &&
mIns[sz - 2].ChangesAccuAndFlag() &&
mIns[sz - 1].mType == ASMIT_ASL && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC)
{
mBranch = ASMIT_BPL;
mIns.SetSize(sz - 1);
sz -= 1;
mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BMI;
mIns.SetSize(sz - 1);
sz -= 1;
mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_ROL && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE)
{
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 2);
sz -= 2;
changed = true;
}
else if (mBranch == ASMIT_BEQ)
{
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 2);
sz -= 2;
changed = true;
}
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_ROL && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C) && !mExitRequiredRegs[CPU_REG_Z] &&
mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
{
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 1);
sz -= 1;
changed = true;
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_ROL && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C) && !mExitRequiredRegs[CPU_REG_Z] &&
mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
{
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 1);
sz -= 1;
changed = true;
}
else if (sz >= 3 &&
mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x0 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE)
{
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 3);
sz -= 3;
changed = true;
}
else if (mBranch == ASMIT_BEQ)
{
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 3);
sz -= 3;
changed = true;
}
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_EOR && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
{
NativeCodeBasicBlock* tblock = mProc->AllocateBlock();
tblock->mTrueJump = mTrueJump->mTrueJump;
tblock->mFalseJump = mTrueJump->mFalseJump;
tblock->mBranch = ASMIT_BMI;
tblock->mTrueJump->mNumEntries++;
tblock->mTrueJump->mEntryBlocks.Push(tblock);
tblock->mFalseJump->mNumEntries++;
tblock->mFalseJump->mEntryBlocks.Push(tblock);
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
mTrueJump->mNumEntries--;
mTrueJump = tblock;
tblock->mNumEntries++;
tblock->mEntryBlocks.Push(this);
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
mExitRequiredRegs -= CPU_REG_C;
CheckLive();
}
}
else if (sz >= 2 &&
mIns[sz - 2].ChangesAccuAndFlag() &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC)
{
mBranch = ASMIT_BPL;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
else if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BMI;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_CMP && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C] &&
(mIns[sz - 1].mType == ASMIT_TAX || mIns[sz - 1].mType == ASMIT_TAY))
{
if (mBranch == ASMIT_BCC)
{
mBranch = ASMIT_BPL;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
CheckLive();
}
else if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BMI;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
CheckLive();
}
}
else if (sz >= 2 &&
mIns[sz - 2].ChangesXReg() &&
mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC)
{
mBranch = ASMIT_BPL;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
else if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BMI;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
}
else if (sz >= 2 &&
mIns[sz - 2].ChangesYReg() &&
mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC)
{
mBranch = ASMIT_BPL;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
else if (mBranch == ASMIT_BCS)
{
mBranch = ASMIT_BMI;
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
CheckLive();
}
}
else if (sz >= 4 &&
mIns[sz - 4].mType == ASMIT_EOR && mIns[sz - 4].mMode == ASMIM_IMMEDIATE && mIns[sz - 4].mAddress == 0x80 &&
mIns[sz - 3].mType == ASMIT_STA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 3].mAddress && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
{
NativeCodeBasicBlock* tblock = mProc->AllocateBlock();
tblock->mTrueJump = mTrueJump->mFalseJump;
tblock->mFalseJump = mTrueJump->mTrueJump;
tblock->mBranch = ASMIT_BMI;
tblock->mTrueJump->mNumEntries++;
tblock->mTrueJump->mEntryBlocks.Push(tblock);
tblock->mFalseJump->mNumEntries++;
tblock->mFalseJump->mEntryBlocks.Push(tblock);
mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
mTrueJump->mNumEntries--;
mTrueJump = tblock;
tblock->mNumEntries++;
tblock->mEntryBlocks.Push(this);
mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
CheckLive();
}
}
else if (sz >= 4 &&
mIns[sz - 4].mType == ASMIT_TXA &&
mIns[sz - 3].mType == ASMIT_CLC &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
mIns[sz - 1].mType == ASMIT_TAX && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
{
mIns[sz - 4].mType = ASMIT_DEX; mIns[sz - 4].mLive |= LIVE_CPU_REG_X;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_CPX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BEQ;
else
mBranch = ASMIT_BNE;
CheckLive();
}
}
else if (sz >= 3 &&
mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 &&
mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x01 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C])
{
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
{
mIns.SetSize(sz - 3);
sz -= 3;
changed = true;
}
}
else if (sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE)
{
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 2);
changed = true;
}
else if (mBranch == ASMIT_BEQ)
{
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 2);
changed = true;
}
sz -= 2;
CheckLive();
}
else if (pass >= 7 && sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 2].mLive & LIVE_MEM) &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE)
{
mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 1);
changed = true;
}
else if (mBranch == ASMIT_BEQ)
{
mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 1);
changed = true;
}
sz -= 1;
CheckLive();
}
if (sz >= 1 &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
{
mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0x00; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
if (mBranch == ASMIT_BEQ)
mBranch = ASMIT_BPL;
else
mBranch = ASMIT_BMI;
changed = true;
}
else if (pass >= 7 && sz >= 1 &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x01 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
{
mIns[sz - 1].mType = ASMIT_LSR; mIns[sz - 1].mLive |= LIVE_CPU_REG_C; mIns[sz - 1].mMode = ASMIM_IMPLIED;
if (mBranch == ASMIT_BEQ)
mBranch = ASMIT_BCC;
else
mBranch = ASMIT_BCS;
changed = true;
}
#if 1
else if (pass >= 7 && sz >= 1 &&
mIns[sz - 1].mType == ASMIT_LDA && (mIns[sz - 1].mMode == ASMIM_ABSOLUTE || mIns[sz - 1].mMode == ASMIM_ZERO_PAGE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
(mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) && !mExitRequiredRegs[CPU_REG_Z])
{
mIns[sz - 1].mType = ASMIT_BIT;
changed = true;
}
#endif
else if (pass >= 7 && sz >= 1 &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x40 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
{
mIns[sz - 1].mType = ASMIT_ASL; mIns[sz - 1].mMode = ASMIM_IMPLIED;
if (mBranch == ASMIT_BEQ)
mBranch = ASMIT_BPL;
else
mBranch = ASMIT_BMI;
changed = true;
}
if (sz == 1 && mBranch == ASMIT_BNE && mTrueJump == this)
{
if (mIns[0].mType == ASMIT_DEX || mIns[0].mType == ASMIT_INX)
{
mIns[0] = NativeCodeInstruction(mIns[0].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0);
changed = true;
}
else if (mIns[0].mType == ASMIT_DEY || mIns[0].mType == ASMIT_INY)
{
mIns[0] = NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0);
changed = true;
}
}
#endif
#endif
#if 1
if (sz >= 4 && (mBranch == ASMIT_BMI || mBranch == ASMIT_BPL) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mIns[sz - 4].mType == ASMIT_LDA &&
(mIns[sz - 3].mType == ASMIT_ASL || mIns[sz - 3].mType == ASMIT_ROL) && mIns[sz - 3].mMode == ASMIM_IMPLIED &&
mIns[sz - 2].mType == ASMIT_STA && !mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 4]))
{
if (mBranch == ASMIT_BMI)
mBranch = ASMIT_BCS;
else
mBranch = ASMIT_BCC;
mIns[sz - 3].mLive |= LIVE_CPU_REG_C;
mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
changed = true;
}
}
#endif
#if 1
if (sz >= 3 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_A])
{
if (mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
mIns[sz - 1].mType == ASMIT_EOR && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1)
{
if (mBranch == ASMIT_BEQ)
mBranch = ASMIT_BCS;
else
mBranch = ASMIT_BCC;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
changed = true;
}
}
#endif
if (sz >= 4 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C])
{
if (mIns[sz - 4].mType == ASMIT_TYA &&
mIns[sz - 3].mType == ASMIT_CLC &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
mIns[sz - 1].mType == ASMIT_TAY)
{
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BNE;
else
mBranch = ASMIT_BEQ;
mIns[sz - 4].mType = ASMIT_INY; mIns[sz - 4].mLive |= LIVE_CPU_REG_Y;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_TYA; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mIns[sz - 4].mType == ASMIT_TXA &&
mIns[sz - 3].mType == ASMIT_CLC &&
mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
mIns[sz - 1].mType == ASMIT_TAX)
{
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BNE;
else
mBranch = ASMIT_BEQ;
mIns[sz - 4].mType = ASMIT_INX; mIns[sz - 4].mLive |= LIVE_CPU_REG_X;
mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mIns[sz - 1].mType = ASMIT_TXA; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
}
#if 1
if (sz >= 3 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
mIns[sz - 1].mType == ASMIT_INY && mIns[sz - 2].mType == ASMIT_CPX && mIns[sz - 3].mType == ASMIT_INX &&
!(mIns[sz - 1].mLive & LIVE_CPU_REG_Z))
{
mIns[sz - 1] = mIns[sz - 2];
mIns[sz - 2] = mIns[sz - 3];
mIns[sz - 3].mType = ASMIT_INY;
changed = true;
}
#endif
#if 1
if (sz > 1 && mFalseJump &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
mIns[sz - 1].mType == ASMIT_CMP &&
!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BCC)
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
mBranch = ASMIT_JMP;
changed = true;
}
else if (mBranch == ASMIT_BCS)
{
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
mBranch = ASMIT_JMP;
changed = true;
}
}
#endif
#if 1
if (sz > 0 && mFalseJump && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE)
{
if (mBranch == ASMIT_BCC)
{
if (mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_CMP && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mTrueJump->mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
!mTrueJump->mExitRequiredRegs[CPU_REG_Z] && !mTrueJump->mExitRequiredRegs[CPU_REG_C])
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mTrueJump->mTrueJump;
mTrueJump->AddEntryBlock(this);
changed = true;
}
else if (mTrueJump->mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
!mTrueJump->mExitRequiredRegs[CPU_REG_Z] && !mTrueJump->mExitRequiredRegs[CPU_REG_C])
{
mTrueJump->RemEntryBlock(this);
mTrueJump = mTrueJump->mFalseJump;
mTrueJump->AddEntryBlock(this);
changed = true;
}
}
}
else if (mBranch == ASMIT_BCS)
{
if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_CMP && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mFalseJump->mBranch == ASMIT_BCC && mFalseJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
!mFalseJump->mExitRequiredRegs[CPU_REG_Z] && !mFalseJump->mExitRequiredRegs[CPU_REG_C])
{
mFalseJump->RemEntryBlock(this);
mFalseJump = mFalseJump->mTrueJump;
mFalseJump->AddEntryBlock(this);
changed = true;
}
else if (mFalseJump->mBranch == ASMIT_BCS && mFalseJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
!mFalseJump->mExitRequiredRegs[CPU_REG_Z] && !mFalseJump->mExitRequiredRegs[CPU_REG_C])
{
mFalseJump->RemEntryBlock(this);
mFalseJump = mFalseJump->mFalseJump;
mFalseJump->AddEntryBlock(this);
changed = true;
}
}
}
}
#endif
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
#if 1
if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump &&
mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
{
if (mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0 && !(mExitRequiredRegs[CPU_REG_C]))
{
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
else if (mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1 && !(mExitRequiredRegs[CPU_REG_C]))
{
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
else if (mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1 && !(mExitRequiredRegs[CPU_REG_C]))
{
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, 1));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
else if (mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0 && !(mExitRequiredRegs[CPU_REG_C]))
{
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, 1));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
else if (mIns.Size() > 0 && mIns.Last().mType == ASMIT_LDA)
{
if (mBranch == ASMIT_BEQ && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0)
{
mIns.Insert(mIns.Size() - 1, NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
else if (mBranch == ASMIT_BNE && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1)
{
mIns.Insert(mIns.Size() - 1, NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
mExitProvidedRegs += CPU_REG_A;
mBranch = ASMIT_JMP;
mTrueJump = mTrueJump->mTrueJump;
mFalseJump = nullptr;
changed = true;
CheckLive();
}
}
}
#endif
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
return changed;
}
bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
{
if (!mVisited)
{
assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());
bool changed = RemoveNops();
mIns.Reserve(mIns.Size() * 2 + 32);
mVisited = true;
CheckLive();
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
if (PeepHoleOptimizerShuffle(pass))
changed = true;
if (PeepHoleOptimizerIterate(pass))
changed = true;
if (PeepHoleOptimizerExits(pass))
changed = true;
if (this->mTrueJump && this->mTrueJump->PeepHoleOptimizer(pass))
changed = true;
if (this->mFalseJump && this->mFalseJump->PeepHoleOptimizer(pass))
changed = true;
assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
return changed;
}
return false;
}
void NativeCodeBasicBlock::CheckVisited(void)
{
#if _DEBUG
if (!mPatched)
{
mPatched = true;
assert(mVisited);
if (mTrueJump)
mTrueJump->CheckVisited();
if (mFalseJump)
mFalseJump->CheckVisited();
}
#endif
}
void NativeCodeBasicBlock::CheckAsmCode(void)
{
#if _DEBUG
if (!mVisited)
{
mVisited = true;
for (int j = 0; j < mIns.Size(); j++)
{
if (mIns[j].mMode == ASMIM_IMMEDIATE_ADDRESS)
assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE));
else
assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode));
if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ABSOLUTE_Y || mIns[j].mMode == ASMIM_ABSOLUTE_X)
assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0);
}
if (mTrueJump) mTrueJump->CheckAsmCode();
if (mFalseJump) mFalseJump->CheckAsmCode();
}
#endif
}
void NativeCodeBasicBlock::CheckBlocks(bool sequence)
{
#if _DEBUG
if (!mChecked)
{
mChecked = true;
assert(this != mProc->mEntryBlock || mNumEntries < 2);
CheckLive();
if (sequence)
{
if (mTrueJump)
assert(mTrueJump->mEntryBlocks.Contains(this));
if (mFalseJump)
assert(mFalseJump->mEntryBlocks.Contains(this));
}
if (mTrueJump) mTrueJump->CheckBlocks();
if (mFalseJump) mFalseJump->CheckBlocks();
}
#endif
}
void NativeCodeBasicBlock::CheckLive(void)
{
#if _DEBUG
uint32 live = 0;
if (mFalseJump && mFalseJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mExitRequiredRegs.Size() > 0)
{
if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].RequiresXReg())
assert(mExitRequiredRegs[CPU_REG_X]);
}
if (mTrueJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mExitRequiredRegs.Size() > 0)
{
if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].RequiresXReg())
assert(mExitRequiredRegs[CPU_REG_X]);
}
assert(mBranch == ASMIT_RTS || (mBranch == ASMIT_JMP) == (mFalseJump == nullptr));
if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
live |= LIVE_CPU_REG_C;
if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI)
live |= LIVE_CPU_REG_Z;
if (mIns.Size() > 0 && mIns[0].mMode == ASMIM_INDIRECT_Y && mEntryRequiredRegs.Size() > 0)
{
assert(mEntryRequiredRegs[CPU_REG_Y]);
}
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_Z])
{
if (mFalseJump)
live |= LIVE_CPU_REG_Z;
else if (mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
{
if (mTrueJump->mIns.Size() == 0 || !mTrueJump->mIns[0].ChangesZFlag())
live |= LIVE_CPU_REG_Z;
}
}
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_C] && (mFalseJump || mTrueJump->mEntryRequiredRegs[CPU_REG_C]))
live |= LIVE_CPU_REG_C;
for (int j = mIns.Size() - 1; j >= 0; j--)
{
assert(mIns[j].mType != ASMIT_INV);
if (mIns[j].mMode == ASMIM_IMMEDIATE_ADDRESS)
assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE));
else
assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode));
if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_ABSOLUTE_X || mIns[j].mMode == ASMIM_ABSOLUTE_Y)
assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0);
if (mIns[j].mType != ASMIT_NOP)
{
assert(!(live & ~mIns[j].mLive));
if (mIns[j].mType == ASMIT_JSR)
{
assert(!(live & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)));
if (!(mIns[j].mFlags & NCIF_JSRFLAGS))
assert(!(live & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)));
}
if (mIns[j].ChangesAccu()) live &= ~LIVE_CPU_REG_A;
if (mIns[j].ChangesXReg()) live &= ~LIVE_CPU_REG_X;
if (mIns[j].ChangesYReg()) live &= ~LIVE_CPU_REG_Y;
if (mIns[j].ChangesCarry()) live &= ~LIVE_CPU_REG_C;
if (mIns[j].ChangesZFlag()) live &= ~LIVE_CPU_REG_Z;
if (mIns[j].RequiresAccu()) live |= LIVE_CPU_REG_A;
if (mIns[j].RequiresXReg()) live |= LIVE_CPU_REG_X;
if (mIns[j].RequiresYReg()) live |= LIVE_CPU_REG_Y;
if (mIns[j].RequiresCarry()) live |= LIVE_CPU_REG_C;
}
}
if (mEntryRequiredRegs.Size() > 0)
{
if (live & LIVE_CPU_REG_A)
assert(mEntryRegA || mEntryRequiredRegs[CPU_REG_A]);
if (live & LIVE_CPU_REG_X)
assert(mEntryRegX || mEntryRequiredRegs[CPU_REG_X]);
if (live & LIVE_CPU_REG_Y)
assert(mEntryRegY || mEntryRequiredRegs[CPU_REG_Y]);
}
#endif
}
void NativeCodeBasicBlock::Assemble(void)
{
if (!mAssembled)
{
mAssembled = true;
for (int i = 0; i < mIns.Size(); i++)
mIns[i].Assemble(this);
if (this->mTrueJump)
this->mTrueJump->Assemble();
if (this->mFalseJump)
this->mFalseJump->Assemble();
}
}
void NativeCodeBasicBlock::Close(const InterInstruction* ins, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch)
{
this->mTrueJump = trueJump;
this->mFalseJump = falseJump;
this->mBranch = branch;
this->mBranchIns = ins;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::SplitAt(int at)
{
NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
eblock->Close(mBranchIns, mTrueJump, mFalseJump, mBranch);
this->mBranch = ASMIT_JMP;
this->mFalseJump = nullptr;
this->mTrueJump = eblock;
for (int i = at; i < mIns.Size(); i++)
eblock->mIns.Push(mIns[i]);
mIns.SetSize(at);
eblock->mNumEntries = 1;
eblock->mEntryBlocks.Push(this);
eblock->mTrueJump->mEntryBlocks.RemoveAll(this);
eblock->mTrueJump->mEntryBlocks.Push(eblock);
if (eblock->mFalseJump)
{
eblock->mFalseJump->mEntryBlocks.RemoveAll(this);
eblock->mFalseJump->mEntryBlocks.Push(eblock);
}
return eblock;
}
NativeCodeBasicBlock* NativeCodeBasicBlock::BypassEmptyBlocks(void)
{
if (mBypassed)
return this;
else if (mTrueJump && !mFalseJump && mCode.Size() == 0 && this != mTrueJump)
return mTrueJump->BypassEmptyBlocks();
else
{
mBypassed = true;
if (mFalseJump)
mFalseJump = mFalseJump->BypassEmptyBlocks();
if (mTrueJump)
mTrueJump = mTrueJump->BypassEmptyBlocks();
return this;
}
}
int NativeCodeBasicBlock::LeadsInto(NativeCodeBasicBlock* block, int dist)
{
if (mPlaced)
return 1000;
else if (this == block)
return 0;
else if (dist < 6)
{
int d0 = mTrueJump ? mTrueJump->LeadsInto(block, dist + 1) : 1000;
int d1 = mFalseJump ? mFalseJump->LeadsInto(block, dist + 1) : 1000;
int d = (d0 < d1 ? d0 : d1) + mCode.Size();
if (d < 100)
return d;
}
return 1000;
}
void NativeCodeBasicBlock::BuildPlacement(ExpandingArray<NativeCodeBasicBlock*>& placement)
{
if (!mPlaced)
{
if (mTrueJump && mFalseJump && mTrueJump == mFalseJump)
{
mFalseJump = nullptr;
mBranch = ASMIT_JMP;
}
assert(mBranch != ASMIT_JMP || mIns.Size() > 0 || mTrueJump == this);
mPlaced = true;
mPlace = placement.Size();
placement.Push(this);
if (mFalseJump)
{
if (mFalseJump->mPlaced)
mTrueJump->BuildPlacement(placement);
else if (mTrueJump->mPlaced)
mFalseJump->BuildPlacement(placement);
else if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
{
if (mTrueJump->mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE || mTrueJump->mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
{
mTrueJump->mPlaced = true;
mTrueJump->mPlace = placement.Size();
placement.Push(mTrueJump);
mFalseJump->BuildPlacement(placement);
}
else
{
mFalseJump->mPlaced = true;
mFalseJump->mPlace = placement.Size();
placement.Push(mFalseJump);
mTrueJump->BuildPlacement(placement);
}
}
else if (mTrueJump->LeadsInto(mFalseJump, 0) < mFalseJump->LeadsInto(mTrueJump, 0))
{
mTrueJump->BuildPlacement(placement);
mFalseJump->BuildPlacement(placement);
}
else if (mTrueJump->LeadsInto(mFalseJump, 0) > mFalseJump->LeadsInto(mTrueJump, 0))
{
mFalseJump->BuildPlacement(placement);
mTrueJump->BuildPlacement(placement);
}
else if (mTrueJump->mCode.Size() < 32 && (mTrueJump->mTrueJump && mTrueJump->mTrueJump->mPlaced) || (mTrueJump->mFalseJump && mTrueJump->mFalseJump->mPlaced))
{
mTrueJump->BuildPlacement(placement);
mFalseJump->BuildPlacement(placement);
}
else if (mFalseJump->mCode.Size() < 32 && (mFalseJump->mTrueJump && mFalseJump->mTrueJump->mPlaced) || (mFalseJump->mFalseJump && mFalseJump->mFalseJump->mPlaced))
{
mFalseJump->BuildPlacement(placement);
mTrueJump->BuildPlacement(placement);
}
else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 100 && mFalseJump->LeadsInto(mTrueJump->mTrueJump, 0) < 100)
{
mTrueJump->mPlaced = true;
mTrueJump->mPlace = placement.Size();
placement.Push(mTrueJump);
mFalseJump->BuildPlacement(placement);
}
else if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump && mFalseJump->mCode.Size() < 100 && mTrueJump->LeadsInto(mFalseJump->mTrueJump, 0) < 100)
{
mFalseJump->mPlaced = true;
mFalseJump->mPlace = placement.Size();
placement.Push(mFalseJump);
mTrueJump->BuildPlacement(placement);
}
else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump == mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
{
mTrueJump->mPlaced = true;
mTrueJump->mPlace = placement.Size();
placement.Push(mTrueJump);
mFalseJump->BuildPlacement(placement);
}
else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump == mFalseJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mFalseJump)
{
mTrueJump->mPlaced = true;
mTrueJump->mPlace = placement.Size();
placement.Push(mTrueJump);
mFalseJump->BuildPlacement(placement);
}
else if (
!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump->mPlaced && mTrueJump->mCode.Size() < 120 ||
mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mFalseJump->mPlaced && mTrueJump->mTrueJump->mPlaced && mTrueJump->mCode.Size() < 120)
{
mTrueJump->BuildPlacement(placement);
mFalseJump->BuildPlacement(placement);
}
else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mFalseJump->mFalseJump && !mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mNumEntries > 1 && mTrueJump->mTrueJump->mTrueJump != mTrueJump->mTrueJump)
{
mTrueJump->mPlaced = true;
mTrueJump->mPlace = placement.Size();
placement.Push(mTrueJump);
mFalseJump->BuildPlacement(placement);
mTrueJump->mTrueJump->BuildPlacement(placement);
}
else
{
mFalseJump->BuildPlacement(placement);
mTrueJump->BuildPlacement(placement);
}
}
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);
}
}
if (mTrueJump->mEntryBlocks.Size() == 2 && this == mTrueJump->mEntryBlocks[0] && !mTrueJump->mEntryBlocks[1]->mFalseJump)
{
if (!mTrueJump->mEntryBlocks[1]->mPlaced && mTrueJump->mEntryBlocks[1]->mCode.Size() + mTrueJump->mCode.Size() < 40)
{
mTrueJump->mEntryBlocks[1]->mPlaced = true;
mTrueJump->mEntryBlocks[1]->mPlace = placement.Size();
placement.Push(mTrueJump->mEntryBlocks[1]);
}
}
}
mTrueJump->BuildPlacement(placement);
}
}
}
void NativeCodeBasicBlock::InitialOffset(int& total)
{
mOffset = total;
total += mCode.Size();
if (mFalseJump)
{
total += 5;
if (mFalseJump->mPlace != mPlace + 1 && mTrueJump->mPlace != mPlace + 1)
total += 3;
}
else if (mTrueJump)
{
if (mTrueJump->mPlace != mPlace + 1)
total += 3;
}
mSize = total - mOffset;
}
bool NativeCodeBasicBlock::CalculateOffset(int& total)
{
bool changed = total != mOffset;
mOffset = total;
total += mCode.Size();
if (mFalseJump)
{
if (mFalseJump->mPlace == mPlace + 1)
total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset);
else if (mTrueJump->mPlace == mPlace + 1)
total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset);
else if (mFalseJump->mPlace < mPlace && mTrueJump->mPlace < mPlace && mPlace - mTrueJump->mPlace < 126 &&
mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_RTS)
{
total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset);
total += JumpByteSize(mFalseJump, mFalseJump->mOffset - total);
}
else if (
mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace ||
mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace)
{
total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset);
total += JumpByteSize(mTrueJump, mTrueJump->mOffset - total);
}
else
{
total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset);
total += JumpByteSize(mFalseJump, mFalseJump->mOffset - total);
}
}
else if (mTrueJump)
{
if (mTrueJump->mPlace != mPlace + 1)
{
if (!mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 3)
{
total += mTrueJump->mCode.Size();
for (int i = 0; i < mTrueJump->mCode.Size(); i++)
mCode.Push(mTrueJump->mCode[i]);
mTrueJump = nullptr;
}
else
total += JumpByteSize(mTrueJump, mTrueJump->mOffset - total);
}
}
if (mOffset + mSize != total)
changed = true;
mSize = total - mOffset;
return changed;
}
void NativeCodeBasicBlock::ShortcutJump(int offset)
{
if (mCode[offset] == 0x4c)
{
int i = 0;
while (i < mRelocations.Size() && mRelocations[i].mOffset != offset + 1)
i++;
if (i < mRelocations.Size())
{
LinkerReference& ref(mRelocations[i]);
if (ref.mRefObject && ref.mRefObject->mData)
{
LinkerObject* lo = ref.mRefObject;
if (lo->mData[ref.mRefOffset] == 0x4c || lo->mData[ref.mRefOffset] == 0x6c)
{
int j = 0;
while (j < lo->mReferences.Size() && lo->mReferences[j]->mOffset != ref.mRefOffset + 1)
j++;
if (j < lo->mReferences.Size())
{
mCode[offset] = lo->mData[ref.mRefOffset];
ref.mRefObject = lo->mReferences[j]->mRefObject;
ref.mRefOffset = lo->mReferences[j]->mRefOffset;
ref.mFlags = lo->mReferences[j]->mFlags;
}
else
{
mCode[offset] = lo->mData[ref.mRefOffset];
mCode[offset + 1] = lo->mData[ref.mRefOffset + 1];
mCode[offset + 2] = lo->mData[ref.mRefOffset + 2];
mRelocations.Remove(i);
}
}
}
}
}
}
void NativeCodeBasicBlock::ShortcutTailRecursion()
{
if (!mVisited)
{
mVisited = true;
if (!mFalseJump && mTrueJump && mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_RTS)
{
if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
{
this->mCode[this->mCode.Size() - 3] = 0x4c;
mTrueJump->mNumEntries--;
mTrueJump = nullptr;
ShortcutJump(this->mCode.Size() - 3);
}
#if 0
else
{
this->mCode.Push(0x60);
mTrueJump->mNumEntries--;
mTrueJump = nullptr;
}
#endif
}
else if (!mFalseJump && !mTrueJump)
{
int ns = mIns.Size();
if (ns >= 2 && mIns[ns - 1].mType == ASMIT_RTS && mIns[ns - 2].IsSimpleJSR())
{
this->mCode.Remove(this->mCode.Size() - 1);
this->mCode[this->mCode.Size() - 3] = 0x4c;
ShortcutJump(this->mCode.Size() - 3);
}
}
if (mTrueJump) mTrueJump->ShortcutTailRecursion();
if (mFalseJump) mFalseJump->ShortcutTailRecursion();
}
}
void NativeCodeBasicBlock::CopyCode(NativeCodeProcedure * proc, uint8* target)
{
int i;
int next, end;
end = mOffset + mCode.Size();
next = mOffset + mSize;
if (mFalseJump)
{
if (mBranchIns)
PutLocation(mBranchIns->mLocation, false);
if (mFalseJump->mPlace == mPlace + 1)
end += PutBranch(proc, mTrueJump, mBranch, mTrueJump->mOffset - end);
else if (mTrueJump->mPlace == mPlace + 1)
end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), mFalseJump->mOffset - end);
else if (mFalseJump->mPlace < mPlace && mTrueJump->mPlace < mPlace && mPlace - mTrueJump->mPlace < 126 &&
mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_RTS)
{
end += PutBranch(proc, mTrueJump, mBranch, mTrueJump->mOffset - end);
end += PutJump(proc, mFalseJump, mFalseJump->mOffset - end);
}
else if (
mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace ||
mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace)
{
end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), mFalseJump->mOffset - end);
end += PutJump(proc, mTrueJump, mTrueJump->mOffset - end);
}
else
{
end += PutBranch(proc, mTrueJump, mBranch, mTrueJump->mOffset - end);
end += PutJump(proc, mFalseJump, mFalseJump->mOffset - end);
}
if (mBranchIns)
PutLocation(mBranchIns->mLocation, false);
}
else if (mTrueJump)
{
if (mTrueJump->mPlace != mPlace + 1)
{
if (mBranchIns)
PutLocation(mBranchIns->mLocation, false);
end += PutJump(proc, mTrueJump, mTrueJump->mOffset - end);
if (mBranchIns)
PutLocation(mBranchIns->mLocation, false);
}
else if (mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_RTS && mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
this->mCode[this->mCode.Size() - 3] = 0x4c;
}
assert(end == next);
for (int i = 0; i < mRelocations.Size(); i++)
{
LinkerReference& rl(mRelocations[i]);
rl.mOffset += mOffset;
if (rl.mFlags & LREF_INBLOCK)
{
rl.mRefOffset += mOffset;
rl.mFlags &= ~LREF_INBLOCK;
}
proc->mRelocations.Push(rl);
}
for (int i = 0; i < mCodeLocations.Size(); i++)
{
CodeLocation loc(mCodeLocations[i]);
loc.mStart += mOffset;
loc.mEnd += mOffset;
proc->mCodeLocations.Push(loc);
}
for (i = 0; i < mCode.Size(); i++)
{
target[i + mOffset] = mCode[i];
}
}
NativeCodeBasicBlock::NativeCodeBasicBlock(NativeCodeProcedure* proc)
{
mProc = proc;
mBranch = ASMIT_RTS;
mBranchIns = nullptr;
mTrueJump = mFalseJump = NULL;
mOffset = -1;
mPlaced = false;
mCopied = false;
mKnownShortBranch = false;
mBypassed = false;
mAssembled = false;
mLocked = false;
mDominator = nullptr;
mLoopHeadBlock = nullptr;
mLoopTailBlock = nullptr;
mEntryRegA = false;
mEntryRegX = false;
mEntryRegY = false;
mExitRegA = false;
mExitRegX = false;
mVisited = false;
mLoopHead = false;
mNumEntries = 0;
}
NativeCodeBasicBlock::~NativeCodeBasicBlock(void)
{
}
NativeCodeProcedure::NativeCodeProcedure(NativeCodeGenerator* generator)
: mGenerator(generator), mSimpleInline(false)
{
mTempBlocks = 1000;
}
NativeCodeProcedure::~NativeCodeProcedure(void)
{
}
void NativeCodeProcedure::CompressTemporaries(bool singles)
{
if (mInterProc->mTempSize > 0)
{
ResetVisited();
NumberSet used(256), modified(256), pairs(256);
mEntryBlock->CollectZeroPageUsage(used, modified, pairs);
uint8 remap[256];
for (int i = 0; i < 256; i++)
remap[i] = i;
int tpos = BC_REG_TMP + mInterProc->mFreeCallerSavedTemps;
int spos = BC_REG_TMP_SAVED;
NumberSet * collisionSet = new NumberSet[NUM_REGS];
for (int i = 0; i < NUM_REGS; i++)
collisionSet[i].Reset(NUM_REGS);
ResetVisited();
mEntryBlock->BuildCollisionTable(collisionSet);
// for (int tsize = 4; tsize > 0; tsize >>= 1)
{
for (int i = 0; i < mInterProc->mTempOffset.Size(); i++)
{
bool tused = false;
int reg = BC_REG_TMP + mInterProc->mTempOffset[i];
// if (mInterProc->mLeafProcedure || reg >= BC_REG_TMP_SAVED)
if (reg >= BC_REG_TMP + mInterProc->mFreeCallerSavedTemps)
{
int size = mInterProc->mTempSizes[i];
// if (size == tsize)
{
int usize = 0;
for (int j = 0; j < size; j++)
if (used[reg + j])
usize = j + 1;
if (usize)
{
int pos = spos;
#if 1
// if (mInterProc->mLeafProcedure)
{
if (singles && usize == 1)
{
int k = 0;
while (k < 4 && collisionSet[k + BC_REG_ACCU][reg])
k++;
if (k < 4)
{
pos = BC_REG_ACCU + k;
for (int i = 0; i < 256; i++)
{
if (collisionSet[reg][i])
{
collisionSet[pos] += i;
collisionSet[i] += pos;
}
}
}
}
else
{
int k = 0;
while (k < usize && !collisionSet[k + BC_REG_ACCU][k + reg])
k++;
if (k == usize)
{
pos = BC_REG_ACCU;
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < usize; j++)
{
if (collisionSet[j + reg][i])
{
collisionSet[j + BC_REG_ACCU] += i;
collisionSet[i] += j + BC_REG_ACCU;
}
}
}
}
}
}
#endif
if (pos == spos)
{
if (tpos + usize <= BC_REG_TMP + mInterProc->mCallerSavedTemps)
{
pos = tpos;
tpos += usize;
}
else
spos += usize;
mInterProc->mTempOffset[i] = pos - BC_REG_TMP;
mInterProc->mTempSizes[i] = usize;
}
else
{
mInterProc->mTempOffset[i] = 0;
mInterProc->mTempSizes[i] = 0;
}
for (int j = 0; j < usize; j++)
remap[reg + j] = pos + j;
}
else
{
mInterProc->mTempOffset[i] = 0;
mInterProc->mTempSizes[i] = 0;
}
}
}
}
}
delete[] collisionSet;
mInterProc->mCallerSavedTemps = tpos - BC_REG_TMP;
ResetVisited();
mEntryBlock->RemapZeroPage(remap);
assert(mInterProc->mTempSize >= tpos - BC_REG_TMP);
if (spos > BC_REG_TMP_SAVED)
mInterProc->mTempSize = spos - BC_REG_TMP;
else
mInterProc->mTempSize = tpos - BC_REG_TMP;
if (mNoFrame && !used[BC_REG_STACK] && mInterProc->mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP)
mStackExpand = 0;
}
}
void NativeCodeProcedure::SaveTempsToStack(int tempSave)
{
if (mInterProc->mSaveTempsLinkerObject)
{
assert(tempSave <= mInterProc->mSaveTempsLinkerObject->mSize);
if (tempSave > 3)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
else if (tempSave > 0)
{
for (int i = 0; i < tempSave; i++)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject));
}
}
}
}
void NativeCodeProcedure::LoadTempsFromStack(int tempSave)
{
if (mInterProc->mSaveTempsLinkerObject)
{
if (tempSave > 3)
{
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject));
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
else if (tempSave > 0)
{
for (int i = 0; i < tempSave; i++)
{
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject));
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i));
}
}
}
}
void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
{
mInterProc = proc;
mInterProc->mLinkerObject->mNativeProc = this;
CheckFunc = !strcmp(mInterProc->mIdent->mString, "sqrt");
int nblocks = proc->mBlocks.Size();
tblocks = new NativeCodeBasicBlock * [nblocks];
for (int i = 0; i < nblocks; i++)
tblocks[i] = nullptr;
mIndex = proc->mID;
mFastCallBase = proc->mFastCallBase;
int tempSave = proc->mTempSize > BC_REG_TMP_SAVED - BC_REG_TMP && !proc->mSaveTempsLinkerObject && !mInterProc->mInterrupt ? proc->mTempSize - (BC_REG_TMP_SAVED - BC_REG_TMP) : 0;
int commonFrameSize = proc->mCommonFrameSize;
mStackExpand = tempSave + proc->mLocalSize;
if (proc->mCallsByteCode || commonFrameSize > 0)
commonFrameSize += 2;
mFrameOffset = 0;
mNoFrame = (mStackExpand + proc->mCommonFrameSize) < 64 && !proc->mHasDynamicStack;// && !(proc->mHasInlineAssembler && !proc->mLeafProcedure);
#if 0
if (!(proc->mCompilerOptions & COPT_OPTIMIZE_BASIC) && (proc->mCompilerOptions & COPT_DEBUGINFO))
mNoFrame = mStackExpand + proc->mCommonFrameSize == 0 && !proc->mHasDynamicStack;
#endif
if (mNoFrame)
proc->mLinkerObject->mFlags |= LOBJF_NO_FRAME;
if (mNoFrame)
{
if (mStackExpand > 0)
mFrameOffset = tempSave;
}
else
{
mStackExpand += 2;
}
if (!proc->mLeafProcedure)
{
if (mNoFrame)
mFrameOffset = commonFrameSize + tempSave;
}
mEntryBlock = AllocateBlock();
mEntryBlock->mLocked = true;
mBlocks.Push(mEntryBlock);
mExitBlock = AllocateBlock();
mExitBlock->mLocked = true;
mBlocks.Push(mExitBlock);
// Place a temporary RTS
uint32 rflags = 0;
switch (proc->mReturnType)
{
case IT_BOOL:
case IT_INT8:
rflags = NCIF_LOWER;
break;
case IT_INT16:
case IT_POINTER:
rflags = NCIF_LOWER | NCIF_UPPER;
break;
case IT_INT32:
case IT_FLOAT:
rflags = NCIF_LOWER | NCIF_UPPER | NCIF_LONG;
break;
}
mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_RTS, ASMIM_IMPLIED, 0, nullptr, rflags));
mEntryBlock->mTrueJump = CompileBlock(mInterProc, mInterProc->mBlocks[0]);
mEntryBlock->mBranch = ASMIT_JMP;
if (proc->mLeafProcedure && proc->mFastCallProcedure && !proc->mInterrupt && !proc->mDispatchedCall && mNoFrame && mStackExpand == 0 && commonFrameSize == 0 && proc->mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP && (mGenerator->mCompilerOptions & COPT_NATIVE))
{
#if 1
if (proc->mParamVars.Size() == 1 && proc->mParamVars[0]->mSize == 1)
{
proc->mLinkerObject->mFlags |= LOBJF_ARG_REG_A;
proc->mLinkerObject->mTemporaries[0]++;
proc->mLinkerObject->mTempSizes[0]--;
mEntryBlock->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS));
mEntryBlock->mEntryRegA = true;
}
#endif
#if 1
if (mExitBlock->mIns[0].mFlags == NCIF_LOWER)
{
mExitBlock->mIns[0].mFlags = NCIF_USE_CPU_REG_A;
mExitBlock->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mExitBlock->mExitRegA = true;
proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A;
}
#endif
}
mGenerator->PopulateShortMulTables();
Optimize();
if (mEntryBlock->mIns.Size() > 0)
{
NativeCodeBasicBlock* eblock = AllocateBlock();
eblock->mTrueJump = mEntryBlock;
mEntryBlock = eblock;
}
// Remove temporary RTS
mExitBlock->mIns.Pop();
int frameSpace = tempSave;
tempSave = proc->mTempSize > BC_REG_TMP_SAVED - BC_REG_TMP ? proc->mTempSize - (BC_REG_TMP_SAVED - BC_REG_TMP) : 0;
if (!(mGenerator->mCompilerOptions & COPT_NATIVE))
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BYTE, ASMIM_IMPLIED, 0xea));
bool ignoreExpandCommonFrame = false;
if (mInterProc->mInterrupt)
{
if (!mNoFrame || mStackExpand > 0 || commonFrameSize > 0)
mGenerator->mErrors->Error(mInterProc->mLocation, ERRR_INTERRUPT_TO_COMPLEX, "Function to complex for interrupt");
ZeroPageSet zpLocal, zpGlobal;
ResetVisited();
if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true))
zpLocal |= zpGlobal;
else
mGenerator->mErrors->Error(mInterProc->mLocation, ERRR_INTERRUPT_TO_COMPLEX, "No recursive functions in interrupt");
if (proc->mHardwareInterrupt)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_TXA));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_TYA));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
}
bool usesStack = false;
if (zpLocal[BC_REG_STACK])
{
usesStack = true;
zpLocal -= BC_REG_STACK;
zpLocal -= BC_REG_STACK + 1;
}
if (usesStack)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
for (int i = 2; i < 256; i++)
{
if (zpLocal[i])
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, i));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
}
}
for (int i = 255; i >= 2; i--)
{
if (zpLocal[i])
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, i));
}
}
if (usesStack)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
if (proc->mHardwareInterrupt)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_TAY));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_TAX));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
}
// We safe all registers
proc->mLinkerObject->mFlags |= LOBJF_ZEROPAGESET;
}
else
{
if (mNoFrame)
{
if (mStackExpand > 0)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BCS, ASMIM_RELATIVE, 2));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
ignoreExpandCommonFrame = true;
if (proc->mSaveTempsLinkerObject)
SaveTempsToStack(tempSave);
else if (tempSave)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1));
if (tempSave == 1)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
else if (tempSave == 2)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
}
else if (commonFrameSize > 0)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
else
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
}
}
else if (proc->mSaveTempsLinkerObject)
SaveTempsToStack(tempSave);
}
else
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, mStackExpand & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
if (proc->mSaveTempsLinkerObject)
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
else
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, tempSave));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_INY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
if (proc->mSaveTempsLinkerObject)
SaveTempsToStack(tempSave);
else if (tempSave)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
if (tempSave > 1)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
}
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_CLC, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_ADC, ASMIM_IMMEDIATE, frameSpace + 2));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));
}
if (!proc->mLeafProcedure && commonFrameSize > 0 && !ignoreExpandCommonFrame)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
if (commonFrameSize >= 256)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
else
{
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BCS, ASMIM_RELATIVE, 2));
mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
if (commonFrameSize >= 256)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
else
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BCC, ASMIM_RELATIVE, 2));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
}
if (mNoFrame)
{
if (mStackExpand > 0)
{
if (proc->mSaveTempsLinkerObject)
LoadTempsFromStack(tempSave);
else if (tempSave)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1));
if (tempSave == 1)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
}
else if (tempSave == 2)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
}
else if (commonFrameSize > 0)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEX, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
else
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
}
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BCC, ASMIM_RELATIVE, 2));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
else if (proc->mSaveTempsLinkerObject)
LoadTempsFromStack(tempSave);
}
else
{
if (proc->mSaveTempsLinkerObject)
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
else
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, tempSave));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));
if (proc->mSaveTempsLinkerObject)
LoadTempsFromStack(tempSave);
else if (tempSave)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
if (tempSave > 1)
{
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
}
}
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, mStackExpand & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
ZeroPageSet zpLocal, zpGlobal;
ResetVisited();
if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, false))
{
zpLocal |= zpGlobal;
proc->mLinkerObject->mZeroPageSet = zpLocal;
proc->mLinkerObject->mFlags |= LOBJF_ZEROPAGESET;
}
}
proc->mFramePointer = !mNoFrame;
for (int i = 0; i < proc->mParamVars.Size(); i++)
{
if (proc->mParamVars[i])
proc->mParamVars[i]->mOffset = i + proc->mLocalSize + 2 + mFrameOffset;
}
for (int i = 0; i < proc->mLocalVars.Size(); i++)
{
if (proc->mLocalVars[i])
proc->mLocalVars[i]->mOffset += mFrameOffset;
}
if (proc->mHardwareInterrupt)
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_RTI, ASMIM_IMPLIED));
else
mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_RTS, ASMIM_IMPLIED));
if (mExitBlock->mIns.Size() == 1 && rflags == NCIF_LOWER && !mExitBlock->mExitRegA && (mGenerator->mCompilerOptions & COPT_NATIVE))
{
if (mExitBlock->mEntryBlocks.Size() == 1)
{
NativeCodeBasicBlock* eblock = mExitBlock->mEntryBlocks[0];
int sz = eblock->mIns.Size();
if (sz >= 0 && eblock->mIns[sz - 1].mType == ASMIT_STA && eblock->mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && eblock->mIns[sz - 1].mAddress == BC_REG_ACCU)
{
mExitBlock->mExitRegA = true;
eblock->mIns.Remove(sz - 1);
proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A;
}
}
}
proc->mLinkerObject->mType = LOT_NATIVE_CODE;
if (!mInterProc->mNoInline)
{
if (mEntryBlock->mIns.Size() == 0 && mExitBlock->mIns.Size() == 1 && !mEntryBlock->mTrueJump->mFalseJump && mEntryBlock->mTrueJump->mTrueJump == mExitBlock)
{
NativeCodeBasicBlock* block = mEntryBlock->mTrueJump;
int sz = block->mIns.Size();
if (sz < 20)
{
int cost = -6;
for (int i = 0; i < sz; i++)
{
const NativeCodeInstruction& ins(block->mIns[i]);
switch (ins.mType)
{
case ASMIT_LDA:
case ASMIT_LDX:
case ASMIT_LDY:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress >= BC_REG_FPARAMS && ins.mAddress < BC_REG_FPARAMS_END)
cost -= 2;
else
cost += AsmInsSize(ins.mType, ins.mMode);
break;
case ASMIT_STA:
case ASMIT_STX:
case ASMIT_STY:
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4)
cost -= 2;
else
cost += AsmInsSize(ins.mType, ins.mMode);
break;
case ASMIT_JSR:
if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_INLINE))
cost += 1000;
else
cost += 3;
break;
case ASMIT_TAX:
case ASMIT_TXA:
case ASMIT_TAY:
case ASMIT_TYA:
case ASMIT_ASL:
case ASMIT_LSR:
case ASMIT_ROL:
case ASMIT_ROR:
case ASMIT_CLC:
case ASMIT_SEC:
case ASMIT_INX:
case ASMIT_INY:
case ASMIT_DEX:
case ASMIT_DEY:
case ASMIT_ADC:
case ASMIT_SBC:
case ASMIT_AND:
case ASMIT_ORA:
case ASMIT_EOR:
case ASMIT_BIT:
case ASMIT_CMP:
case ASMIT_CPX:
case ASMIT_CPY:
cost += AsmInsSize(ins.mType, ins.mMode);
break;
default:
cost += 1000;
break;
}
}
if (cost <= 0)
{
mSimpleInline = true;
}
}
}
}
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
{
ResetVisited();
mEntryBlock->RegisterFunctionCalls();
}
}
void NativeCodeProcedure::Assemble(void)
{
CheckFunc = !strcmp(mInterProc->mIdent->mString, "data_check");
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
{
ResetVisited();
mEntryBlock->MergeFunctionCalls();
}
mEntryBlock->Assemble();
ResetVisited();
mEntryBlock = mEntryBlock->BypassEmptyBlocks();
ResetVisited();
mEntryBlock->ShortcutTailRecursion();
ExpandingArray<NativeCodeBasicBlock*> placement;
int total;
total = 0;
mEntryBlock->BuildPlacement(placement);
for (int i = 0; i < placement.Size(); i++)
placement[i]->InitialOffset(total);
bool progress;
do {
progress = false;
total = 0;
for (int i = 0; i < placement.Size(); i++)
if (placement[i]->CalculateOffset(total))
progress = true;
} while (progress);
uint8* data = mInterProc->mLinkerObject->AddSpace(total);
for (int i = 0; i < placement.Size(); i++)
{
LinkerObjectRange range;
char buffer[100];
if (placement[i]->mLoopHead)
sprintf_s(buffer, "l%d", placement[i]->mIndex);
else
sprintf_s(buffer, "s%d", placement[i]->mIndex);
range.mIdent = Ident::Unique(buffer);
range.mOffset = placement[i]->mOffset;
range.mSize = placement[i]->mSize;
mInterProc->mLinkerObject->mRanges.Push(range);
placement[i]->CopyCode(this, data);
}
for (int i = 0; i < mRelocations.Size(); i++)
{
LinkerReference& rl(mRelocations[i]);
rl.mObject = mInterProc->mLinkerObject;
if (!rl.mRefObject)
rl.mRefObject = mInterProc->mLinkerObject;
mInterProc->mLinkerObject->AddReference(rl);
}
if (mGenerator->mCompilerOptions & COPT_DEBUGINFO)
{
if (mCodeLocations.Size() > 0)
{
int i = 1, j = 0;
while (i < mCodeLocations.Size())
{
if (mCodeLocations[j].mEnd == mCodeLocations[i].mStart &&
mCodeLocations[j].mLocation.mFileName == mCodeLocations[i].mLocation.mFileName &&
mCodeLocations[j].mLocation.mLine == mCodeLocations[i].mLocation.mLine)
mCodeLocations[j].mEnd = mCodeLocations[i].mEnd;
else
mCodeLocations[++j] = mCodeLocations[i];
i++;
}
mCodeLocations.SetSize(j + 1);
mInterProc->mLinkerObject->AddLocations(mCodeLocations);
}
}
}
bool NativeCodeProcedure::MapFastParamsToTemps(void)
{
NumberSet used(256), modified(256), statics(256), pairs(256);
ResetVisited();
mEntryBlock->CollectZeroPageUsage(used, modified, pairs);
used.Fill();
for (int i = BC_REG_TMP; i < 256; i++)
used -= i;
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
if (!modified[i])
statics += i;
uint8 alias[256];
for (int i = 0; i < 256; i++)
alias[i] = 0;
ResetVisited();
mEntryBlock->FindZeroPageAlias(statics, used, alias, -1);
for (int i = 1; i < 256; i++)
{
if (used[i] || !alias[i] ||
(pairs[i] && (used[i + 1] || alias[i + 1] != alias[i] + 1)) ||
(pairs[i - 1] && (used[i - 1] || alias[i - 1] + 1 != alias[i])))
{
alias[i] = i;
}
}
NativeCodeBasicBlock* block = mEntryBlock;
while (block && block->mIns.Size() == 0 && !block->mFalseJump)
block = block->mTrueJump;
if (block && block->mNumEntries == 1)
{
used.Clear();
modified.Clear();
NumberSet tpairs(256), aliased(256);
for (int i = 1; i < 256; i++)
{
if (alias[i] != i)
aliased += alias[i];
}
ResetVisited();
if (block->mTrueJump)
block->mTrueJump->CollectZeroPageUsage(used, modified, tpairs);
if (block->mFalseJump)
block->mFalseJump->CollectZeroPageUsage(used, modified, tpairs);
for (int i = 0; i + 1 < block->mIns.Size(); i++)
{
if (block->mIns[i + 0].mType == ASMIT_LDA && block->mIns[i + 0].mMode == ASMIM_ZERO_PAGE && block->mIns[i + 0].mAddress >= BC_REG_FPARAMS && block->mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
block->mIns[i + 1].mType == ASMIT_STA && block->mIns[i + 1].mMode == ASMIM_ZERO_PAGE && block->mIns[i + 1].mAddress > BC_REG_TMP && !used[block->mIns[i + 0].mAddress] &&
!aliased[block->mIns[i + 0].mAddress])
{
if (!block->ReferencesZeroPage(block->mIns[i + 0].mAddress, i + 1) && !block->ReferencesZeroPage(block->mIns[i + 1].mAddress, 0, i))
{
alias[block->mIns[i + 1].mAddress] = block->mIns[i + 0].mAddress;
aliased += block->mIns[i + 0].mAddress;
}
}
}
for (int i = 1; i < 255; i++)
{
if ((pairs[i ] && alias[i + 1] != alias[i] + 1) ||
(pairs[i - 1] && alias[i - 1] + 1 != alias[i] ))
alias[i] = i;
}
}
ResetVisited();
return mEntryBlock->RemapZeroPage(alias);
}
void NativeCodeProcedure::RebuildEntry(void)
{
ResetVisited();
for (int i = 0; i < mBlocks.Size(); i++)
{
mBlocks[i]->mNumEntries = 0;
mBlocks[i]->mVisiting = false;
mBlocks[i]->mLoopHead = false;
mBlocks[i]->mFromJump = nullptr;
mBlocks[i]->mDominator = nullptr;
mBlocks[i]->mSameBlock = nullptr;
}
ResetVisited();
ResetEntryBlocks();
mEntryBlock->CountEntries(nullptr);
ResetVisited();
mEntryBlock->CollectEntryBlocks(nullptr);
NativeCodeBasicBlock::DominatorStacks stacks;
mEntryBlock->BuildDominatorTree(nullptr, stacks);
}
void NativeCodeProcedure::CheckBlocks(bool sequence)
{
#if _DEBUG
ResetChecked();
mEntryBlock->CheckBlocks();
#endif
}
void NativeCodeProcedure::Optimize(void)
{
#if 1
int step = 0;
int cnt = 0;
bool swappedXY = false;
CheckCase = false;
CheckBlocks();
bool changed, xmapped = false, ymapped = false;
do
{
changed = false;
RebuildEntry();
assert(mEntryBlock->mNumEntries < 2);
#if 1
if (step > 3)
{
ResetVisited();
if (mEntryBlock->FindSameBlocks(this))
{
ResetVisited();
changed = mEntryBlock->MergeSameBlocks(this);
}
}
#endif
RebuildEntry();
assert(mEntryBlock->mNumEntries < 2);
if (step == 4)
{
ResetVisited();
mEntryBlock->Split16BitLoopCount(this);
}
if (step >= 6)
{
ResetVisited();
mEntryBlock->CrossBlockYAliasProgpagation(nullptr);
}
RebuildEntry();
assert(mEntryBlock->mNumEntries < 2);
#if 1
if (step > 3)
{
NativeRegisterDataSet data;
bool bchanged;
do {
ResetVisited();
bchanged = mEntryBlock->BitFieldForwarding(data);
if (bchanged)
RebuildEntry();
else
{
ResetPatched();
mEntryBlock->CheckVisited();
}
} while (bchanged);
}
#endif
if (step >= 3)
{
ResetVisited();
mEntryBlock->RegisterValueForwarding();
}
#if 1
if (step == 2)
{
BuildDataFlowSets();
ResetVisited();
mEntryBlock->ReplaceFinalZeroPageUse(this);
}
#endif
if (step > 1)
{
ResetVisited();
mEntryBlock->LocalZeroPageValueNumbering();
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step == 9 || step == 16)
{
ResetVisited();
if (mEntryBlock->IndexXYValueForwarding(-1, 0, 0, -1, 0, 0))
changed = true;
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
int t = 0;
#if 1
do
{
RebuildEntry();
BuildDataFlowSets();
ResetVisited();
changed = mEntryBlock->RemoveUnusedResultInstructions();
if (step == 0)
{
ResetVisited();
ExpandingArray<NativeRegisterSum16Info> cinfo;
if (mEntryBlock->Propagate16BitSum(cinfo))
changed = true;
}
if (!changed)
{
ResetVisited();
NativeRegisterDataSet data;
if (mEntryBlock->ValueForwarding(this, data, step > 0, step == 8))
{
changed = true;
}
else
{
#if 1
ResetPatched();
mEntryBlock->CheckVisited();
if (step > 1)
{
ResetVisited();
if (mEntryBlock->GlobalValueForwarding(this, step == 8))
{
changed = true;
}
}
#endif
}
}
t++;
} while (changed && t < 20);
#endif
BuildDataFlowSets();
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
if (step == 8)
{
ResetVisited();
ValueNumberingDataSet data;
if (mEntryBlock->OffsetValueForwarding(data))
{
changed = true;
CheckBlocks();
BuildDataFlowSets();
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
}
}
CheckBlocks();
if (step == 9)
{
ResetVisited();
ExpandingArray<NativeCodeLoadStorePair> pairs;
if (mEntryBlock->AbsoluteValueForwarding(pairs))
{
changed = true;
CheckBlocks();
BuildDataFlowSets();
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
}
}
CheckBlocks();
#if 1
ResetVisited();
if (mEntryBlock->PeepHoleOptimizer(step))
changed = true;
#endif
if (step == 2)
{
ResetVisited();
if (mEntryBlock->ShortcutIndirectLoadStore())
changed = true;
}
#if 1
if (step >= 3)
{
ResetVisited();
if (mEntryBlock->ReverseBitfieldForwarding())
changed = true;
}
#endif
if (step == 5)
{
ResetVisited();
if (mEntryBlock->FoldLoopEntry())
changed = true;
}
#if 1
if (step < 7)
{
ResetVisited();
if (mEntryBlock->OptimizeSelect(this))
{
changed = true;
}
}
#if 1
if (step == 3)
{
ResetVisited();
if (mEntryBlock->RemoveSimpleLoopUnusedIndex())
changed = true;
}
#endif
#if 1
if (step == 3)
{
ResetVisited();
if (mEntryBlock->ShortcutPointerAddForward())
changed = true;
}
#endif
if (step == 5 && cnt < 10)
{
ResetVisited();
if (mEntryBlock->RemoveDoubleZPStore())
changed = true;
}
if (step == 3 || step == 5 || step == 9)
{
ResetVisited();
if (mEntryBlock->PropagateCommonSubExpression())
changed = true;
}
#if 1
CheckBlocks();
if (step > 0)
{
RebuildEntry();
ResetVisited();
if (mEntryBlock->OptimizeSimpleLoop(this, step > 5))
changed = true;
ResetVisited();
if (mEntryBlock->SimpleLoopReversal(this))
changed = true;
}
#endif
#if 1
CheckBlocks();
ResetVisited();
if (mEntryBlock->MergeBasicBlocks())
{
// changed = true;
BuildDataFlowSets();
CheckBlocks();
}
#endif
RebuildEntry();
CheckBlocks();
#if 1
if (step == 2)
{
if (MapFastParamsToTemps())
changed = true;
}
#endif
#if 1
if (step > 5 && !changed)
{
ResetVisited();
if (mEntryBlock->ShortcutCrossBlockMoves(this))
changed = true;
}
#endif
if (step > 6 && !changed)
{
ResetVisited();
if (mEntryBlock->ShortcutCrossBlockCondition())
changed = true;
}
CheckBlocks();
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step > 2 && !changed)
{
ResetVisited();
if (mEntryBlock->JoinTailCodeSequences(this, step > 4))
{
changed = true;
BuildDataFlowSets();
}
ResetVisited();
if (mEntryBlock->PropagateSinglePath())
changed = true;
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step > 2 && !changed)
{
ResetVisited();
if (mEntryBlock->JoinCommonBranchCodeSequences())
{
changed = true;
BuildDataFlowSets();
}
}
if (step > 4 && step != 6)
{
ResetVisited();
if (mEntryBlock->ShortcutBlockExit())
changed = true;
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step > 4)
{
ResetVisited();
if (mEntryBlock->ShortcutORACascade())
changed = true;
}
if (step > 6)
{
ResetVisited();
if (mEntryBlock->JoinEntryLoadStoreZP())
changed = true;
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
CheckBlocks();
#if 1
if (step == 3 || step == 4 || (step == 15 && cnt > 0))
{
#if 1
ResetVisited();
if (mEntryBlock->OptimizeInnerLoops(this))
changed = true;
#endif
CheckBlocks(true);
#if 1
ResetVisited();
if (mEntryBlock->OptimizeFindLoop(this))
changed = true;
#endif
CheckBlocks(true);
#if 1
ResetVisited();
if (mEntryBlock->ReduceLocalYPressure())
changed = true;
#endif
CheckBlocks(true);
#if 1
if (step == 4)
{
#if 1
ResetVisited();
if (!changed && mEntryBlock->LoopRegisterXYMap())
changed = true;
#endif
ResetVisited();
if (!changed && mEntryBlock->OptimizeGenericLoop(this))
changed = true;
}
#endif
CheckBlocks(true);
#if 1
ResetVisited();
if (!changed && mEntryBlock->ShortcutZeroPageCopyUp(this))
changed = true;
#endif
CheckBlocks(true);
#if 1
ResetVisited();
if (!changed && mEntryBlock->CrossBlockXYShortcut())
changed = true;
#endif
CheckBlocks(true);
#if 1
ResetVisited();
if (!changed && mEntryBlock->CrossBlockXYPreservation())
changed = true;
#endif
}
#endif
CheckBlocks();
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step > 4 && !changed)
{
ResetVisited();
if (mEntryBlock->OptimizeXYSimpleLoop())
changed = true;
}
if (step == 3)
{
ResetVisited();
if (mEntryBlock->EliminateUpper16BitSum(this))
changed = true;
}
CheckBlocks();
if (step == 3)
{
ResetVisited();
if (mEntryBlock->CrossBlockIncToZeroShortcut())
changed = true;
}
#if 1
if (!changed && (step == 5 || step == 6 || step == 19))
{
#if 1
int xregs[256], yregs[256];
for (int i = 0; i < 256; i++)
xregs[i] = yregs[i] = 0;
for (int i = 0; i < 4; i++)
{
xregs[BC_REG_ACCU + i] = -1;
yregs[BC_REG_ACCU + i] = -1;
xregs[BC_REG_WORK + i] = -1;
yregs[BC_REG_WORK + i] = -1;
}
if (!mInterProc->mLeafProcedure)
{
for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
{
xregs[i] = -1;
yregs[i] = -1;
}
}
if (xmapped)
xregs[0] = -1;
if (ymapped)
yregs[0] = -1;
ResetVisited();
mEntryBlock->GlobalRegisterXYCheck(xregs, yregs);
if (xregs[0] >= 0)
{
int j = 1;
for (int i = 0; i < 256; i++)
if (xregs[i] > xregs[j])
j = i;
if (xregs[j] > 2)
{
ResetVisited();
mEntryBlock->GlobalRegisterXMap(j);
if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA)
mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_ZERO_PAGE, j));
changed = true;
xmapped = true;
continue;
}
}
if (!changed && yregs[0] >= 0)
{
int j = 1;
for (int i = 0; i < 256; i++)
if (yregs[i] > yregs[j])
j = i;
if (yregs[j] > 2)
{
ResetVisited();
mEntryBlock->GlobalRegisterYMap(j);
if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA)
mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_ZERO_PAGE, j));
changed = true;
ymapped = true;
continue;
}
}
#endif
if (!changed)
{
if (step == 5)
{
ResetVisited();
mEntryBlock->ReduceLocalXPressure();
}
else
{
ResetVisited();
if (mEntryBlock->LocalRegisterXYMap())
changed = true;
}
}
}
#endif
CheckBlocks();
#if 1
ResetVisited();
NativeRegisterDataSet data;
mEntryBlock->BuildEntryDataSet(data);
ResetVisited();
if (mEntryBlock->ApplyEntryDataSet())
changed = true;
#endif
if (step == 2 && !changed)
{
ResetVisited();
if (mEntryBlock->CombineSameXY())
changed = true;
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step >= 5)
{
if (step == 9)
{
ResetVisited();
mEntryBlock->ReduceLocalYPressure();
}
ResetVisited();
if (mEntryBlock->MoveAccuTrainsUp())
changed = true;
ResetVisited();
if (mEntryBlock->MoveAccuTrainsDown())
changed = true;
ResetVisited();
if (mEntryBlock->CombineSameXY())
changed = true;
ResetVisited();
if (mEntryBlock->RecycleImmediates())
changed = true;
ResetVisited();
if (mEntryBlock->RecycleLoadStore())
changed = true;
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step == 7)
{
ResetVisited();
if (mEntryBlock->SinglePathRegisterForward())
changed = true;
}
if (step > 7)
{
ResetVisited();
if (mEntryBlock->SinglePathStoreForward())
changed = true;
}
CheckBlocks();
if (step == 7)
{
ResetVisited();
if (mEntryBlock->CrossBlockRegisterAlias(false, false))
changed = true;
}
if (step == 8)
{
ResetVisited();
if (mEntryBlock->JoinXYCascade())
changed = true;
}
#if 1
if (step == 9 && cnt < 10)
{
CheckBlocks();
ResetVisited();
while (mEntryBlock->OptimizeXYSpilling())
{
BuildDataFlowSets();
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
changed = true;
}
CheckBlocks();
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step == 6)
{
ResetVisited();
if (mEntryBlock->AlternateXYUsage())
changed = true;
ResetVisited();
if (mEntryBlock->OptimizeXYPairUsage())
changed = true;
ResetVisited();
if (mEntryBlock->UntangleXYUsage())
changed = true;
}
#endif
CheckBlocks();
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
ResetVisited();
if (mEntryBlock->ForwardAccuAddSub())
changed = true;
#endif
#if 1
ResetVisited();
if (mEntryBlock->ForwardZpYIndex(step >= 5))
changed = true;
#endif
#if 1
ResetVisited();
if (mEntryBlock->ForwardZpXIndex(step >= 5))
changed = true;
#endif
CheckBlocks();
#if 1
if (step == 6)
{
ResetVisited();
if (mEntryBlock->SimplifyDiamond(this))
changed = true;
CheckBlocks();
ResetVisited();
if (mEntryBlock->SimplifyLoopEnd(this))
changed = true;
CheckBlocks();
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step >= 6)
{
ResetVisited();
if (mEntryBlock->BypassRegisterConditionBlock())
changed = true;
}
if (step == 8)
{
ResetVisited();
if (mEntryBlock->LoopRegisterWrapAround())
changed = true;
}
#if 0
if (step == 12)
{
ResetVisited();
if (mEntryBlock->JoinXYCrossBlock())
changed = true;
}
#endif
if (step >= 9)
{
ResetVisited();
if (mEntryBlock->EliminateDeadLoops())
changed = true;
}
CheckBlocks();
if (step == 6 || step == 7)
{
ResetVisited();
if (mEntryBlock->Propagate16BitHighSum())
changed = true;
}
if (step == 8)
{
ResetVisited();
if (mEntryBlock->SimplifyDiamond(this))
changed = true;
}
CheckBlocks();
#if 1
if (step == 8)
{
ResetVisited();
if (mEntryBlock->CrossBlockXYFlood(this))
changed = true;
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step == 8)
{
ResetVisited();
if (mEntryBlock->CrossBlockY2XFlood(this))
changed = true;
}
#endif
if (step == 8)
{
ResetVisited();
if (mEntryBlock->CrossBlock16BitFlood(this))
changed = true;
}
#if 1
if (step >= 7)
{
ResetVisited();
NativeRegisterDataSet data;
mEntryBlock->BuildEntryDataSet(data);
ResetVisited();
if (mEntryBlock->ExpandADCToBranch(this))
changed = true;
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step == 9)
{
RebuildEntry();
ResetVisited();
if (mEntryBlock->OptimizeSingleEntryLoop(this))
changed = true;
}
#endif
RebuildEntry();
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (step == 2 && !changed)
{
ResetVisited();
if (mEntryBlock->CrossBlockStoreLoadBypass(this))
changed = true;
}
#endif
#if 1
if (step == 10 && (mInterProc->mCompilerOptions & COPT_OPTIMIZE_BASIC))
{
ResetVisited();
mEntryBlock->MarkLocalUsedLinkerObjects();
ResetVisited();
if (mEntryBlock->RemoveLocalUnusedLinkerObjects())
changed = true;
}
#endif
#endif
if (step == 8)
{
ResetVisited();
if (mEntryBlock->ForwardAXYReg())
changed = true;
}
#if 1
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step == 10)
{
if (changed)
swappedXY = false;
else if (!swappedXY)
{
ResetVisited();
if (mEntryBlock->CanGlobalSwapXY())
{
ResetVisited();
changed = mEntryBlock->GlobalSwapXY();
swappedXY = true;
}
}
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
if (step == 11)
{
if (changed && cnt < 20)
swappedXY = false;
else if (!swappedXY)
{
ResetVisited();
changed = mEntryBlock->LocalSwapXY();
swappedXY = true;
}
}
#endif
#if 1
if (step == 12)
{
ResetVisited();
bool cc = mEntryBlock->GlobalLoadStoreForwarding(false, NativeCodeInstruction(), NativeCodeInstruction(), NativeCodeInstruction());
if (!cc)
{
ResetVisited();
cc = mEntryBlock->GlobalLoadStoreForwarding(true, NativeCodeInstruction(), NativeCodeInstruction(), NativeCodeInstruction());
}
if (cc)
{
ResetVisited();
NativeRegisterDataSet data;
mEntryBlock->BuildEntryDataSet(data);
changed = true;
}
}
#endif
#if 1
if (step == 14 && cnt == 0)
{
ResetVisited();
mEntryBlock->BypassAccuLoadStoreXY();
changed = true;
}
#endif
#if 1
if (step == 15 && cnt == 0)
{
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
BuildDataFlowSets();
ResetVisited();
if (mEntryBlock->AlternateXXUsage())
changed = true;
}
#endif
if (step == 16)
{
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_INLINE)
{
ResetVisited();
if (mEntryBlock->SimpleInlineCalls())
changed = true;
}
}
if (step == 17)
{
if (!(mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
{
ResetVisited();
if (mEntryBlock->Expand16BitLoopBranch())
changed = true;
}
}
if (step == 18)
{
ResetVisited();
if (mEntryBlock->PartialBackwardValuePropagation())
changed = true;
if (!changed)
{
ResetVisited();
if (mEntryBlock->HoistCommonLoads())
changed = true;
}
}
#if _DEBUG
ResetVisited();
mEntryBlock->CheckAsmCode();
#endif
#if 1
if (cnt > 190)
{
printf("Oops %d\n", step);
}
#endif
if (cnt > 200)
{
changed = false;
mGenerator->mErrors->Error(mInterProc->mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mInterProc->mIdent);
}
#if 1
if (!changed && step < 19)
{
ResetIndexFlipped();
cnt = 0;
step++;
changed = true;
swappedXY = false;
}
#endif
else
cnt++;
} while (changed);
#if 1
ResetVisited();
mEntryBlock->ReduceLocalYPressure();
#endif
#if 1
BuildDataFlowSets();
CompressTemporaries(false);
BuildDataFlowSets();
CompressTemporaries(false);
BuildDataFlowSets();
CompressTemporaries(true);
#endif
do {
ResetVisited();
NativeRegisterDataSet data;
mEntryBlock->BuildEntryDataSet(data);
ResetVisited();
} while (mEntryBlock->ExpandADCToBranch(this));
do {
ResetVisited();
} while (mEntryBlock->EliminateMicroBlocks());
#if 1
do
{
RebuildEntry();
BuildDataFlowSets();
ResetVisited();
changed = mEntryBlock->RemoveUnusedResultInstructions();
if (!changed)
{
ResetVisited();
NativeRegisterDataSet data;
if (mEntryBlock->ValueForwarding(this, data, true, true))
{
changed = true;
}
else
{
#if 1
ResetPatched();
mEntryBlock->CheckVisited();
ResetVisited();
if (mEntryBlock->GlobalValueForwarding(this, true))
changed = true;
#endif
}
}
BuildDataFlowSets();
ResetVisited();
if (mEntryBlock->RemoveUnusedResultInstructions())
changed = true;
CheckBlocks();
if (!changed)
{
ResetVisited();
changed = mEntryBlock->PeepHoleOptimizer(20);
}
if (!changed)
{
ResetVisited();
changed = mEntryBlock->JoinTailCodeSequences(this, true);
}
} while (changed);
#endif
ResetVisited();
mEntryBlock->OptimizeLoopCarryOver();
ResetVisited();
NativeRegisterDataSet data;
mEntryBlock->ValueForwarding(this, data, true, true);
ResetVisited();
mEntryBlock->CrossBlockFlagsForwarding();
ResetVisited();
data.Reset();
mEntryBlock->PropagateZPAbsolute(data);
ResetVisited();
mEntryBlock->PropagateAddGlobalCarry();
BuildDataFlowSets();
ResetVisited();
mEntryBlock->RemoveUnusedResultInstructions();
ResetVisited();
mEntryBlock->RemoveJumpToBranch();
#if 1
ResetVisited();
data.Reset();
mEntryBlock->BuildEntryDataSet(data);
ResetVisited();
if (mEntryBlock->ApplyEntryDataSet())
changed = true;
#endif
#if 1
ResetVisited();
mEntryBlock->BlockSizeReduction(this, -1, -1);
ResetVisited();
mEntryBlock->MergeBasicBlocks();
#endif
#endif
}
void NativeCodeProcedure::BuildDataFlowSets(void)
{
//
// Build set with local provided/required temporaries
//
ResetVisited();
mBlocks[0]->BuildLocalRegSets();
//
// Build set of globally provided temporaries
//
ResetVisited();
mBlocks[0]->BuildGlobalProvidedRegSet(NumberSet(NUM_REGS));
//
// Build set of globally required temporaries, might need
// multiple iterations until it stabilizes
//
NumberSet totalRequired(NUM_REGS);
do {
ResetVisited();
} while (mBlocks[0]->BuildGlobalRequiredRegSet(totalRequired));
}
NativeCodeBasicBlock* NativeCodeProcedure::AllocateBlock(void)
{
NativeCodeBasicBlock* block = new NativeCodeBasicBlock(this);
block->mNoFrame = mNoFrame;
block->mFrameOffset = mFrameOffset;
block->mIndex = mTempBlocks++;
mBlocks.Push(block);
return block;
}
NativeCodeBasicBlock* NativeCodeProcedure::CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* sblock)
{
if (tblocks[sblock->mIndex])
return tblocks[sblock->mIndex];
NativeCodeBasicBlock* block = new NativeCodeBasicBlock(this);
block->mNoFrame = mNoFrame;
block->mFrameOffset = mFrameOffset;
mBlocks.Push(block);
tblocks[sblock->mIndex] = block;
block->mIndex = sblock->mIndex;
CompileInterBlock(iproc, sblock, block);
return block;
}
void NativeCodeProcedure::ResetEntryBlocks(void)
{
for (int i = 0; i < mBlocks.Size(); i++)
mBlocks[i]->mEntryBlocks.SetSize(0);
}
void NativeCodeProcedure::ResetIndexFlipped(void)
{
for (int i = 0; i < mBlocks.Size(); i++)
{
for (int j = 0; j < mBlocks[i]->mIns.Size(); j++)
mBlocks[i]->mIns[j].mFlags &= ~NICT_INDEXFLIPPED;
}
}
void NativeCodeProcedure::ResetPatched(void)
{
for (int i = 0; i < mBlocks.Size(); i++)
{
NativeCodeBasicBlock* b = mBlocks[i];
b->mPatched = false;
b->mPatchFail = false;
b->mPatchChecked = false;
b->mPatchStart = false;
b->mPatchLoop = false;
b->mPatchLoopChanged = false;
b->mPatchExit = false;
}
}
void NativeCodeProcedure::ResetChecked(void)
{
for (int i = 0; i < mBlocks.Size(); i++)
{
mBlocks[i]->mChecked = false;
}
}
void NativeCodeProcedure::ResetVisited(void)
{
for (int i = 0; i < mBlocks.Size(); i++)
{
// assert(mBlocks[i]->mIns.Size() > 0 || (mBlocks[i]->mTrueJump != mBlocks[i] && mBlocks[i]->mFalseJump != mBlocks[i]));
mBlocks[i]->mVisited = false;
mBlocks[i]->mNumEntered = 0;
mBlocks[i]->mLoopHeadBlock = nullptr;
}
}
void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* iblock, NativeCodeBasicBlock* block)
{
int i = 0;
while (i < iblock->mInstructions.Size())
{
const InterInstruction * ins = iblock->mInstructions[i];
switch (ins->mCode)
{
case IC_STORE:
if (i + 1 < iblock->mInstructions.Size() &&
ins->mSrc[0].mType == IT_INT8 &&
ins->mSrc[0].mTemp >= 0 &&
ins->mSrc[1].mTemp >= 0 &&
iblock->mInstructions[i + 1]->mCode == IC_STORE &&
iblock->mInstructions[i + 1]->mSrc[0].mType == IT_INT8 &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mSrc[0].mTemp &&
iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp >= 0)
{
block->LoadStoreIndirectPair(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else
block->StoreValue(iproc, ins);
break;
case IC_LOAD:
if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_STORE &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp &&
iblock->mInstructions[i + 1]->mSrc[0].mFinal)
{
block->LoadStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 2 < iblock->mInstructions.Size() &&
(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
iblock->mInstructions[i + 2]->mCode == IC_STORE &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp &&
(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
block->LoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], 1, iblock->mInstructions[i + 2]))
{
i += 2;
}
else if (i + 2 < iblock->mInstructions.Size() &&
(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
iblock->mInstructions[i + 2]->mCode == IC_STORE &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp &&
(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
block->LoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], 0, iblock->mInstructions[i + 2]))
{
i += 2;
}
else if (i + 2 < iblock->mInstructions.Size() &&
(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
iblock->mInstructions[i + 1]->mCode == IC_UNARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
iblock->mInstructions[i + 2]->mCode == IC_STORE &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp &&
(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
block->LoadUnopStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]))
{
i += 2;
}
else if (i + 3 < iblock->mInstructions.Size() &&
(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD &&
iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
iblock->mInstructions[i + 3]->mCode == IC_STORE &&
iblock->mInstructions[i + 3]->mSrc[0].mTemp == iblock->mInstructions[i + 2]->mDst.mTemp && //iblock->mInstructions[i + 3]->mSrc[0].mFinal &&
block->LoadLoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2], iblock->mInstructions[i + 3]))
{
i += 3;
}
else if (i + 3 < iblock->mInstructions.Size() &&
(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD &&
iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 2]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
iblock->mInstructions[i + 3]->mCode == IC_STORE &&
iblock->mInstructions[i + 3]->mSrc[0].mTemp == iblock->mInstructions[i + 2]->mDst.mTemp && //iblock->mInstructions[i + 3]->mSrc[0].mFinal &&
block->LoadLoadOpStoreIndirectValue(iproc, iblock->mInstructions[i + 1], ins, iblock->mInstructions[i + 2], iblock->mInstructions[i + 3]))
{
i += 3;
}
else if (i + 1 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal)
{
block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], ins, ins);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
{
block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], nullptr, ins);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride < 256 &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal)
{
block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], ins, nullptr);
i++;
}
else if (i + 2 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD && InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] >= 2 &&
InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] * iblock->mInstructions[i + 1]->mSrc[0].mStride <= 256 &&
iblock->mInstructions[i + 1]->mDst.mTemp != ins->mDst.mTemp &&
iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mType == iblock->mInstructions[i + 1]->mDst.mType && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
iblock->mInstructions[i + 2]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 2]->mSrc[1].mFinal)
{
block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 2], ins, iblock->mInstructions[i + 1]);
i += 2;
}
else if (i + 2 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD && InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] >= 2 &&
InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] * iblock->mInstructions[i + 1]->mSrc[0].mStride <= 256 &&
iblock->mInstructions[i + 1]->mDst.mTemp != ins->mDst.mTemp &&
iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mType == iblock->mInstructions[i + 1]->mDst.mType && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 2]->mSrc[0].mFinal)
{
block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 2], iblock->mInstructions[i + 1], ins);
i += 2;
}
else if (i + 1 < iblock->mInstructions.Size() &&
InterTypeSize[ins->mDst.mType] >= 2 &&
iblock->mInstructions[i + 1]->mCode == IC_LEA &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
!(iblock->mInstructions[i + 1]->mSrc[0].IsUByte() &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 &&
i + 2 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 2]->mCode == IC_LOAD &&
iblock->mInstructions[i + 2]->mSrc->mTemp == iblock->mInstructions[i + 1]->mDst.mTemp))
{
block->LoadEffectiveAddress(iproc, iblock->mInstructions[i + 1], ins, nullptr, false);
i++;
}
else
block->LoadValue(iproc, ins);
break;
case IC_FILL:
block = block->FillValue(iproc, ins, this);
break;
case IC_COPY:
block = block->CopyValue(iproc, ins, this);
break;
case IC_STRCPY:
block = block->StrcpyValue(iproc, ins, this);
break;
case IC_MALLOC:
block->CallMalloc(iproc, ins, this);
break;
case IC_FREE:
block->CallFree(iproc, ins, this);
break;
case IC_BREAKPOINT:
{
NativeCodeGenerator::Runtime& frt(mGenerator->ResolveRuntime(Ident::Unique("breakpoint")));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_LOWER | NCIF_UPPER | NCIF_VOLATILE | NCIF_BREAKPOINT));
} break;
case IC_LOAD_TEMPORARY:
{
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
for (int i = 0; i < InterTypeSize[ins->mDst.mType]; i++)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + i));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + i));
}
}
} break;
case IC_BINARY_OPERATOR:
if (i + 1 < iblock->mInstructions.Size() &&
ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_ADD && ins->mSrc[1].IsSByte() && ins->mSrc[0].mTemp < 0 &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[i + 1]->mOperator == IA_SAR &&
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0 && iblock->mInstructions[i + 1]->mSrc[0].mIntConst <= 4 &&
ins->mSrc[0].mIntConst == (1LL << (iblock->mInstructions[i + 1]->mSrc[0].mIntConst - 1)))
{
block->AddAsrSignedByte(iproc, ins, iblock->mInstructions[i + 1]);
i ++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_DIVU &&
iblock->mInstructions[i + 1]->mOperator == IA_MODU &&
ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
block->BinaryDivModPair(iproc, this, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_MODU &&
iblock->mInstructions[i + 1]->mOperator == IA_DIVU &&
ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
{
block->BinaryDivModPair(iproc, this, iblock->mInstructions[i + 1], ins);
i++;
}
else
block = block->BinaryOperator(iproc, this, ins, nullptr, nullptr);
break;
case IC_UNARY_OPERATOR:
if (i + 1 < iblock->mInstructions.Size() && ins->mOperator == IA_NEG && iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
{
block->LoadEffectiveAddress(iproc, iblock->mInstructions[i + 1], nullptr, ins, false);
i++;
}
else if (i + 2 < iblock->mInstructions.Size() && ins->mOperator == IA_NEG &&
iblock->mInstructions[i + 2]->mCode == IC_LEA && iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal)
{
block->LoadEffectiveAddress(iproc, iblock->mInstructions[i + 2], iblock->mInstructions[i + 1], ins, false);
i+=2;
}
else
block->UnaryOperator(iproc, this, ins);
break;
case IC_CONVERSION_OPERATOR:
if (i + 1 < iblock->mInstructions.Size() &&
ins->mOperator == IA_EXT8TO16S &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[i + 1]->mOperator == IA_ADD &&
(iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal && iblock->mInstructions[i + 1]->mSrc[1].mTemp < 0 ||
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0))
{
block->SignExtendAddImmediate(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
(iproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) &&
(ins->mOperator == IA_INT2FLOAT || ins->mOperator == IA_UINT2FLOAT) &&
ins->mSrc[0].IsSByte() && ins->mSrc[0].mRange.mMaxValue - ins->mSrc[0].mRange.mMinValue < 16 &&
iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
(iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal && iblock->mInstructions[i + 1]->mSrc[1].mTemp < 0 ||
iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0))
{
block->BinaryFloatOperatorLookup(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else
block->NumericConversion(iproc, this, ins);
break;
case IC_LEA:
{
bool avalid = false;
if (i + 1 < iblock->mInstructions.Size())
{
if (iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp)
avalid = true;
else if (iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp)
avalid = true;
else if (iblock->mInstructions[i + 1]->mCode == IC_COPY && (iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp || iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp))
avalid = true;
}
#if 1
if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
iblock->mInstructions[i + 1]->mSrc[0].mIntConst == 0 &&
(ins->mSrc[0].mRange.mMaxValue + InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] <= 256 || iblock->mInstructions[i + 1]->mSrc[0].mStride == 1))
{
block->LoadByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
iblock->mInstructions[i + 1]->mSrc[1].mIntConst == 0 && (iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) &&
(InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] == 1 || iblock->mInstructions[i + 1]->mSrc[1].mStride == 1))
{
block->StoreByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
iblock->mInstructions[i + 1]->mSrc[1].mIntConst + ins->mSrc[0].mRange.mMaxValue + InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] <= 256 &&
(iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) &&
(InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] == 1 || iblock->mInstructions[i + 1]->mSrc[1].mStride == 1))
{
block->StoreByteOffsetIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
{
block->StoreAbsoluteByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 1 < iblock->mInstructions.Size() &&
iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
{
block->LoadAbsoluteByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
i++;
}
else if (i + 2 < iblock->mInstructions.Size() &&
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mLinkerObject->mSize <= 256 &&
// ins->mSrc[0].IsUByte() &&
iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
// iblock->mInstructions[i + 1]->mSrc[0].IsUByte() &&
iblock->mInstructions[i + 2]->mCode == IC_LOAD && iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal)
{
block->LoadStoreOpAbsolute2D(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]);
i += 2;
}
else if (i + 2 < iblock->mInstructions.Size() &&
ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mLinkerObject->mSize <= 256 &&
// ins->mSrc[0].IsUByte() &&
iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
// iblock->mInstructions[i + 1]->mSrc[0].IsUByte() &&
iblock->mInstructions[i + 2]->mCode == IC_STORE && iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal)
{
block->LoadStoreOpAbsolute2D(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]);
i += 2;
}
else
#endif
{
block->LoadEffectiveAddress(iproc, ins, nullptr, nullptr, avalid);
}
}
break;
case IC_CONSTANT:
block->LoadConstant(iproc, ins);
break;
case IC_DISPATCH:
case IC_CALL:
block->CallFunction(iproc, this, ins);
break;
case IC_CALL_NATIVE:
case IC_ASSEMBLER:
block->CallAssembler(iproc, this, ins);
break;
case IC_PUSH_FRAME:
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
} break;
case IC_POP_FRAME:
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
} break;
case IC_RELATIONAL_OPERATOR:
if (i + 1 < iblock->mInstructions.Size() && iblock->mInstructions[i + 1]->mCode == IC_BRANCH && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
{
block->RelationalOperator(iproc, ins, this, CompileBlock(iproc, iblock->mTrueJump), CompileBlock(iproc, iblock->mFalseJump));
return;
}
else
{
NativeCodeBasicBlock* tblock, * fblock, * rblock;
tblock = AllocateBlock();
fblock = AllocateBlock();
rblock = AllocateBlock();
block->RelationalOperator(iproc, ins, this, tblock, fblock);
tblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 1));
tblock->Close(ins, rblock, nullptr, ASMIT_JMP);
fblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
fblock->Close(ins, rblock, nullptr, ASMIT_JMP);
rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
if (InterTypeSize[ins->mDst.mType] > 1)
{
rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + 1));
}
block = rblock;
}
break;
case IC_RETURN_VALUE:
{
if (!mExitBlock->mBranchIns)
mExitBlock->mBranchIns = ins;
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mType == IT_FLOAT)
{
union { float f; unsigned int v; } cc;
cc.f = float(ins->mSrc[0].mFloatConst);
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mExitBlock->mIns[0].mFlags |= NCIF_LOWER | NCIF_UPPER | NCIF_LONG;
}
else
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mExitBlock->mIns[0].mFlags |= NCIF_LOWER;
if (InterTypeSize[ins->mSrc[0].mType] > 1)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mExitBlock->mIns[0].mFlags |= NCIF_UPPER;
if (InterTypeSize[ins->mSrc[0].mType] > 2)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mExitBlock->mIns[0].mFlags |= NCIF_LONG;
}
}
}
}
else
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
mExitBlock->mIns[0].mFlags |= NCIF_LOWER;
if (InterTypeSize[ins->mSrc[0].mType] > 1)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mExitBlock->mIns[0].mFlags |= NCIF_UPPER;
if (InterTypeSize[ins->mSrc[0].mType] > 2)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
mExitBlock->mIns[0].mFlags |= NCIF_LONG;
}
}
}
block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
return;
}
case IC_RETURN:
if (!mExitBlock->mBranchIns)
mExitBlock->mBranchIns = ins;
block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
return;
case IC_TYPECAST:
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
if (InterTypeSize[ins->mDst.mType] > 1)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + 1));
}
}
break;
case IC_BRANCH:
if (ins->mSrc[0].mTemp < 0)
{
if (ins->mSrc[0].mIntConst == 0)
block->Close(ins, CompileBlock(iproc, iblock->mFalseJump), nullptr, ASMIT_JMP);
else
block->Close(ins, CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP);
}
else
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
if (InterTypeSize[ins->mSrc[0].mType] > 1)
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
if (InterTypeSize[ins->mSrc[0].mType] > 2)
{
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2));
block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3));
}
block->Close(ins, CompileBlock(iproc, iblock->mTrueJump), CompileBlock(iproc, iblock->mFalseJump), ASMIT_BNE);
}
return;
case IC_UNREACHABLE:
block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
return;
}
i++;
}
block->Close(nullptr, CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP);
}
NativeCodeGenerator::NativeCodeGenerator(Errors* errors, Linker* linker, LinkerSection* runtimeSection)
: mErrors(errors), mLinker(linker), mRuntimeSection(runtimeSection), mCompilerOptions(COPT_DEFAULT), mFunctionCalls(nullptr)
{
}
NativeCodeGenerator::~NativeCodeGenerator(void)
{
}
void NativeCodeGenerator::CompleteRuntime(void)
{
PopulateShortMulTables();
}
void NativeCodeGenerator::PopulateShortMulTables(void)
{
for (int i = 0; i < mMulTables.Size(); i++)
{
const MulTable& m(mMulTables[i]);
if (m.mLinkerLSB->mSize != m.mSize)
{
m.mLinkerLSB->AddSpace(m.mSize);
m.mLinkerMSB->AddSpace(m.mSize);
for (int j = 0; j < m.mSize; j++)
{
int val = m.mFactor;
switch (m.mOperator)
{
case IA_MUL:
val *= j;
break;
case IA_SHL:
val <<= j;
break;
case IA_SHR:
val = (val & 0xffff) >> j;
break;
case IA_SAR:
val = (int)(short)val >> j;
break;
}
m.mLinkerLSB->mData[j] = (uint8)(val);
m.mLinkerMSB->mData[j] = (uint8)(val >> 8);
}
}
}
for (int i = 0; i < mFloatTables.Size(); i++)
{
const FloatTable& f(mFloatTables[i]);
if (f.mLinker[0]->mSize != f.mMaxValue + 1 - f.mMinValue)
{
for (int j = 0; j < 4; j++)
f.mLinker[j]->AddSpace(f.mMaxValue + 1 - f.mMinValue);
}
for (int j = f.mMinValue; j <= f.mMaxValue; j++)
{
union {
float f;
uint8 u[4];
} fu;
switch (f.mOperator)
{
case IA_MUL:
fu.f = f.mConst * float(j);
break;
case IA_ADD:
fu.f = f.mConst * float(j);
break;
case IA_SUB:
if (f.mReverse)
fu.f = f.mConst - float(j);
else
fu.f = float(j) - f.mConst;
break;
case IA_DIVS:
if (f.mReverse)
fu.f = f.mConst / float(j);
else
fu.f = float(j) / f.mConst;
break;
}
for (int k = 0; k < 4; k++)
f.mLinker[k]->mData[j - f.mMinValue] = fu.u[k];
}
}
}
LinkerObject* NativeCodeGenerator::AllocateFloatTable(InterOperator op, bool reverse, int minval, int maxval, float fval, int index)
{
int i = 0;
while (i < mFloatTables.Size() &&
(mFloatTables[i].mOperator != op ||
mFloatTables[i].mReverse != reverse ||
mFloatTables[i].mConst != fval ||
mFloatTables[i].mMinValue != minval))
i++;
if (i == mFloatTables.Size())
{
Location loc;
FloatTable ft;
char name[60];
const char* base = "";
switch (op)
{
case IA_MUL:
base = "fmul";
break;
case IA_ADD:
base = "fadd";
break;
case IA_SUB:
if (reverse)
base = "frsub";
else
base = "fsub";
break;
case IA_DIVS:
if (reverse)
base = "frdiv";
else
base = "fdiv";
break;
}
for (int i = 0; i < 4; i++)
{
sprintf_s(name, "__%stab%d_%d_%f", base, i, minval, fval);
ft.mLinker[i] = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);
ft.mLinker[i]->mFlags |= LOBJF_CONST;
}
ft.mOperator = op;
ft.mReverse = reverse;
ft.mConst = fval;
ft.mMinValue = minval;
ft.mMaxValue = maxval;
mFloatTables.Push(ft);
return ft.mLinker[index];
}
else
{
if (maxval > mFloatTables[i].mMaxValue)
mFloatTables[i].mMaxValue = maxval;
return mFloatTables[i].mLinker[index];
}
}
LinkerObject* NativeCodeGenerator::AllocateShortMulTable(InterOperator op, int factor, int size, bool msb)
{
assert(size > 0);
int i = 0;
while (i < mMulTables.Size() && (mMulTables[i].mFactor != factor || mMulTables[i].mOperator != op))
i++;
if (i == mMulTables.Size())
{
Location loc;
MulTable mt;
char name[20];
const char* base = "";
switch (op)
{
case IA_MUL:
base = "mul";
break;
case IA_SHL:
base = "shl";
break;
case IA_SHR:
base = "shr";
break;
case IA_SAR:
base = "sar";
break;
}
sprintf_s(name, "__%stab%dL", base, factor);
mt.mLinkerLSB = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);
sprintf_s(name, "__%stab%dH", base, factor);
mt.mLinkerMSB = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);
mt.mLinkerLSB->mFlags |= LOBJF_CONST;
mt.mLinkerMSB->mFlags |= LOBJF_CONST;
mt.mFactor = factor;
mt.mSize = size;
mt.mOperator = op;
mMulTables.Push(mt);
return msb ? mt.mLinkerMSB : mt.mLinkerLSB;
}
else
{
if (size > mMulTables[i].mSize)
mMulTables[i].mSize = size;
return msb ? mMulTables[i].mLinkerMSB : mMulTables[i].mLinkerLSB;
}
}
NativeCodeGenerator::Runtime& NativeCodeGenerator::ResolveRuntime(const Ident* ident)
{
int i = 0;
while (i < mRuntime.Size() && mRuntime[i].mIdent != ident)
i++;
Location loc;
if (i == mRuntime.Size() || !mRuntime[i].mLinkerObject)
mErrors->Error(loc, EERR_RUNTIME_CODE, "Undefined runtime function", ident->mString);
return mRuntime[i];
}
static inline bool isfparam(const NativeCodeInstruction & cins, const NativeCodeInstruction & ins)
{
if (cins.mFlags & NCIF_RUNTIME)
{
if (ins.mAddress >= BC_REG_WORK && ins.mAddress < BC_REG_WORK + 8)
return true;
if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4)
return true;
}
else
{
if (ins.mAddress >= BC_REG_FPARAMS && ins.mAddress < BC_REG_FPARAMS_END)
return true;
}
return false;
}
void NativeCodeGenerator::RegisterFunctionCall(NativeCodeBasicBlock* block, int at)
{
LinkerObject* lo = block->mIns[at].mLinkerObject;
if (lo->mIdent)// && !(block->mIns[at].mFlags & NCIF_USE_ZP_32_X))
{
uint64 fpmask = 0;
int i = at;
while (i >= 2 &&
block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE &&
isfparam(block->mIns[at], block->mIns[i - 1]) &&
block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE || block->mIns[i - 2].mMode == ASMIM_ABSOLUTE))
{
if (block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE && block->mIns[i - 2].mAddress >= BC_REG_FPARAMS && block->mIns[i - 2].mAddress < BC_REG_FPARAMS_END)
{
if (fpmask & (1ull << (block->mIns[i - 2].mAddress - BC_REG_WORK)))
break;
}
fpmask |= 1ull << (block->mIns[i - 1].mAddress - BC_REG_WORK);
i -= 2;
}
if (i < at)
{
FunctionCall* ncp = new FunctionCall();
ncp->mLinkerObject = lo;
ncp->mOffset = block->mIns[at].mAddress;
ncp->mProxyObject = nullptr;
ncp->mCount = 1;
while (i < at)
{
ncp->mIns[block->mIns[i + 1].mAddress - BC_REG_WORK] = block->mIns[i];
i += 2;
}
FunctionCall* cp = mFunctionCalls;
while (cp && (cp->mLinkerObject != ncp->mLinkerObject || cp->mOffset != ncp->mOffset))
cp = cp->mNext;
if (!cp)
{
ncp->mNext = mFunctionCalls;
mFunctionCalls = ncp;
ncp->mSame = nullptr;
}
else
{
FunctionCall* scp = cp;
while (scp && !scp->IsSame(ncp))
scp = scp->mSame;
if (!scp)
{
ncp->mSame = cp->mSame;
cp->mSame = ncp;
}
else
{
scp->mCount++;
ncp = scp;
}
}
}
}
}
bool NativeCodeGenerator::MergeFunctionCall(NativeCodeBasicBlock* block, int at)
{
LinkerObject* lo = block->mIns[at].mLinkerObject;
if (lo->mIdent)
{
uint64 fpmask = 0;
int i = at;
while (i >= 2 &&
block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE &&
isfparam(block->mIns[at], block->mIns[i - 1]) &&
block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE || block->mIns[i - 2].mMode == ASMIM_ABSOLUTE))
{
if (block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE && block->mIns[i - 2].mAddress >= BC_REG_FPARAMS && block->mIns[i - 2].mAddress < BC_REG_FPARAMS_END)
{
if (fpmask & (1ull << (block->mIns[i - 2].mAddress - BC_REG_WORK)))
break;
}
fpmask |= 1ull << (block->mIns[i - 1].mAddress - BC_REG_WORK);
i -= 2;
}
if (i < at)
{
FunctionCall ncp;
ncp.mLinkerObject = lo;
ncp.mOffset = block->mIns[at].mAddress;
int j = i;
while (i < at)
{
ncp.mIns[block->mIns[i + 1].mAddress - BC_REG_WORK] = block->mIns[i];
i += 2;
}
FunctionCall* cp = mFunctionCalls;
while (cp && (cp->mLinkerObject != ncp.mLinkerObject || cp->mOffset != ncp.mOffset))
cp = cp->mNext;
if (cp)
{
FunctionCall* bcp = nullptr;
int bmatch = 0;
FunctionCall* scp = cp;
while (scp)
{
if (scp->mProxyObject)
{
int m = ncp.Matches(scp);
if (m > bmatch)
{
bmatch = m;
bcp = scp;
}
}
scp = scp->mSame;
}
if (bcp)
{
while (j < at)
{
if (bcp->mIns[block->mIns[j + 1].mAddress - BC_REG_WORK].mType != ASMIT_INV)
{
block->mIns[j + 0].mType = ASMIT_NOP; block->mIns[j + 0].mMode = ASMIM_IMPLIED;
block->mIns[j + 1].mType = ASMIT_NOP; block->mIns[j + 1].mMode = ASMIM_IMPLIED;
}
j += 2;
}
block->mIns[j].mLinkerObject = bcp->mProxyObject;
block->mIns[j].mAddress = 0;
return true;
}
}
}
}
return false;
}
void NativeCodeGenerator::BuildFunctionProxies(void)
{
FunctionCall* cp = mFunctionCalls;
while (cp)
{
ExpandingArray<FunctionCall*> ocalls;
FunctionCall* ncp = cp;
while (ncp)
{
if (ncp->mCount == 1)
ocalls.Push(ncp);
ncp = ncp->mSame;
}
// Loop while we have unmatched calls
while (ocalls.Size() > 1)
{
int i = 0;
while (i < ocalls.Size())
{
int j = 0;
while (j < ocalls.Size() && (i == j || ocalls[i]->PotentialMatches(ocalls[j]) == 0))
j++;
if (j == ocalls.Size())
ocalls.Remove(i);
else
i++;
}
if (ocalls.Size() > 1)
{
// Find best matching pair
int besti = 0, bestj = 0, bestm = 0;
for (int i = 0; i < ocalls.Size(); i++)
{
for (int j = i + 1; j < ocalls.Size(); j++)
{
int m = ocalls[i]->PotentialMatches(ocalls[j]);
if (m > bestm)
{
besti = i;
bestj = j;
bestm = m;
}
}
}
FunctionCall* fi = ocalls[besti], * fj = ocalls[bestj];
ocalls.Remove(besti);
for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
{
if (fi->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
{
if (!fi->mIns[i - BC_REG_WORK].IsSame(fj->mIns[i - BC_REG_WORK]))
{
fi->mIns[i - BC_REG_WORK].mType = ASMIT_INV;
}
}
}
int i = 0;
while (i < ocalls.Size())
{
if (ocalls[i]->Matches(fi) > 0)
{
ocalls.Remove(i);
fi->mCount++;
}
else
i++;
}
}
}
ncp = cp;
while (ncp)
{
if (ncp->mCount > 1)
{
// printf("RFC %s : %d\n", ncp->mLinkerObject->mIdent->mString, ncp->mCount);
ncp->mProxyObject = mLinker->AddObject(ncp->mLinkerObject->mLocation, ncp->mLinkerObject->mIdent->Mangle("@proxy"), ncp->mLinkerObject->mSection, ncp->mLinkerObject->mType);
ExpandingArray<uint8> code;
for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
{
NativeCodeInstruction& ins(ncp->mIns[i - BC_REG_WORK]);
if (ins.mType == ASMIT_LDA)
{
switch (ins.mMode)
{
case ASMIM_IMMEDIATE:
code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE]));
code.Push(uint8(ins.mAddress));
break;
case ASMIM_ZERO_PAGE:
code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ZERO_PAGE]));
if (ins.mLinkerObject)
{
LinkerReference rl;
rl.mObject = ncp->mProxyObject;
rl.mOffset = code.Size();
rl.mRefObject = ins.mLinkerObject;
rl.mRefOffset = ins.mAddress;
rl.mFlags = LREF_LOWBYTE;
ncp->mProxyObject->AddReference(rl);
code.Push(0);
}
else
code.Push(uint8(ins.mAddress));
break;
case ASMIM_IMMEDIATE_ADDRESS:
code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE]));
if (ins.mLinkerObject)
{
LinkerReference rl;
rl.mObject = ncp->mProxyObject;
rl.mOffset = code.Size();
rl.mFlags = 0;
if (ins.mFlags & NCIF_LOWER)
rl.mFlags |= LREF_LOWBYTE;
if (ins.mFlags & NCIF_UPPER)
rl.mFlags |= LREF_HIGHBYTE;
rl.mRefObject = ins.mLinkerObject;
rl.mRefOffset = ins.mAddress;
ins.mLinkerObject->mFlags |= LOBJF_NO_CROSS;
ncp->mProxyObject->AddReference(rl);
code.Push(0);
}
else
code.Push(uint8(ins.mAddress));
break;
case ASMIM_ABSOLUTE:
if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGE))
{
code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ZERO_PAGE]));
LinkerReference rl;
rl.mObject = ncp->mProxyObject;
rl.mOffset = code.Size();
rl.mRefObject = ins.mLinkerObject;
rl.mRefOffset = ins.mAddress;
rl.mFlags = LREF_LOWBYTE;
ncp->mProxyObject->AddReference(rl);
code.Push(0);
}
else
{
code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ABSOLUTE]));
if (ins.mLinkerObject)
{
LinkerReference rl;
rl.mObject = ncp->mProxyObject;
rl.mOffset = code.Size();
rl.mRefObject = ins.mLinkerObject;
rl.mRefOffset = ins.mAddress;
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ncp->mProxyObject->AddReference(rl);
code.Push(0);
code.Push(0);
}
else
{
code.Push(uint8(ins.mAddress & 0xff));
code.Push(uint8(ins.mAddress >> 8));
}
}
break;
}
code.Push(uint8(AsmInsOpcodes[ASMIT_STA][ASMIM_ZERO_PAGE]));
code.Push(uint8(i));
}
}
code.Push(uint8(AsmInsOpcodes[ASMIT_JMP][ASMIM_ABSOLUTE]));
LinkerReference rl;
rl.mObject = ncp->mProxyObject;
rl.mOffset = code.Size();
rl.mRefObject = ncp->mLinkerObject;
rl.mRefOffset = ncp->mOffset;
rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ncp->mProxyObject->AddReference(rl);
code.Push(0);
code.Push(0);
ncp->mProxyObject->AddData(&(code[0]), code.Size());
}
ncp = ncp->mSame;
}
cp = cp->mNext;
}
}
void NativeCodeGenerator::RegisterRuntime(const Ident* ident, LinkerObject* object, int offset)
{
Runtime rt;
rt.mIdent = ident;
rt.mLinkerObject = object;
rt.mOffset = offset;
mRuntime.Push(rt);
}
bool NativeCodeGenerator::FunctionCall::IsSame(const FunctionCall* fc) const
{
for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
if (!mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
return false;
return true;
}
int NativeCodeGenerator::FunctionCall::Matches(const FunctionCall* fc) const
{
int match = 0;
for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
{
if (fc->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
{
if (!mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
return -1;
match++;
}
}
return match;
}
int NativeCodeGenerator::FunctionCall::PotentialMatches(const FunctionCall* fc) const
{
int match = 0;
for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
{
if (fc->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
{
if (mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
match++;
}
}
return match;
}