#include "NativeCodeGenerator.h" #include "CompilerTypes.h" #define JUMP_TO_BRANCH 1 #define CHECK_NULLPTR 0 #define REYCLE_JUMPS 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) { mFlags = 0; mMode = NRDM_UNKNOWN; mValue = GlobalValueNumber++; } void NativeRegisterData::ResetMask(void) { mMask = 0; } void NativeRegisterData::ResetAliasing(void) { if (mFlags & NCIF_ALIASING) Reset(); } 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)) { ResetAliasing(); 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::ResetAliasing(void) { for (int i = 0; i < NUM_REGS; i++) mRegs[i].ResetAliasing(); } 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= 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(linkerObject || (address >= 0 && address < 256)); } if (mode == ASMIM_ZERO_PAGE) { assert(linkerObject || (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 { #if 0 for (int i = 0; i < 4; i++) { requiredTemps -= BC_REG_ACCU + i; requiredTemps -= BC_REG_WORK + i; } #endif 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; else 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 if (mFlags & NCIF_VOLATILE) { if (mMode != ASMIM_IMPLIED && mMode != ASMIM_ZERO_PAGE) used = true; } 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 mType == ASMIT_LDY || HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y); else if (mMode == ASMIM_ABSOLUTE_Y) return mType == ASMIT_LDX || 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 if (mLinkerObject && mLinkerObject->mNumTemporaries) { for (int i = 0; i < mLinkerObject->mNumTemporaries; i++) { for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++) UpdateCollisionSet(liveTemps, collisionSets, mLinkerObject->mTemporaries[i] + j); } } 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_WORK_Y) return true; 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 (!mLinkerObject) { return false; } 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 if (mType == ASMIT_JSR) { return (mFlags & NCIF_USE_CPU_REG_A); } 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::IsLogic(void) const { return 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.mFlags & NCIF_ALIASING) return true; 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 (mFlags & NCIF_ALIASING) return true; 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); int changed = (~data.mRegs[CPU_REG_A].mMask | data.mRegs[CPU_REG_A].mValue) & (~opmask | ~opvalue) & 0xff; if (changed == 0) { if (mMode != ASMIM_IMMEDIATE || mAddress != 0xff) { mMode = ASMIM_IMMEDIATE; mAddress = 0xff; changed = true; } } else { 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) & 0xff) + (data.mRegs[CPU_REG_A].mValue & 0xff) + data.mRegs[CPU_REG_C].mValue; else t = ((mAddress ^ 0xffff) >> 8) + (data.mRegs[CPU_REG_A].mValue >> 8) + 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; data.mRegs[CPU_REG_A].mFlags = mFlags; } } break; case ASMIT_LDX: if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z)) { 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; data.mRegs[CPU_REG_X].mFlags = mFlags; } } break; case ASMIT_LDY: if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z)) { 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; data.mRegs[CPU_REG_Y].mFlags = mFlags; } } 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[data.mRegs[CPU_REG_A].mValue].mFlags = mFlags; data.mRegs[mAddress].Reset(); } else #endif { data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue; data.mRegs[mAddress].mFlags = data.mRegs[CPU_REG_A].mFlags; } } 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; data.mRegs[mAddress].mFlags = data.mRegs[CPU_REG_X].mFlags; } 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; data.mRegs[CPU_REG_X].mFlags = mFlags; } 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; data.mRegs[mAddress].mFlags = data.mRegs[CPU_REG_Y].mFlags; } 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 && 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 from, int to, AsmInsType code) { 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; } else if (to - from >= -126 && to - from <= 129) { if (code != ASMIT_INV) { PutOpcode(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]); PutByte(to - from - 2); return 2; } #if JUMP_TO_BRANCH else 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(to - from - 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(to - from - 2); return 2; } #endif } target->mAsmFromJump = from; 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, bool final) { if (to - from >= -126 && to - from <= 129) return 2; else { if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS) return 3; if (final) { #if REYCLE_JUMPS if (target->mAsmFromJump >= 0 && target->mAsmFromJump - from >= -126) return 2; #endif target->mAsmFromJump = from + 2; return 5; } else { return 5; } } } int NativeCodeBasicBlock::JumpByteSize(NativeCodeBasicBlock* target, int from, int to, bool second, bool final) { 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; } else if (to - from >= -126 && to - from <= 129) { if (second) return 2; #if JUMP_TO_BRANCH else if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) return 2; else if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) return 2; #endif else { if (final) target->mAsmFromJump = from; return 3; } } else { if (final) target->mAsmFromJump = from; return 3; } } int NativeCodeBasicBlock::PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int from, int to) { if (to - from >= -126 && to - from <= 129) { PutOpcode(AsmInsOpcodes[code][ASMIM_RELATIVE]); PutByte(to - from - 2); return 2; } #if REYCLE_JUMPS else if (target->mAsmFromJump >= 0 && target->mAsmFromJump - from >= -126) { PutOpcode(AsmInsOpcodes[code][ASMIM_RELATIVE]); PutByte(target->mAsmFromJump - from - 2); return 2; } #endif 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); target->mAsmFromJump = from + 2; PutByte(0x4c); LinkerReference rl; rl.mObject = nullptr; rl.mOffset = mCode.Size(); rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE; rl.mRefObject = nullptr; rl.mRefOffset = to; mRelocations.Push(rl); PutWord(0); return 5; } } } void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure* proc, const InterInstruction* ins, const InterOperand& op, InterType type, int reg, bool checkRange) { 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 (checkRange && (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->mAliasing) flags |= NCIF_ALIASING; 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])); int stride = rins->mSrc[0].mStride; uint32 flags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) flags |= NCIF_VOLATILE; if (rins->mAliasing) flags |= NCIF_ALIASING; for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++) { if (i != 0) { if (stride == 1) mIns.Push(NativeCodeInstruction(rins, ASMIT_INY, ASMIM_IMPLIED)); else { mIns.Push(NativeCodeInstruction(rins, ASMIT_TYA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(rins, ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(rins, ASMIT_ADC, ASMIM_IMMEDIATE, stride)); mIns.Push(NativeCodeInstruction(rins, ASMIT_TAY, 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])); int stride = wins->mSrc[1].mStride; uint32 flags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) flags |= NCIF_VOLATILE; if (wins->mAliasing) flags |= NCIF_ALIASING; for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++) { if (i != 0) { if (stride == 1) mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED)); else { mIns.Push(NativeCodeInstruction(wins, ASMIT_TYA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(wins, ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(wins, ASMIT_ADC, ASMIM_IMMEDIATE, stride)); mIns.Push(NativeCodeInstruction(wins, ASMIT_TAY, 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; if (rins->mAliasing) flags |= NCIF_ALIASING; 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; if (wins->mAliasing) flags |= NCIF_ALIASING; 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; if (wins->mAliasing) flags |= NCIF_ALIASING; 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; if (wins0->mAliasing) wflags0 |= NCIF_ALIASING; 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; if (wins1->mAliasing) wflags1 |= NCIF_ALIASING; 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; if (rins->mAliasing) rflags |= NCIF_ALIASING; 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; if (wins->mAliasing) wflags |= NCIF_ALIASING; 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; if (rins->mAliasing) rflags |= NCIF_ALIASING; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (wins->mAliasing) wflags |= NCIF_ALIASING; 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; if (rins->mAliasing) rflags |= NCIF_ALIASING; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (wins->mAliasing) wflags |= NCIF_ALIASING; 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; if (rins->mAliasing) rflags |= NCIF_ALIASING; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (wins->mAliasing) wflags |= NCIF_ALIASING; 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->mAliasing) flags |= NCIF_ALIASING; 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, nullptr, flags)); 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, nullptr, flags)); 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, nullptr, flags)); 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, nullptr, flags)); 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; bool accu = reg == areg; 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)); 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 { 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)); 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 < 4; 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)); } } } } } 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, 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_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + 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_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, nullptr, flags)); } 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, 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_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + 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_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, nullptr, flags)); 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, nullptr, flags)); 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, nullptr, flags)); 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, nullptr, flags)); 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 (ins->mAliasing) flags |= NCIF_ALIASING; 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 (ins->mAliasing) flags |= NCIF_ALIASING; 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)); return BC_REG_ACCU; } 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_ACCU; } 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("fadd"))); mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); } break; case IA_SUB: { bool add = false; if (changedSign) add = true; else 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)); add = true; } NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique(add ? "fadd" : "fsub"))); 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 && sins0 && sins1->mDst.mTemp == sins0->mSrc[0].mTemp) { LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr); LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr); } else { 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_ACCU; } 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_ACCU; } #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_FLOAT2LINT: { 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("ftoli"))); 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_LINT2FLOAT: { 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("ffromli"))); 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_FLOAT2LUINT: { 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("ftolu"))); 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_LUINT2FLOAT: { 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("ffromlu"))); 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, false); } else lreg = BC_REG_TMP + proc->mTempOffset[lreg]; if (rreg < 0) { rreg = BC_REG_ACCU; LoadConstantToReg(proc, ins, ins->mSrc[ri], IT_POINTER, rreg, false); } 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; op = MirrorRelational(op); } NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); NativeCodeBasicBlock* rblock = nproc->AllocateBlock(); if (op >= IA_CMPGES && op <= IA_CMPLS) { if (ins->mSrc[ri].mTemp >= 0) { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); 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)); mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3)); this->Close(ins, eblock3, eblock, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3)); eblock->Close(ins, nblock, rblock, ASMIT_BPL); } else { 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)); this->Close(ins, nblock, eblock3, ASMIT_BNE); } } 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)); 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); rblock->Close(ins, falseJump, nullptr, ASMIT_JMP); eblock1->Close(ins, trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: nblock->Close(ins, trueJump, nullptr, ASMIT_JMP); rblock->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); rblock->Close(ins, trueJump, falseJump, ASMIT_BCS); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: eblock1->Close(ins, nblock, nullptr, ASMIT_JMP); nblock->Close(ins, trueJump, falseJump, ASMIT_BCS); rblock->Close(ins, trueJump, falseJump, 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()) { int li = 1, ri = 0; if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS) { li = 0; ri = 1; op = MirrorRelational(op); } int iconst = 0; bool rconst = false; if (ins->mSrc[li].mTemp < 0 && op == IA_CMPGES && int16(ins->mSrc[li].mIntConst) < 127) { iconst = int(ins->mSrc[li].mIntConst) + 1; rconst = true; li = ri; ri = 1 - li; op = IA_CMPLS; } else if (ins->mSrc[li].mTemp < 0 && op == IA_CMPLS && int16(ins->mSrc[li].mIntConst) < 127) { iconst = int(ins->mSrc[li].mIntConst) + 1; rconst = true; li = ri; ri = 1 - li; op = IA_CMPGES; } 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) { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); NativeCodeBasicBlock* pblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eqjmp, * gtjmp, * ltjmp; if (op == IA_CMPGES || op == IA_CMPLES) eqjmp = trueJump; else eqjmp = falseJump; if (op == IA_CMPGS || op == IA_CMPGES) { gtjmp = trueJump; ltjmp = falseJump; } else { gtjmp = falseJump; ltjmp = trueJump; } 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])); mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); this->Close(ins, eqjmp, eblock, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); eblock->Close(ins, pblock, nblock, ASMIT_BCS); pblock->Close(ins, gtjmp, ltjmp, ASMIT_BPL); nblock->Close(ins, ltjmp, gtjmp, ASMIT_BPL); return; } else { 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)); } mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (iconst & 0xff) ^ 0x80)); } } 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* rblock = 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)); cblock->Close(ins, nblock, eblock, ASMIT_BNE); } 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)); cblock->Close(ins, nblock, eblock, ASMIT_BNE); } 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)); cblock->Close(ins, nblock, eblock, ASMIT_BNE); } 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)); cblock->Close(ins, nblock, eblock, ASMIT_BNE); } else { if (!rconst) { NativeCodeBasicBlock* sblock = nproc->AllocateBlock(); 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)); mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); this->Close(ins, eblock, sblock, ASMIT_BEQ); sblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); sblock->Close(ins, nblock, rblock, ASMIT_BPL); } 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)); cblock->Close(ins, nblock, eblock, ASMIT_BNE); } } } 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); rblock->Close(ins, trueJump, falseJump, ASMIT_BCS); 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); rblock->Close(ins, falseJump, trueJump, ASMIT_BCS); 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) & 0xff)); 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 (lref) { linkerObject = lref->mRefObject; address = 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 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; // Make sure we are not aliasing zeropage globals if (dins.mMode == ASMIM_ZERO_PAGE && dins.mLinkerObject) dins.mMode = ASMIM_ABSOLUTE; 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; if (mIns[i].mFlags & NCIF_ALIASING) 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() || (mIns[i].mFlags & NCIF_ALIASING)) 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) { if (mALSIns.mMode == ASMIM_ABSOLUTE_Y) mALSIns.mType = ASMIT_INV; if (mXLSIns.mMode == ASMIM_ABSOLUTE_Y) mXLSIns.mType = ASMIT_INV; mYLSIns = mALSIns; } else if (ins.mType == ASMIT_TAX) { if (mALSIns.mMode == ASMIM_ABSOLUTE_X) mALSIns.mType = ASMIT_INV; if (mYLSIns.mMode == ASMIM_ABSOLUTE_X) mYLSIns.mType = ASMIT_INV; 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_CPU_REG_Y | 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 (flagsFront & NCIF_ALIASING) { for (int i = mid; i < end; i++) if (mIns[i].mType == ASMIT_JSR) return false; } if (flagsBack & NCIF_ALIASING) { for (int i = start; i < mid; i++) if (mIns[i].mType == ASMIT_JSR) 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; } mIns[sz].mLive |= LIVE_MEM; 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; } mIns[sz].mLive |= LIVE_MEM; 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; jmIns.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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 2].mIns; 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->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 3].mIns; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 0].mIns; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = iins; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 0].mIns; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 0].mIns; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 0].mIns; 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; rblock->mBranchIns = mBranchIns; 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; mBranchIns = mIns[i + 0].mIns; 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; fblock->mBranchIns = mBranchIns; const InterInstruction* iins = mIns[0].mIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; const InterInstruction* iins = mIns[0].mIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; const InterInstruction* iins = mIns[0].mIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; 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; mBranchIns = iins; 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; fblock->mBranchIns = mBranchIns; const InterInstruction* iins(mIns[i].mIns); 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; mBranchIns = iins; 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->mTrueJump; changed = true; } } else if (mFalseJump->mBranch == ASMIT_BCS) { if (mFalseJump->mTrueJump == mTrueJump) { mBranch = ASMIT_BCS; mFalseJump = mFalseJump->mFalseJump; 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->mIns.Size() == 0 && mFalseJump->mIns.Size() == 0 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)) { if (mTrueJump->mBranch == ASMIT_BEQ && mFalseJump->mBranch == ASMIT_BNE && mTrueJump->mTrueJump == mFalseJump->mFalseJump) { NativeCodeBasicBlock* iblock = proc->AllocateBlock(); iblock->Close(mBranchIns, mTrueJump->mFalseJump, mFalseJump->mTrueJump, mBranch); mBranch = ASMIT_BEQ; mTrueJump = mTrueJump->mTrueJump; mFalseJump = iblock; 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 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 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 && HasAsmInstructionMode(ASMIT_CPX, lblock->mIns[ls - 1].mMode) && !(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 && !(mIns[0].mLive & LIVE_CPU_REG_Z)) { 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]); CheckLive(); 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; mIns[ns - 1].mLive |= LIVE_CPU_REG_X; 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; mIns[ns - 1].mLive |= LIVE_CPU_REG_X; 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::CombineAlternateLoads(void) { bool changed = false; if (!mVisited) { mVisited = true; if (mTrueJump && mFalseJump && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 && mTrueJump->mTrueJump == mFalseJump->mTrueJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1) { if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE) { mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Push(mFalseJump->mIns[0]); mFalseJump->mIns.Remove(0); mExitRequiredRegs += CPU_REG_A; mFalseJump->mEntryRequiredRegs += CPU_REG_A; changed = true; } else if (mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE) { mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Push(mFalseJump->mIns[0]); mFalseJump->mIns.Remove(0); mExitRequiredRegs += CPU_REG_X; mFalseJump->mEntryRequiredRegs += CPU_REG_X; changed = true; } else if (mTrueJump->mIns[0].mType == ASMIT_LDY && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mType == ASMIT_LDY && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE) { mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Push(mFalseJump->mIns[0]); mFalseJump->mIns.Remove(0); mExitRequiredRegs += CPU_REG_Y; mFalseJump->mEntryRequiredRegs += CPU_REG_Y; changed = true; } } if (mTrueJump && mTrueJump->CombineAlternateLoads()) changed = true; if (mFalseJump && mFalseJump->CombineAlternateLoads()) 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::JoinSameBranch(NativeCodeBasicBlock* block) { bool changed = false; if (!mPatched) { mPatched = true; if (this != block) { if (mBranch == block->mBranch && mTrueJump == block->mTrueJump && mFalseJump == block->mFalseJump) { mTrueJump->mNumEntries--; mFalseJump->mNumEntries--; block->mNumEntries++; mBranch = ASMIT_JMP; mTrueJump = block; mFalseJump = nullptr; changed = true; } } if (mTrueJump && mTrueJump->JoinSameBranch(block)) changed = true; if (mFalseJump && mFalseJump->JoinSameBranch(block)) changed = true; } return changed; } bool NativeCodeBasicBlock::MergeSameBranch(void) { bool changed = false; if (!mVisited) { mVisited = true; if (mIns.Size() == 0 && mFalseJump) { mProc->ResetPatched(); if (mProc->mEntryBlock->JoinSameBranch(this)) changed = true; } if (mTrueJump && mTrueJump->MergeSameBranch()) changed = true; if (mFalseJump && mFalseJump->MergeSameBranch()) changed = true; } return changed; } 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 (index && 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 (index && 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)) { if (mPatchFail) return false; mPatchChecked = true; if (mTrueJump && !mTrueJump->CheckPatchFailUse() || mFalseJump && !mFalseJump->CheckPatchFailUse()) return false; 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 || ins.mType == ASMIT_RTS) { if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || (index && 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 (index && 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; if (index) ins.mMode = ASMIM_ABSOLUTE_Y; else if (ins.mLinkerObject || address >= 256) ins.mMode = ASMIM_ABSOLUTE; else ins.mMode = ASMIM_ZERO_PAGE; ins.mLinkerObject = lobj; ins.mAddress = address + yval; ins.mFlags = (ins.mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | flags; if (index) { 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 (index && 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 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 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 & 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.mSrcL->mMode = mRSumInfos[j].mDstL->mMode; info.mSrcH->mAddress = mRSumInfos[j].mDstH->mAddress; info.mSrcH->mMode = mRSumInfos[j].mDstH->mMode; 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::FindAccuExitValue(int& at) { int i = mIns.Size() - 1; while (i >= 0) { if ((mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE)) { at = i; i++; while (i < mIns.Size()) { if (mIns[at].MayBeChangedOnAddress(mIns[i])) return false; i++; } return true; } else if (mIns[i].ChangesAccu()) return false; i--; } return false; } bool NativeCodeBasicBlock::MoveLoadXAbsUpCrossBlock(int at) { int i = at - 1; while (i >= 0) { if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA) && mIns[i].SameEffectiveAddress(mIns[at])) { mIns[i].mLive |= LIVE_CPU_REG_A; i++; mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX)); mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; while (i < at + 1) { mIns[i].mLive |= LIVE_CPU_REG_X; i++; } return true; } if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X)) return false; if (mIns[at].MayBeChangedOnAddress(mIns[i])) return false; i--; } if (mEntryBlocks.Size() == 1) { NativeCodeBasicBlock* eb = mEntryBlocks[0]; if (eb->FindAccuExitValue(i) && eb->mIns[i].SameEffectiveAddress(mIns[at])) { while (i < eb->mIns.Size()) { eb->mIns[i].mLive |= LIVE_CPU_REG_A; i++; } eb->mExitRequiredRegs += CPU_REG_A; mEntryRequiredRegs += CPU_REG_A; mIns.Insert(0, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX)); mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; i = 0; while (i < at + 1) { mIns[i].mLive |= LIVE_CPU_REG_X; i++; } return true; } } return false; } 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 | LIVE_CPU_REG_Z))) 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::MoveTXALogicTAXDown(int at) { int i = at + 3; while (i < mIns.Size()) { if (mIns[i].ChangesXReg()) return false; if (mIns[i].mType == ASMIT_TXA) { if (mIns[i].mLive & LIVE_CPU_REG_X) return false; mIns[at + 1].mLive |= mIns[i].mLive; mIns.Insert(i + 1, mIns[at + 1]); mIns.Remove(at, 3); return true; } if (mIns[i].RequiresXReg()) return false; i++; } 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::MoveLoadLogicStoreAbsUp(int at) { // at + 0 : LDA zp // at + 1 : ORA zp / imm // at + 2 : STA abs / abs,x / abs,y 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) { while (j + 1 < mIns.Size() && mIns[j + 1].mType == ASMIT_STA) j++; if (mIns[j].mLive & LIVE_CPU_REG_A) 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 + 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]); // ORA 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[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 1].mAddress)) return false; if (mIns[j].UsesMemoryOf(mIns[at + 2])) return false; if (mIns[at + 2].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg()) return false; if (mIns[at + 2].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg()) return false; j--; } 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 & npairs) { bool changed = false; if (!mVisited) { mVisited = true; ExpandingArray 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 == 0) { if (!(mIns[i].mLive & LIVE_CPU_REG_Z)) { mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; changed = true; } else if (!(mIns[i].mLive & LIVE_CPU_REG_A)) { mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED; changed = true; } } else 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 | LIVE_CPU_REG_X))) { 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 == 0) { if (!(mIns[i].mLive & LIVE_CPU_REG_Z)) { mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; changed = true; } else if (!(mIns[i].mLive & LIVE_CPU_REG_A)) { mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED; changed = true; } } else 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 lblocks, pblocks; bool addprefix = false; for(int i=0; iIsDominatedBy(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; jmEntryBlocks.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 >= 4 && mIns[0].mType == ASMIT_TAY && mIns[sz - 3].mType == ASMIT_INX && mIns[sz - 2].mType == ASMIT_TXA && mIns[sz - 1].mType == ASMIT_CPX && !ChangesYReg(1) && !ReferencesXReg(0, sz - 3)) { if (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); for (int i = 0; i < sz; i++) mIns[i].mLive |= LIVE_CPU_REG_Y; mIns[sz - 3].mType = ASMIT_INY; mIns[sz - 2].mType = ASMIT_TYA; mIns[sz - 1].mType = ASMIT_CPY; if (exitBlock->mEntryRequiredRegs[CPU_REG_X]) { exitBlock->mEntryRequiredRegs += CPU_REG_A; exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[sz - 2].mIns, ASMIT_TAX)); } 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; imIns.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) && !mEntryRequiredRegs[CPU_REG_A]) { 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; imExitRequiredRegs += 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; if (mEntryRequiredRegs[CPU_REG_X]) mIns[ai].mLive |= LIVE_CPU_REG_X; 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; } } } } else if (sz > 5 && mIns[0].mType == ASMIT_STY && mIns[0].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mType == ASMIT_LDY && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && mIns[0].mAddress == mIns[sz - 3].mAddress && !ChangesZeroPage(mIns[0].mAddress, 1, sz - 3) && !(mIns[sz - 3].mLive & LIVE_CPU_REG_X)) { int j = 0; while (j < sz - 3 && !(mIns[j].ChangesYReg() || mIns[j].mType == ASMIT_LDX && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[0].mAddress)) j++; if (mIns[j].mType == ASMIT_LDX && !ChangesXReg(j + 1, sz - 3)) { int k = j + 1; while (k < sz - 3 && mIns[k].CanSwapXYReg()) k++; if (k == sz - 3) { for (k = j + 1; k < sz - 3; k++) mIns[k].SwapXYReg(); for (k = 0; k < sz; k++) mIns[k].mLive |= LIVE_CPU_REG_Y; mIns[j].mType = ASMIT_NOP; mIns[j].mMode = ASMIM_IMPLIED; mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED; changed = true; } } } } #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 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z)) { 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 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z)) { 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= -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& 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_TXA) { if (!ChangesAccu(1) && !ChangesXReg(1)) { int i = 0; while (i < lblocks.Size() && (lblocks[i] == this || (!lblocks[i]->ChangesXReg() && !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 (!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& 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; lblock->mEntryRequiredRegs = tail->mTrueJump->mEntryRequiredRegs; eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg)); eblock->mBranch = ASMIT_JMP; eblock->mTrueJump = tail->mFalseJump; eblock->mFalseJump = nullptr; eblock->mEntryRequiredRegs = tail->mFalseJump->mEntryRequiredRegs; 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& 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 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 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; areg = -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; areg = -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 entries; ExpandingArray 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& 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& lblocks) { ExpandingArray 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& 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& 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++; if (k == 1 && i == 4 && mIns[si + 0].mMode == ASMIM_ZERO_PAGE && mIns[si + 1].mMode == ASMIM_ZERO_PAGE) { if (mIns[si + 0].mAddress == BC_REG_ACCU) { NativeCodeGenerator::Runtime& frt(mProc->mGenerator->ResolveRuntime(Ident::Unique("store32"))); mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, mIns[si + 1].mAddress); si += 8; return true; } else if (mIns[si + 1].mAddress == BC_REG_ACCU) { NativeCodeGenerator::Runtime& frt(mProc->mGenerator->ResolveRuntime(Ident::Unique("load32"))); mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, mIns[si + 0].mAddress); si += 8; return true; } } 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; } } } #if 1 if (si + 5 < mIns.Size() && mIns[si + 0].mType == ASMIT_LDY && mIns[si + 0].mMode == ASMIM_IMMEDIATE && mIns[si + 1].mType == ASMIT_STA && mIns[si + 1].mMode == ASMIM_INDIRECT_Y) { int i = 1; while (si + 2 * i + 1 < mIns.Size() && mIns[si + 2 * i + 0].mType == ASMIT_LDY && mIns[si + 2 * i + 0].mMode == ASMIM_IMMEDIATE && 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 == ASMIM_INDIRECT_Y && mIns[si + 2 * i + 1].mAddress == mIns[si + 1].mAddress) { i++; } if (i > 2) { int k = mIns[si + 0].mAddress + i - 1; mIns[di + 0] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[si + 0].mAddress - 1); mIns[di + 2] = mIns[si + 1]; mIns[di + 1] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_INY); mIns[di + 3] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_CPY, ASMIM_IMMEDIATE, k); mIns[di + 4] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_BNE, ASMIM_RELATIVE, -7); di += 5; si += 2 * i; if (si == mIns.Size()) { mNDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; mNDataSet.mRegs[CPU_REG_C].mValue = 1; mNDataSet.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; mNDataSet.mRegs[CPU_REG_Z].mValue = 0; } return true; } } #endif } 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 (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_X)) { mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX); i++; j++; } else if (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y)) { mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY); i++; j++; } 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) { mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; } else 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 #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 - add # - store up to initial store // for (int i = 1; i + 2 < mIns.Size(); i++) { if ( mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].IsLogic() && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE || mIns[i + 2].mMode == ASMIM_ABSOLUTE_X || mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y) && (mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0) { if (MoveLoadLogicStoreAbsUp(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 if (pass > 10) { for (int i = 0; i < mIns.Size(); i++) { if (!(mIns[i].mFlags & NCIF_VOLATILE)) { 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 (MoveLoadXAbsUpCrossBlock(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 // 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 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 + 3 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].IsLogic() && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { if (MoveTXALogicTAXDown(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].mFlags & NCIF_VOLATILE)) { 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 + 0].mType != ASMIT_TXA && (mIns[i + 1].mType == ASMIT_INX || mIns[i + 1].mType == ASMIT_DEX) && 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; } if ( mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_DEX && mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) { mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_CPX; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff; return true; } else if ( mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 0].mType != ASMIT_TYA && (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_TYA && 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].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) { mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_CPY; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff; 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; } 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_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) { mIns[i + 2].mAddress = (mIns[i + 2].mAddress + mIns[i + 1].mAddress) & 0xff; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].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 + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) { mIns[i + 2].mAddress = (mIns[i + 2].mAddress - mIns[i + 1].mAddress) & 0xff; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; return true; } if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && !(mIns[i + 0].mAddress & 1) && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 1)) { mIns[i + 0].mAddress |= mIns[i + 2].mAddress; mIns[i + 2].mType = ASMIT_NOP; 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 + 1].ChangesZeroPage(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].mMode == ASMIM_INDIRECT_Y) { mIns[i + 0].mLive |= LIVE_MEM; mIns[i + 3].mLive |= LIVE_MEM; } 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_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 >= 0xfe && 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 == 0xfe) 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_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_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 >= 0xfe && 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 == 0xfe) 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_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_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 1].mType == ASMIT_TAY && mIns[i + 2].mType == ASMIT_TXA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y))) { mIns[i + 2] = mIns[i + 0]; mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X; mIns[i + 1].mType = ASMIT_TAX; mIns[i + 3].mMode = ASMIM_ABSOLUTE_X; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; 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; } else if ( mIns[i + 0].mType == ASMIT_TXA && 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_TAX && !(mIns[i + 4].mLive & LIVE_CPU_REG_C)) { mIns[i + 0].mLive |= LIVE_CPU_REG_X; 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 | LIVE_CPU_REG_Z; mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_TXA; return true; } else if ( mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_STA && 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 + 4].mType == ASMIT_TAX && !(mIns[i + 4].mLive & LIVE_CPU_REG_C)) { mIns[i + 0].mLive |= LIVE_CPU_REG_X; 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 | LIVE_CPU_REG_Z; mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_TXA; 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; } 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_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mType == ASMIT_LDA && !mIns[i + 3].MayBeSameAddress(mIns[i + 2]) && mIns[i + 4].mType == ASMIT_ASL && mIns[i + 4].mMode == ASMIM_IMPLIED && mIns[i + 5].mType == ASMIT_ORA && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 5].mLive & LIVE_MEM)) { 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].mLive |= LIVE_CPU_REG_C; mIns[i + 4].mType = ASMIT_ROL; mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED; return true; } #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_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; } } #endif 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 ( 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_ABSOLUTE_X || mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 3].mMode == ASMIM_ABSOLUTE) && 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; 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 + 4].mType = ASMIT_NOP; mIns[i + 4].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 1 if (i + 5 < mIns.Size() && PeepHoleOptimizerIterate6(i, pass)) progress = true; CheckLive(); #endif #if 1 if (i + 3 < mIns.Size() && pass == 0 && 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 && mIns[i + 2].mType == ASMIT_LDA && 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 + 1].mAddress + 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_A)) { mProc->ResetPatched(); if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, 0, i + 4, -1)) { mProc->ResetPatched(); if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, 0, i + 4, -1, nullptr, 256 * mIns[i + 2].mAddress + mIns[i + 0].mAddress)) progress = true; } } #endif #if 1 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; } } #endif #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_C; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; mExitRequiredRegs -= CPU_REG_C; 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(); } else if (pass >= 7 && sz >= 2 && mIns[sz - 2].mType == ASMIT_AND && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 && mIns[sz - 1].mType == ASMIT_EOR && 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].mMode = ASMIM_IMPLIED; mIns[sz - 2].mLive |= LIVE_CPU_REG_C; mBranch = ASMIT_BCC; mIns.SetSize(sz - 1); changed = true; } else if (mBranch == ASMIT_BEQ) { mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mMode = ASMIM_IMPLIED; mIns[sz - 2].mLive |= LIVE_CPU_REG_C; mBranch = ASMIT_BCS; 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 #if 1 if (sz > 0 && mFalseJump && mIns[sz - 1].ChangesAccuAndFlag() && mBranch == ASMIT_BMI) { if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_CMP && mFalseJump->mBranch == ASMIT_BCS && mFalseJump->mTrueJump == mTrueJump) { mTrueJump->RemEntryBlock(this); mTrueJump = mFalseJump; mFalseJump = nullptr; mBranch = ASMIT_JMP; changed = true; } } #endif #if 1 if (pass > 15 && sz > 0 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY)) { if (mTrueJump && mTrueJump->mEntryBlocks.Size() == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].IsSame(mIns[sz - 1])) { mTrueJump->mIns[0].mType = ASMIT_NOP; mTrueJump->mIns[0].mMode = ASMIM_IMPLIED; if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z) { mExitRequiredRegs += CPU_REG_Z; mTrueJump->mEntryRequiredRegs += CPU_REG_Z; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; } if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_C) { mExitRequiredRegs += CPU_REG_C; mTrueJump->mEntryRequiredRegs += CPU_REG_C; mIns[sz - 1].mLive |= LIVE_CPU_REG_C; } changed = true; } if (mFalseJump && mFalseJump->mEntryBlocks.Size() == 1 && mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].IsSame(mIns[sz - 1])) { mFalseJump->mIns[0].mType = ASMIT_NOP; mFalseJump->mIns[0].mMode = ASMIM_IMPLIED; if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_Z) { mExitRequiredRegs += CPU_REG_Z; mFalseJump->mEntryRequiredRegs += CPU_REG_Z; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; } if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_C) { mExitRequiredRegs += CPU_REG_C; mFalseJump->mEntryRequiredRegs += CPU_REG_C; mIns[sz - 1].mLive |= LIVE_CPU_REG_C; } 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 CHECK_NULLPTR 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); #endif } 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]); live |= LIVE_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]); live |= LIVE_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 CHECK_NULLPTR 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); #endif 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; } NativeCodeBasicBlock * NativeCodeBasicBlock::PlaceSequence(ExpandingArray& placement, NativeCodeBasicBlock* block) { int size = 0; do { block->mPlaced = true; block->mPlace = placement.Size(); placement.Push(block); size += block->mCode.Size(); block = block->mTrueJump; } while (block && !block->mFalseJump && !block->mPlaced && size + block->mCode.Size() < 32); return block; } void NativeCodeBasicBlock::BuildPlacement(ExpandingArray& 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->mTrueJump->mFalseJump && mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 20 && mTrueJump->mTrueJump->mCode.Size() < 20 && mFalseJump->mFalseJump->LeadsInto(mTrueJump->mTrueJump->mTrueJump, 0) < 10 && mFalseJump->mFalseJump->LeadsInto(mTrueJump->mTrueJump->mFalseJump, 0) < 10) { mTrueJump->mPlaced = true; mTrueJump->mPlace = placement.Size(); placement.Push(mTrueJump); mTrueJump->mTrueJump->mPlaced = true; mTrueJump->mTrueJump->mPlace = placement.Size(); placement.Push(mTrueJump->mTrueJump); mFalseJump->BuildPlacement(placement); mTrueJump->mTrueJump->mTrueJump->BuildPlacement(placement); mTrueJump->mTrueJump->mFalseJump->BuildPlacement(placement); } else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 100 && mFalseJump->LeadsInto(mTrueJump->mTrueJump, 0) < 100) { NativeCodeBasicBlock * xblock = PlaceSequence(placement, mTrueJump); mFalseJump->BuildPlacement(placement); if (xblock) xblock->BuildPlacement(placement); } else if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump && mFalseJump->mCode.Size() < 100 && mTrueJump->LeadsInto(mFalseJump->mTrueJump, 0) < 100) { NativeCodeBasicBlock * xblock = PlaceSequence(placement, mFalseJump); mTrueJump->BuildPlacement(placement); if (xblock) xblock->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) { mAsmFromJump = -1; 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 final) { bool changed = total != mOffset; mOffset = total; total += mCode.Size(); if (mFalseJump) { if (mFalseJump->mPlace == mPlace + 1) total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final); else if (mTrueJump->mPlace == mPlace + 1) total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset, final); 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, final); total += JumpByteSize(mFalseJump, total, mFalseJump->mOffset, true, final); } else if ( mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace || mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace) { total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset, final); total += JumpByteSize(mTrueJump, total, mTrueJump->mOffset, true, final); } else { total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final); total += JumpByteSize(mFalseJump, total, mFalseJump->mOffset, true, final); } } 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, total, mTrueJump->mOffset, false, final); } } 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, end, mTrueJump->mOffset); else if (mTrueJump->mPlace == mPlace + 1) end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), end, mFalseJump->mOffset); 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, end, mTrueJump->mOffset); end += PutJump(proc, mFalseJump, end, mFalseJump->mOffset, mBranch); } else if ( mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace || mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace) { end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), end, mFalseJump->mOffset); end += PutJump(proc, mTrueJump, end, mTrueJump->mOffset, InvertBranchCondition(mBranch)); } else { end += PutBranch(proc, mTrueJump, mBranch, end, mTrueJump->mOffset); end += PutJump(proc, mFalseJump, end, mFalseJump->mOffset, mBranch); } if (mBranchIns) PutLocation(mBranchIns->mLocation, false); } else if (mTrueJump) { if (mTrueJump->mPlace != mPlace + 1) { if (mBranchIns) PutLocation(mBranchIns->mLocation, false); end += PutJump(proc, mTrueJump, end, mTrueJump->mOffset); 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, "main"); 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, "fighter_ai"); if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS) { ResetVisited(); mEntryBlock->MergeFunctionCalls(); } mEntryBlock->Assemble(); ResetVisited(); mEntryBlock = mEntryBlock->BypassEmptyBlocks(); ResetVisited(); mEntryBlock->ShortcutTailRecursion(); ExpandingArray 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, false)) progress = true; } while (progress); // final run to recycle jumps do { progress = false; for (int i = 0; i < placement.Size(); i++) placement[i]->mAsmFromJump = -1; total = 0; for (int i = 0; i < placement.Size(); i++) if (placement[i]->CalculateOffset(total, true)) progress = true; } while (progress); for (int i = 0; i < placement.Size(); i++) placement[i]->mAsmFromJump = -1; 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 | COPT_PROFILEINFO)) { 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->mTrueJump != block) 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 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 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 == 8 || (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->CombineAlternateLoads(); #endif #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(); ResetVisited(); mEntryBlock->MergeSameBranch(); #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] - 1) * iblock->mInstructions[i + 1]->mSrc[0].mStride < 256) { 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) && ins->mSrc[0].mRange.mMaxValue + (InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] - 1) * iblock->mInstructions[i + 1]->mSrc[1].mStride < 256) { 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) { // Check conflicting local branch if (i > 0 && block->mIns[i - 1].mMode == ASMIM_RELATIVE && block->mIns[i - 1].mAddress > 0) return; 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) { // Check conflicting local branch if (i > 0 && block->mIns[i - 1].mMode == ASMIM_RELATIVE && block->mIns[i - 1].mAddress > 0) return false; 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 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 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; }