#include "NativeCodeGenerator.h" #include "CompilerTypes.h" static bool CheckFunc; 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_MEM = 0x00000020; static const uint32 LIVE_ALL = 0x000000ff; static int GlobalValueNumber = 0; NativeRegisterData::NativeRegisterData(void) : mMode(NRDM_UNKNOWN), mValue(GlobalValueNumber++), mMask(0) { } void NativeRegisterData::Reset(void) { mMode = NRDM_UNKNOWN; mValue = GlobalValueNumber++; } void NativeRegisterData::ResetMask(void) { mMask = 0; } bool NativeRegisterData::SameData(const NativeCodeInstruction& ins) const { if (ins.mMode == ASMIM_ZERO_PAGE) return mMode == NRDM_ZERO_PAGE && mValue == ins.mAddress; else if (ins.mMode == ASMIM_ABSOLUTE) return mMode == NRDM_ABSOLUTE && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags; else if (ins.mMode == ASMIM_ABSOLUTE_X) return mMode == NRDM_ABSOLUTE_X && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags; else if (ins.mMode == ASMIM_ABSOLUTE_Y) return mMode == NRDM_ABSOLUTE_Y && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags; else if (ins.mMode == ASMIM_INDIRECT_Y) return mMode == NRDM_INDIRECT_Y && mValue == ins.mAddress; else return false; } bool NativeRegisterData::SameData(const NativeRegisterData& d) const { if (mMode != d.mMode) return false; switch (mMode) { case NRDM_UNKNOWN: case NRDM_IMMEDIATE: case NRDM_ZERO_PAGE: return mValue == d.mValue; case NRDM_IMMEDIATE_ADDRESS: case NRDM_ABSOLUTE: return mValue == d.mValue && mLinkerObject == d.mLinkerObject && mFlags == d.mFlags; default: return false; } } void NativeRegisterDataSet::Reset(void) { for (int i = 0; i < NUM_REGS; i++) mRegs[i].Reset(); } void NativeRegisterDataSet::ResetMask(void) { for (int i = 0; i < NUM_REGS; i++) mRegs[i].ResetMask(); } void NativeRegisterDataSet::ResetWorkRegs(void) { ResetZeroPage(BC_REG_WORK_Y); ResetZeroPage(BC_REG_ADDR + 0); ResetZeroPage(BC_REG_ADDR + 1); for (int i = 0; i < 4; i++) ResetZeroPage(BC_REG_ACCU + i); for (int i = 0; i < 8; i++) ResetZeroPage(BC_REG_WORK + i); } 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(); } } 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::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; } else if (mRegs[mRegs[i].mValue].mValue != set.mRegs[set.mRegs[i].mValue].mValue) { mRegs[i].Reset(); changed = true; } } 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 || mRegs[i].mMode == NRDM_ABSOLUTE_Y) { mRegs[i].Reset(); changed = true; } } } while (changed); } NativeCodeInstruction::NativeCodeInstruction(AsmInsType type, AsmInsMode mode, int address, LinkerObject* linkerObject, uint32 flags, int param) : mType(type), mMode(mode), mAddress(address), mLinkerObject(linkerObject), mFlags(flags), mParam(param), mLive(LIVE_ALL) { if (mode == ASMIM_IMMEDIATE_ADDRESS) { assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER)); assert(HasAsmInstructionMode(mType, ASMIM_IMMEDIATE)); } if (mode == ASMIM_IMMEDIATE) { assert(address >= 0 && address < 256); } if (mode == ASMIM_ZERO_PAGE) { assert(address >= 2 && address < 256); } } NativeCodeInstruction::NativeCodeInstruction(AsmInsType type, const NativeCodeInstruction& addr) : mType(type), mMode(addr.mMode), mAddress(addr.mAddress), mLinkerObject(addr.mLinkerObject), mFlags(addr.mFlags), mParam(addr.mParam), mLive(LIVE_ALL) { } bool NativeCodeInstruction::IsUsedResultInstructions(NumberSet& requiredTemps) { bool used = false; mLive = 0; if (requiredTemps[CPU_REG_A]) mLive |= LIVE_CPU_REG_A; if (requiredTemps[CPU_REG_X]) mLive |= LIVE_CPU_REG_X; if (requiredTemps[CPU_REG_Y]) mLive |= LIVE_CPU_REG_Y; if (requiredTemps[CPU_REG_Z]) mLive |= LIVE_CPU_REG_Z; if (requiredTemps[CPU_REG_C]) mLive |= LIVE_CPU_REG_C; if (mMode == ASMIM_ZERO_PAGE && requiredTemps[mAddress]) mLive |= LIVE_MEM; if (mMode == ASMIM_INDIRECT_Y && (requiredTemps[mAddress] || requiredTemps[mAddress + 1])) mLive |= LIVE_MEM; if (mType == ASMIT_JSR) { requiredTemps -= CPU_REG_C; requiredTemps -= CPU_REG_Z; requiredTemps -= CPU_REG_A; requiredTemps -= CPU_REG_X; requiredTemps -= CPU_REG_Y; if (mFlags & NCIF_USE_CPU_REG_A) requiredTemps += CPU_REG_A; if (mFlags & NCIF_USE_CPU_REG_X) requiredTemps += CPU_REG_X; if (mFlags & NCIF_USE_CPU_REG_Y) requiredTemps += CPU_REG_Y; if (mFlags & NCIF_RUNTIME) { for (int i = 0; i < 4; i++) { requiredTemps += BC_REG_ACCU + i; requiredTemps += BC_REG_WORK + i; } if (mFlags & NCIF_USE_ZP_32_X) { for (int i = 0; i < 4; i++) requiredTemps += mParam + i; } if (mFlags & NCIF_FEXEC) { requiredTemps += BC_REG_LOCALS; requiredTemps += BC_REG_LOCALS + 1; for(int i= BC_REG_FPARAMS; i< BC_REG_FPARAMS_END; i++) requiredTemps += i; } } else { for (int i = 0; i < 4; i++) { requiredTemps -= BC_REG_ACCU + i; requiredTemps -= BC_REG_WORK + i; } if (mFlags & NICF_USE_WORKREGS) { for (int i = 0; i < 10; i++) requiredTemps += BC_REG_WORK + i; } requiredTemps += BC_REG_LOCALS; requiredTemps += BC_REG_LOCALS + 1; if (mLinkerObject) { for (int i = 0; i < mLinkerObject->mNumTemporaries; i++) { for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++) requiredTemps += mLinkerObject->mTemporaries[i] + j; } } } return true; } if (mType == ASMIT_RTS) { #if 1 if (mFlags & NCIF_LOWER) { requiredTemps += BC_REG_ACCU; if (mFlags & NCIF_UPPER) { requiredTemps += BC_REG_ACCU + 1; if (mFlags & NCIF_LONG) { requiredTemps += BC_REG_ACCU + 2; requiredTemps += BC_REG_ACCU + 3; } } } #endif #if 0 for (int i = 0; i < 4; i++) { requiredTemps += BC_REG_ACCU + i; } #endif requiredTemps += BC_REG_STACK; requiredTemps += BC_REG_STACK + 1; requiredTemps += BC_REG_LOCALS; requiredTemps += BC_REG_LOCALS + 1; return true; } if (mType == ASMIT_BYTE) return true; // check side effects switch (mType) { case ASMIT_STA: case ASMIT_STX: case ASMIT_STY: case ASMIT_INC: case ASMIT_DEC: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_ROL: case ASMIT_ROR: if (mMode != ASMIM_IMPLIED && mMode != ASMIM_ZERO_PAGE) used = true; break; case ASMIT_JSR: case ASMIT_JMP: case ASMIT_BEQ: case ASMIT_BNE: case ASMIT_BPL: case ASMIT_BMI: case ASMIT_BCC: case ASMIT_BCS: used = true; break; } if (requiredTemps[CPU_REG_C]) { switch (mType) { case ASMIT_CLC: case ASMIT_SEC: case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ROL: case ASMIT_ROR: case ASMIT_CMP: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_CPX: case ASMIT_CPY: used = true; break; } } if (requiredTemps[CPU_REG_Z]) { switch (mType) { case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ROL: case ASMIT_ROR: case ASMIT_INC: case ASMIT_DEC: case ASMIT_CMP: case ASMIT_CPX: case ASMIT_CPY: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_ORA: case ASMIT_EOR: case ASMIT_AND: case ASMIT_LDA: case ASMIT_LDX: case ASMIT_LDY: case ASMIT_BIT: case ASMIT_INX: case ASMIT_DEX: case ASMIT_INY: case ASMIT_DEY: case ASMIT_TYA: case ASMIT_TXA: case ASMIT_TAY: case ASMIT_TAX: used = true; break; } } if (requiredTemps[CPU_REG_A]) { switch (mType) { case ASMIT_ROL: case ASMIT_ROR: case ASMIT_ASL: case ASMIT_LSR: if (mMode == ASMIM_IMPLIED) used = true; break; case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ORA: case ASMIT_EOR: case ASMIT_AND: case ASMIT_LDA: case ASMIT_TXA: case ASMIT_TYA: used = true; break; } } if (requiredTemps[CPU_REG_X]) { switch (mType) { case ASMIT_LDX: case ASMIT_INX: case ASMIT_DEX: case ASMIT_TAX: used = true; break; } } if (requiredTemps[CPU_REG_Y]) { switch (mType) { case ASMIT_LDY: case ASMIT_INY: case ASMIT_DEY: case ASMIT_TAY: used = true; break; } } if (mMode == ASMIM_ZERO_PAGE) { switch (mType) { case ASMIT_ROL: case ASMIT_ROR: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_INC: case ASMIT_DEC: case ASMIT_STA: case ASMIT_STX: case ASMIT_STY: if (requiredTemps[mAddress]) used = true; break; } } if (used) { switch (mMode) { case ASMIM_ZERO_PAGE_X: case ASMIM_INDIRECT_X: case ASMIM_ABSOLUTE_X: requiredTemps += CPU_REG_X; break; case ASMIM_ZERO_PAGE_Y: case ASMIM_ABSOLUTE_Y: requiredTemps += CPU_REG_Y; break; case ASMIM_INDIRECT_Y: requiredTemps += CPU_REG_Y; requiredTemps += mAddress; requiredTemps += mAddress + 1; break; } // check carry flags switch (mType) { case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ROL: case ASMIT_ROR: requiredTemps += CPU_REG_C; break; case ASMIT_CMP: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_CPX: case ASMIT_CPY: case ASMIT_CLC: case ASMIT_SEC: requiredTemps -= CPU_REG_C; break; case ASMIT_BCC: case ASMIT_BCS: requiredTemps += CPU_REG_C; break; case ASMIT_BEQ: case ASMIT_BNE: case ASMIT_BPL: case ASMIT_BMI: requiredTemps += CPU_REG_Z; break; } // check zero flags switch (mType) { case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ROL: case ASMIT_ROR: case ASMIT_CMP: case ASMIT_CPX: case ASMIT_CPY: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_INC: case ASMIT_DEC: case ASMIT_ORA: case ASMIT_EOR: case ASMIT_AND: case ASMIT_LDA: case ASMIT_LDX: case ASMIT_LDY: case ASMIT_BIT: case ASMIT_TAY: case ASMIT_TYA: case ASMIT_TAX: case ASMIT_TXA: case ASMIT_INX: case ASMIT_DEX: case ASMIT_INY: case ASMIT_DEY: requiredTemps -= CPU_REG_Z; break; } // check CPU register switch (mType) { case ASMIT_ROL: case ASMIT_ROR: case ASMIT_ASL: case ASMIT_LSR: if (mMode == ASMIM_IMPLIED) requiredTemps += CPU_REG_A; break; case ASMIT_LDA: requiredTemps -= CPU_REG_A; break; case ASMIT_ADC: case ASMIT_SBC: case ASMIT_ORA: case ASMIT_EOR: case ASMIT_AND: requiredTemps += CPU_REG_A; break; case ASMIT_LDX: requiredTemps -= CPU_REG_X; break; case ASMIT_INX: case ASMIT_DEX: requiredTemps += CPU_REG_X; break; case ASMIT_LDY: requiredTemps -= CPU_REG_Y; break; case ASMIT_INY: case ASMIT_DEY: requiredTemps += CPU_REG_Y; break; case ASMIT_CMP: case ASMIT_STA: requiredTemps += CPU_REG_A; break; case ASMIT_CPX: case ASMIT_STX: requiredTemps += CPU_REG_X; break; case ASMIT_CPY: case ASMIT_STY: requiredTemps += CPU_REG_Y; break; case ASMIT_TXA: requiredTemps += CPU_REG_X; requiredTemps -= CPU_REG_A; break; case ASMIT_TYA: requiredTemps += CPU_REG_Y; requiredTemps -= CPU_REG_A; break; case ASMIT_TAX: requiredTemps += CPU_REG_A; requiredTemps -= CPU_REG_X; break; case ASMIT_TAY: requiredTemps += CPU_REG_A; requiredTemps -= CPU_REG_Y; break; } if (mMode == ASMIM_ZERO_PAGE) { switch (mType) { case ASMIT_STA: case ASMIT_STX: case ASMIT_STY: requiredTemps -= mAddress; break; default: requiredTemps += mAddress; } } return true; } return false; } bool NativeCodeInstruction::LoadsAccu(void) const { return mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_JSR; } bool NativeCodeInstruction::ChangesAccuAndFlag(void) const { if (mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR || mType == ASMIT_SBC || mType == ASMIT_ADC) return true; else if (mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROR || mType == ASMIT_ROL) return mMode == ASMIM_IMPLIED; else return false; } uint32 NativeCodeInstruction::NeedsLive(void) const { uint32 live = mLive; if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y) live |= LIVE_CPU_REG_Y; if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X) live |= LIVE_CPU_REG_X; if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY) live |= LIVE_CPU_REG_Y; if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX) live |= LIVE_CPU_REG_X; if (mMode == ASMIM_IMPLIED && (mType == ASMIT_TAX || mType == ASMIT_TAY || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR)) live |= LIVE_CPU_REG_A; if (mType == ASMIT_STA || mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR || mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP) live |= LIVE_CPU_REG_A; if (mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_ROL || mType == ASMIT_ROR) live |= LIVE_CPU_REG_C; return live; } bool NativeCodeInstruction::RequiresYReg(void) const { if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y) return true; if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY) return true; return false; } bool NativeCodeInstruction::RequiresXReg(void) const { if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X) return true; if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX) return true; return false; } bool NativeCodeInstruction::ReplaceYRegWithXReg(void) { bool changed = false; switch (mType) { case ASMIT_LDY: mType = ASMIT_LDX; changed = true; break; case ASMIT_STY: mType = ASMIT_STX; changed = true; break; case ASMIT_CPY: mType = ASMIT_CPX; changed = true; break; case ASMIT_TYA: mType = ASMIT_TXA; changed = true; break; case ASMIT_TAY: mType = ASMIT_TAX; changed = true; break; case ASMIT_INY: mType = ASMIT_INX; changed = true; break; case ASMIT_DEY: mType = ASMIT_DEX; changed = true; break; } if (mMode == ASMIM_ABSOLUTE_Y) { assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X)); mMode = ASMIM_ABSOLUTE_X; changed = true; } if (mLive & LIVE_CPU_REG_Y) mLive |= LIVE_CPU_REG_X; return changed; } bool NativeCodeInstruction::CanSwapXYReg(void) { if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y) return false; else if (mMode == ASMIM_ABSOLUTE_X) return HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y); else if (mMode == ASMIM_ABSOLUTE_Y) return HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X); else return true; } bool NativeCodeInstruction::SwapXYReg(void) { bool changed = false; switch (mType) { case ASMIT_LDX: mType = ASMIT_LDY; changed = true; break; case ASMIT_STX: mType = ASMIT_STY; changed = true; break; case ASMIT_CPX: mType = ASMIT_CPY; changed = true; break; case ASMIT_TXA: mType = ASMIT_TYA; changed = true; break; case ASMIT_TAX: mType = ASMIT_TAY; changed = true; break; case ASMIT_INX: mType = ASMIT_INY; changed = true; break; case ASMIT_DEX: mType = ASMIT_DEY; changed = true; break; case ASMIT_LDY: mType = ASMIT_LDX; changed = true; break; case ASMIT_STY: mType = ASMIT_STX; changed = true; break; case ASMIT_CPY: mType = ASMIT_CPX; changed = true; break; case ASMIT_TYA: mType = ASMIT_TXA; changed = true; break; case ASMIT_TAY: mType = ASMIT_TAX; changed = true; break; case ASMIT_INY: mType = ASMIT_INX; changed = true; break; case ASMIT_DEY: mType = ASMIT_DEX; changed = true; break; } if (mMode == ASMIM_ABSOLUTE_X) { assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y)); mMode = ASMIM_ABSOLUTE_Y; changed = true; } else if (mMode == ASMIM_ABSOLUTE_Y) { assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X)); mMode = ASMIM_ABSOLUTE_X; changed = true; } uint32 live = mLive; mLive &= ~(LIVE_CPU_REG_X | LIVE_CPU_REG_Y); if (live & LIVE_CPU_REG_X) mLive |= LIVE_CPU_REG_Y; if (live & LIVE_CPU_REG_Y) mLive |= LIVE_CPU_REG_X; return changed; } static void UpdateCollisionSet(NumberSet& liveTemps, NumberSet* collisionSets, int temp) { int i; if (temp >= 0 && !liveTemps[temp]) { for (i = 0; i < liveTemps.Size(); i++) { if (liveTemps[i]) { collisionSets[i] += temp; collisionSets[temp] += i; } } liveTemps += temp; } } void NativeCodeInstruction::BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets) { if (mMode == ASMIM_ZERO_PAGE) { if (ChangesAddress()) liveTemps -= mAddress; if (UsesAddress()) UpdateCollisionSet(liveTemps, collisionSets, mAddress); } if (mMode == ASMIM_INDIRECT_Y) { UpdateCollisionSet(liveTemps, collisionSets, mAddress); UpdateCollisionSet(liveTemps, collisionSets, mAddress + 1); } if (mType == ASMIT_JSR) { for(int i= BC_REG_ACCU; i< BC_REG_ACCU + 4; i++) UpdateCollisionSet(liveTemps, collisionSets, i); for (int i = BC_REG_WORK; i < BC_REG_WORK + 4; i++) UpdateCollisionSet(liveTemps, collisionSets, i); if (mFlags & NCIF_RUNTIME) { if (mFlags & NCIF_USE_ZP_32_X) { for (int i = mParam; i < mParam + 4; i++) UpdateCollisionSet(liveTemps, collisionSets, i); } if (mFlags & NCIF_FEXEC) { for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) UpdateCollisionSet(liveTemps, collisionSets, i); } } else { for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) UpdateCollisionSet(liveTemps, collisionSets, i); if (mLinkerObject && mLinkerObject->mProc) { for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++) UpdateCollisionSet(liveTemps, collisionSets, i); } else { for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) UpdateCollisionSet(liveTemps, collisionSets, i); } } } } bool NativeCodeInstruction::ReplaceXRegWithYReg(void) { bool changed = false; switch (mType) { case ASMIT_LDX: mType = ASMIT_LDY; changed = true; break; case ASMIT_STX: mType = ASMIT_STY; changed = true; break; case ASMIT_CPX: mType = ASMIT_CPY; changed = true; break; case ASMIT_TXA: mType = ASMIT_TYA; changed = true; break; case ASMIT_TAX: mType = ASMIT_TAY; changed = true; break; case ASMIT_INX: mType = ASMIT_INY; changed = true; break; case ASMIT_DEX: mType = ASMIT_DEY; changed = true; break; } if (mMode == ASMIM_ABSOLUTE_X) { assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y)); mMode = ASMIM_ABSOLUTE_Y; changed = true; } if (mLive & LIVE_CPU_REG_X) mLive |= LIVE_CPU_REG_Y; return changed; } bool NativeCodeInstruction::ChangesYReg(void) const { return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY || mType == ASMIT_JSR; } bool NativeCodeInstruction::ChangesXReg(void) const { return mType == ASMIT_TAX || mType == ASMIT_LDX || mType == ASMIT_INX || mType == ASMIT_DEX || mType == ASMIT_JSR; } bool NativeCodeInstruction::ReferencesCarry(void) const { return ChangesCarry() || RequiresCarry(); } bool NativeCodeInstruction::ReferencesAccu(void) const { return ChangesAccu() || RequiresAccu(); } bool NativeCodeInstruction::ReferencesYReg(void) const { return ChangesYReg() || RequiresYReg(); } bool NativeCodeInstruction::ReferencesXReg(void) const { return ChangesXReg() || RequiresXReg(); } bool NativeCodeInstruction::ReferencesZeroPage(int address) const { return UsesZeroPage(address) || ChangesZeroPage(address); } bool NativeCodeInstruction::ChangesZeroPage(int address) const { if (mMode == ASMIM_ZERO_PAGE && mAddress == address) return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY; else if (mType == ASMIT_JSR) { if (address >= BC_REG_ACCU && address < BC_REG_ACCU + 4) return true; if (address >= BC_REG_WORK && address < BC_REG_WORK + 8) return true; if (address >= BC_REG_ADDR && address < BC_REG_ADDR + 4) return true; if (!(mFlags & NCIF_RUNTIME) || (mFlags & NCIF_FEXEC)) { if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END) return true; if (mLinkerObject && mLinkerObject->mProc) { if (address >= BC_REG_TMP && address < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps) return true; } else { if (address >= BC_REG_TMP && address < BC_REG_TMP_SAVED) return true; } } 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_JSR; } bool NativeCodeInstruction::ChangesCarry(void) const { return mType == ASMIT_CLC || mType == ASMIT_SEC || mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY || mType == ASMIT_JSR; } bool NativeCodeInstruction::RequiresAccu(void) const { if (mMode == ASMIM_IMPLIED) { return mType == ASMIT_TAX || mType == ASMIT_TAY || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR; } else { return mType == ASMIT_STA || mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR || mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP; } } bool NativeCodeInstruction::UsesAccu(void) const { if (ChangesAccu()) return true; return mType == ASMIT_STA || mType == ASMIT_CMP || mType == ASMIT_TAX || mType == ASMIT_TAY; } bool NativeCodeInstruction::ChangesAccu(void) const { if (mMode == ASMIM_IMPLIED) { return mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR; } else { return mType == ASMIT_JSR || mType == ASMIT_LDA || mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR || mType == ASMIT_SBC || mType == ASMIT_ADC; } } bool NativeCodeInstruction::UsesAddress(void) const { if (mMode != ASMIM_IMPLIED) { return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY || mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY || mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR; } 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)); } bool NativeCodeInstruction::IsShift(void) const { return mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR; } bool NativeCodeInstruction::IsShiftOrInc(void) const { return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR;// || mType == ASMIT_ROL || mType == ASMIT_ROR; } bool NativeCodeInstruction::IsCommutative(void) const { return mType == ASMIT_ADC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR; } bool NativeCodeInstruction::IsSame(const NativeCodeInstruction& ins) const { if (mType == ins.mType && mMode == ins.mMode && mParam == ins.mParam) { switch (mMode) { case ASMIM_IMPLIED: return true; case ASMIM_IMMEDIATE: case ASMIM_ZERO_PAGE: case ASMIM_ZERO_PAGE_X: case ASMIM_ZERO_PAGE_Y: case ASMIM_INDIRECT_X: case ASMIM_INDIRECT_Y: return ins.mAddress == mAddress; case ASMIM_IMMEDIATE_ADDRESS: return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags); case ASMIM_ABSOLUTE: case ASMIM_ABSOLUTE_X: case ASMIM_ABSOLUTE_Y: return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress); default: return false; } } else return false; } bool NativeCodeInstruction::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 ((ins.mLive & LIVE_CPU_REG_Z) && 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::MayBeChangedOnAddress(const NativeCodeInstruction& ins, bool sameXY) const { if (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS) return false; if (ins.mType == ASMIT_JSR) { if (mMode == ASMIM_ZERO_PAGE) return ins.ChangesZeroPage(mAddress); else if (mMode == ASMIM_IMPLIED || mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS) return false; else return true; } if (!ins.ChangesAddress()) return false; if (ins.mMode == ASMIM_ZERO_PAGE) { if (mMode == ASMIM_ZERO_PAGE) return mAddress == ins.mAddress; else if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y) return mAddress == ins.mAddress || mAddress + 1 == ins.mAddress; else return mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y; } else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y) { return mMode == ASMIM_ZERO_PAGE || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y; } else if (ins.mMode == ASMIM_ABSOLUTE) { if (mMode == ASMIM_ABSOLUTE) return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress; else if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) return mLinkerObject == ins.mLinkerObject; else if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X) return mAddress != BC_REG_STACK; else return false; } else if (ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) { if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) { if (mLinkerObject != ins.mLinkerObject) return false; else return mMode != ins.mMode || !sameXY || mAddress == ins.mAddress; } else if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X) return mAddress != BC_REG_STACK; else return false; } else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X) { if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) return ins.mAddress != BC_REG_STACK; else return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X; } else return false; } bool NativeCodeInstruction::UsesMemoryOf(const NativeCodeInstruction& ins) const { if (ins.mMode == ASMIM_ZERO_PAGE) return UsesZeroPage(ins.mAddress); else if (UsesAddress()) { if (ins.mMode == ASMIM_ABSOLUTE && mMode == ASMIM_ABSOLUTE) return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress; else if ( (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)) return mLinkerObject == ins.mLinkerObject; else if (ins.mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_Y) return true; else return false; } else return false; } bool NativeCodeInstruction::SameEffectiveAddress(const NativeCodeInstruction& ins) const { if (mMode != ins.mMode) return false; switch (mMode) { case ASMIM_ZERO_PAGE: case ASMIM_ZERO_PAGE_X: case ASMIM_ZERO_PAGE_Y: case ASMIM_INDIRECT_X: case ASMIM_INDIRECT_Y: case ASMIM_IMMEDIATE: return ins.mAddress == mAddress; case ASMIM_ABSOLUTE: case ASMIM_ABSOLUTE_X: case ASMIM_ABSOLUTE_Y: return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress); default: return false; } } bool NativeCodeInstruction::ApplySimulation(const NativeRegisterDataSet& data) { switch (mType) { case ASMIT_LDA: case ASMIT_LDX: case ASMIT_LDY: case ASMIT_CMP: case ASMIT_CPX: case ASMIT_CPY: case ASMIT_ADC: case ASMIT_SBC: case ASMIT_AND: case ASMIT_ORA: case ASMIT_EOR: if (mMode == ASMIM_ZERO_PAGE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { mMode = ASMIM_IMMEDIATE; mAddress = data.mRegs[mAddress].mValue; return true; } else if (mMode == ASMIM_ZERO_PAGE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS) { mMode = ASMIM_IMMEDIATE_ADDRESS; mLinkerObject = data.mRegs[mAddress].mLinkerObject; mFlags = data.mRegs[mAddress].mFlags; mAddress = data.mRegs[mAddress].mValue; assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER)); return true; } break; } if (mMode == ASMIM_INDIRECT_Y && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE) { mMode = ASMIM_ABSOLUTE_Y; mAddress = data.mRegs[mAddress].mValue + 256 * data.mRegs[mAddress + 1].mValue; mLinkerObject = nullptr; } else if (mMode == ASMIM_INDIRECT_Y && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject) { mMode = ASMIM_ABSOLUTE_Y; mLinkerObject = data.mRegs[mAddress].mLinkerObject; mAddress = data.mRegs[mAddress].mValue; } return false; } void NativeCodeInstruction::Simulate(NativeRegisterDataSet& data) { int reg = -1; if (mMode == ASMIM_ZERO_PAGE) reg = mAddress; else if (mMode == ASMIM_IMPLIED) reg = CPU_REG_A; switch (mType) { case ASMIT_JSR: data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_X].Reset(); data.mRegs[CPU_REG_Y].Reset(); data.ResetWorkRegs(); if (mFlags & NCIF_FEXEC) { for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) data.mRegs[i].Reset(); } else if (!(mFlags & NCIF_RUNTIME)) { if (mLinkerObject && mLinkerObject->mProc) { for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++) data.mRegs[i].Reset(); } else { for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) data.mRegs[i].Reset(); } } break; case ASMIT_ROL: if (reg >= 0) { if (data.mRegs[reg].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { int t = (data.mRegs[reg].mValue << 1) | data.mRegs[CPU_REG_C].mValue; data.mRegs[CPU_REG_C].mValue = t >= 256; data.mRegs[reg].mValue = t & 255; data.mRegs[CPU_REG_Z].mValue = t & 255; data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; } else { 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 { 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_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 { 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 { 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; } } 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; 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 { 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_ZERO_PAGE) { data.mRegs[CPU_REG_A].mMask = data.mRegs[mAddress].mMask; data.mRegs[CPU_REG_A].mValue = data.mRegs[mAddress].mValue; if (data.mRegs[CPU_REG_A].mMask == 0xff) { mType = ASMIT_LDA; mMode = ASMIM_IMMEDIATE; mAddress = data.mRegs[CPU_REG_A].mValue; changed = true; } } else 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 = 0; 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_ZERO_PAGE) { data.mRegs[CPU_REG_X].mMask = data.mRegs[mAddress].mMask; data.mRegs[CPU_REG_X].mValue = data.mRegs[mAddress].mValue; if (data.mRegs[CPU_REG_X].mMask == 0xff) { mType = ASMIT_LDX; mMode = ASMIM_IMMEDIATE; mAddress = data.mRegs[CPU_REG_X].mValue; changed = true; } } else 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 = 0; 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_ZERO_PAGE) { data.mRegs[CPU_REG_Y].mMask = data.mRegs[mAddress].mMask; data.mRegs[CPU_REG_Y].mValue = data.mRegs[mAddress].mValue; if (data.mRegs[CPU_REG_Y].mMask == 0xff) { mType = ASMIT_LDY; mMode = ASMIM_IMMEDIATE; mAddress = data.mRegs[CPU_REG_Y].mValue; changed = true; } } else 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 = 0; 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: if (mMode == ASMIM_ZERO_PAGE) { int zeros = (data.mRegs[mAddress].mMask & ~data.mRegs[mAddress].mValue) | (data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue); int ones = (data.mRegs[mAddress].mMask & data.mRegs[mAddress].mValue) & (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; } } else if (mMode == ASMIM_IMMEDIATE) { if (mAddress != 0xff && ((data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue) | mAddress) == 0xff) { mAddress = 0xff; changed = true; } int zeros = ~mAddress | (data.mRegs[CPU_REG_A].mMask & ~data.mRegs[CPU_REG_A].mValue); int ones = mAddress & (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; } } else data.mRegs[CPU_REG_A].mMask &= ~data.mRegs[CPU_REG_A].mValue; break; case ASMIT_ORA: if (mMode == ASMIM_ZERO_PAGE) { int ones = (data.mRegs[mAddress].mMask & data.mRegs[mAddress].mValue) | (data.mRegs[CPU_REG_A].mMask & data.mRegs[CPU_REG_A].mValue); int zeros = (data.mRegs[mAddress].mMask & ~data.mRegs[mAddress].mValue) & (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; } } else if (mMode == ASMIM_IMMEDIATE) { if (mAddress != 0x00 && (~(data.mRegs[CPU_REG_A].mMask & data.mRegs[CPU_REG_A].mValue) & mAddress) == 0x00) { mAddress = 0x00; changed = true; } int ones = mAddress | (data.mRegs[CPU_REG_A].mMask & data.mRegs[CPU_REG_A].mValue); int zeros = ~ mAddress & (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; } } else data.mRegs[CPU_REG_A].mMask &= data.mRegs[CPU_REG_A].mValue; 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) { 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.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.ResetIndirect(0); data.ResetWorkRegs(); 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.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); } 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) { data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE_ADDRESS; data.mRegs[CPU_REG_A].mValue = mAddress; data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject; data.mRegs[CPU_REG_A].mFlags = mFlags; data.mRegs[CPU_REG_Z].Reset(); } else { if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_INDIRECT_Y && mMode != ASMIM_ABSOLUTE_X && mMode != ASMIM_ABSOLUTE_Y) data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_Z].Reset(); } break; case ASMIT_STA: if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_A].mValue) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } break; case ASMIT_STX: if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_X].mValue) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } break; case ASMIT_STY: if (mMode == ASMIM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mAddress == data.mRegs[CPU_REG_Y].mValue) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } break; case ASMIT_ADC: if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data.mRegs[CPU_REG_C].mValue == 0) { mType = ASMIT_ORA; changed = true; } else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0 && data.mRegs[CPU_REG_C].mValue == 0) { mType = ASMIT_LDA; changed = true; } else if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE) { int t = mAddress + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue; mType = ASMIT_LDA; mAddress = t & 0xff; int c = t >= 256; if (c && !data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_SEC; else if (!c && data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_CLC; changed = true; } } data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); break; case ASMIT_SBC: if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data.mRegs[CPU_REG_C].mValue == 1) { mType = ASMIT_ORA; changed = true; } else if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE) { int t = (mAddress ^ 0xff) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue; mType = ASMIT_LDA; mAddress = t & 0xff; int c = t >= 256; if (c && !data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_SEC; else if (!c && data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_CLC; changed = true; } else if (mMode == ASMIM_IMMEDIATE_ADDRESS && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS && mLinkerObject == data.mRegs[CPU_REG_A].mLinkerObject) { int t; if (mFlags & NCIF_LOWER) t = (mAddress ^ 0xffff) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue; else t = ((mAddress ^ 0xffff) >> 8) + data.mRegs[CPU_REG_A].mValue + data.mRegs[CPU_REG_C].mValue; mType = ASMIT_LDA; mMode = ASMIM_IMMEDIATE; mAddress = t & 0xff; int c = t >= 256; if (c && !data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_SEC; else if (!c && data.mRegs[CPU_REG_C].mValue) carryop = ASMIT_CLC; changed = true; } } data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); break; case ASMIT_CMP: if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_A].mValue - mAddress; data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_A].mValue >= mAddress; } else if (mMode == ASMIM_IMMEDIATE && mAddress == 0) { data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_C].mValue = 1; data.mRegs[CPU_REG_Z].Reset(); } else { data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); } break; case ASMIT_CPX: if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_X].mValue - mAddress; data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_X].mValue >= mAddress; } else { data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); } break; case ASMIT_CPY: if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = data.mRegs[CPU_REG_Y].mValue - mAddress; data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_C].mValue = data.mRegs[CPU_REG_Y].mValue >= mAddress; } else { data.mRegs[CPU_REG_C].Reset(); data.mRegs[CPU_REG_Z].Reset(); } break; case ASMIT_ORA: case ASMIT_EOR: case ASMIT_AND: if (mMode == ASMIM_IMMEDIATE && data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE) { if (mType == ASMIT_ORA) mAddress |= data.mRegs[CPU_REG_A].mValue; else if (mType == ASMIT_AND) mAddress &= data.mRegs[CPU_REG_A].mValue; else if (mType == ASMIT_EOR) mAddress ^= data.mRegs[CPU_REG_A].mValue; mType = ASMIT_LDA; data.mRegs[CPU_REG_A].mValue = mAddress; data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = mAddress; changed = true; } else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0) { if (mType == ASMIT_ORA || mType == ASMIT_EOR) { mType = ASMIT_LDA; data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_Z].Reset(); } else { mType = ASMIT_LDA; mMode = ASMIM_IMMEDIATE; mAddress = 0; data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = 0; } changed = true; } else if (mMode == ASMIM_IMMEDIATE && ((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_ZERO_PAGE && mMode != ASMIM_ABSOLUTE) data.mRegs[CPU_REG_X].Reset(); 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_ZERO_PAGE && mMode != ASMIM_ABSOLUTE) 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: 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: 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)) { int i = data.FindAbsolute(mLinkerObject, mAddress); if (i >= 0) { mMode = ASMIM_ZERO_PAGE; mAddress = i; mLinkerObject = nullptr; 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) { 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 { data.mRegs[CPU_REG_A].Reset(); if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_A].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_A].mValue = data.mRegs[mAddress].mValue; } else if (initial && mAddress == BC_REG_WORK_Y) { data.mRegs[CPU_REG_A].Reset(); } else { data.mRegs[CPU_REG_A].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_A].mValue = mAddress; } } break; case ASMIT_LDX: if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_X].mValue == mAddress) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_X] = data.mRegs[mAddress]; mAddress = data.mRegs[CPU_REG_X].mValue; mMode = ASMIM_IMMEDIATE; changed = true; } else if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress) { mType = ASMIT_TAX; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A]; changed = true; } else if (data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A])) { mType = ASMIT_TAX; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A]; changed = true; } #if 1 else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE) { data.mRegs[CPU_REG_X] = data.mRegs[mAddress]; mAddress = data.mRegs[CPU_REG_X].mValue; changed = true; } #endif else { data.mRegs[CPU_REG_X].Reset(); if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_X].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_X].mValue = data.mRegs[mAddress].mValue; } else { data.mRegs[CPU_REG_X].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_X].mValue = mAddress; } } break; case ASMIT_LDY: if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mValue == mAddress) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_Y] = data.mRegs[mAddress]; mAddress = data.mRegs[CPU_REG_Y].mValue; mMode = ASMIM_IMMEDIATE; changed = true; } else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress) { mType = ASMIT_TAY; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A]; changed = true; } else if (final && data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A])) { mType = ASMIT_TAY; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A]; changed = true; } #if 1 else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE) { data.mRegs[CPU_REG_Y] = data.mRegs[mAddress]; mAddress = data.mRegs[CPU_REG_Y].mValue; changed = true; } #endif else { data.mRegs[CPU_REG_Y].Reset(); if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { data.mRegs[CPU_REG_Y].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Y].mValue = data.mRegs[mAddress].mValue; } else { data.mRegs[CPU_REG_Y].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_Y].mValue = mAddress; } } break; case ASMIT_ADC: case ASMIT_SBC: case ASMIT_AND: case ASMIT_ORA: case ASMIT_EOR: case ASMIT_CMP: case ASMIT_CPX: case ASMIT_CPY: if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { mAddress = data.mRegs[mAddress].mValue; mMode = ASMIM_IMMEDIATE; changed = true; } else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE) { mAddress = data.mRegs[mAddress].mValue; changed = true; } else if (data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && !final) { mMode = ASMIM_ABSOLUTE; mLinkerObject = data.mRegs[mAddress].mLinkerObject; mAddress = data.mRegs[mAddress].mValue; changed = true; } break; case ASMIT_STA: if (data.mRegs[mAddress].SameData(data.mRegs[CPU_REG_A]) || data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_A].mValue == mAddress) { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; changed = true; } else { data.ResetZeroPage(mAddress); if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE || data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS) { data.mRegs[mAddress] = data.mRegs[CPU_REG_A]; } else if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE) { #if 1 if (data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode == NRDM_UNKNOWN && (mAddress >= BC_REG_FPARAMS && mAddress < BC_REG_FPARAMS_END) && !(data.mRegs[CPU_REG_A].mValue >= BC_REG_FPARAMS && data.mRegs[CPU_REG_A].mValue < BC_REG_FPARAMS_END)) { data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode = NRDM_ZERO_PAGE; data.mRegs[data.mRegs[CPU_REG_A].mValue].mValue = mAddress; data.mRegs[mAddress].Reset(); } else #endif { data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue; } } else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE) { data.mRegs[mAddress] = data.mRegs[CPU_REG_A]; } else { data.mRegs[CPU_REG_A].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_A].mValue = mAddress; } } break; case ASMIT_STX: data.ResetZeroPage(mAddress); if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE) { data.mRegs[mAddress].mMode = NRDM_IMMEDIATE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_X].mValue; } else if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE) { data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_X].mValue; } else if (data.mRegs[CPU_REG_X].mMode == NRDM_ABSOLUTE) { data.mRegs[mAddress] = data.mRegs[CPU_REG_X]; } else { data.mRegs[CPU_REG_X].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_X].mValue = mAddress; } break; case ASMIT_STY: data.ResetZeroPage(mAddress); if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE) { data.mRegs[mAddress].mMode = NRDM_IMMEDIATE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_Y].mValue; } else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE) { data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_Y].mValue; } else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ABSOLUTE) { data.mRegs[mAddress] = data.mRegs[CPU_REG_Y]; } else { data.mRegs[CPU_REG_Y].mMode = NRDM_ZERO_PAGE; data.mRegs[CPU_REG_Y].mValue = mAddress; } break; case ASMIT_INC: case ASMIT_DEC: case ASMIT_ASL: case ASMIT_LSR: case ASMIT_ROL: case ASMIT_ROR: data.ResetZeroPage(mAddress); break; } } else if (final && mMode == ASMIM_IMMEDIATE) { #if 1 switch (mType) { case ASMIT_LDA: if (data.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_Y].mValue == mAddress) { data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y]; mType = ASMIT_TYA; mMode = ASMIM_IMPLIED; changed = true; } else if (data.mRegs[CPU_REG_X].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_X].mValue == mAddress) { data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X]; mType = ASMIT_TXA; mMode = ASMIM_IMPLIED; changed = true; } break; case ASMIT_LDX: if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == mAddress) { data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A]; mType = ASMIT_TAX; mMode = ASMIM_IMPLIED; changed = true; } break; case ASMIT_LDY: if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == mAddress) { data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A]; mType = ASMIT_TAY; mMode = ASMIM_IMPLIED; changed = true; } break; } #endif } else if (mMode == ASMIM_INDIRECT_Y) { if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress + 1].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress].mValue + 1 == data.mRegs[mAddress + 1].mValue) { mFlags |= NICT_ZPFLIPPED; mAddress = data.mRegs[mAddress].mValue; if (mType == ASMIT_LDA) data.mRegs[CPU_REG_A].Reset(); } else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject) { mMode = ASMIM_ABSOLUTE_Y; mLinkerObject = data.mRegs[mAddress].mLinkerObject; mAddress = data.mRegs[mAddress + 1].mValue; if (mType == ASMIT_LDA) data.mRegs[CPU_REG_A].Reset(); } else if (mType == ASMIT_LDA) { if (!(mFlags & NCIF_VOLATILE)) { if (data.mRegs[CPU_REG_A].mMode == NRDM_INDIRECT_Y && data.mRegs[CPU_REG_A].mValue == mAddress) { if (mLive & LIVE_CPU_REG_Z) { mType = ASMIT_ORA; mMode = ASMIM_IMMEDIATE; mAddress = 0; } else { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; } changed = true; } else if (data.mRegs[CPU_REG_X].SameData(*this)) { mType = ASMIT_TXA; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X]; changed = true; } else if (data.mRegs[CPU_REG_Y].SameData(*this)) { mType = ASMIT_TYA; mMode = ASMIM_IMPLIED; data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y]; changed = true; } else { data.mRegs[CPU_REG_A].mMode = NRDM_INDIRECT_Y; data.mRegs[CPU_REG_A].mValue = mAddress; data.mRegs[CPU_REG_A].mFlags = mFlags; } } else data.mRegs[CPU_REG_A].Reset(); } if (ChangesAddress()) data.ResetIndirect(mAddress); } else if (mMode == ASMIM_ABSOLUTE_X) { if (mType == ASMIT_LDA) { if (!(mFlags & NCIF_VOLATILE)) { if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress) { if (mLive & LIVE_CPU_REG_Z) { mType = ASMIT_ORA; mMode = ASMIM_IMMEDIATE; mAddress = 0; } else { mType = ASMIT_NOP; mMode = ASMIM_IMPLIED; } changed = true; } else { data.mRegs[CPU_REG_A].mMode = NRDM_ABSOLUTE_X; data.mRegs[CPU_REG_A].mLinkerObject = mLinkerObject; data.mRegs[CPU_REG_A].mValue = mAddress; data.mRegs[CPU_REG_A].mFlags = mFlags; } } else data.mRegs[CPU_REG_A].Reset(); } if (ChangesAddress()) data.ResetIndirect(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(); } if (ChangesAddress()) data.ResetIndirect(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; 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_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; 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_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: 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) { if (mType == ASMIT_BYTE) block->PutByte(mAddress); 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->PutByte(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->PutByte(AsmInsOpcodes[mType][ASMIM_IMMEDIATE]); } else { assert(HasAsmInstructionMode(mType, mode)); block->PutByte(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 { assert(mAddress != 0); 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 { block->PutWord(uint16(mAddress)); } break; case ASMIM_RELATIVE: block->PutByte(uint8(mAddress)); break; } } } void NativeCodeBasicBlock::PutByte(uint8 code) { this->mCode.Push(code); } void NativeCodeBasicBlock::PutWord(uint16 code) { this->mCode.Push((uint8)(code & 0xff)); this->mCode.Push((uint8)(code >> 8)); } static AsmInsType InvertBranchCondition(AsmInsType code) { switch (code) { case ASMIT_BEQ: return ASMIT_BNE; case ASMIT_BNE: return ASMIT_BEQ; case ASMIT_BPL: return ASMIT_BMI; case ASMIT_BMI: return ASMIT_BPL; case ASMIT_BCS: return ASMIT_BCC; case ASMIT_BCC: return ASMIT_BCS; default: return code; } } static AsmInsType TransposeBranchCondition(AsmInsType code) { switch (code) { case ASMIT_BEQ: return ASMIT_BEQ; case ASMIT_BNE: return ASMIT_BNE; case ASMIT_BPL: return ASMIT_BMI; case ASMIT_BMI: return ASMIT_BPL; case ASMIT_BCS: return ASMIT_BCC; case ASMIT_BCC: return ASMIT_BCS; default: return code; } } int NativeCodeBasicBlock::PutJump(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, int offset) { if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS) { if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR()) { this->mCode[this->mCode.Size() - 3] = 0x4c; return 0; } else { PutByte(0x60); return 1; } } #if 1 else if (offset >= -126 && offset <= 129) { if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { if (mNDataSet.mRegs[CPU_REG_C].mValue) PutByte(AsmInsOpcodes[ASMIT_BCS][ASMIM_RELATIVE]); else PutByte(AsmInsOpcodes[ASMIT_BCC][ASMIM_RELATIVE]); PutByte(offset - 2); return 2; } else if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) { if (mNDataSet.mRegs[CPU_REG_Z].mValue) PutByte(AsmInsOpcodes[ASMIT_BNE][ASMIM_RELATIVE]); else PutByte(AsmInsOpcodes[ASMIT_BEQ][ASMIM_RELATIVE]); PutByte(offset - 2); return 2; } } #endif PutByte(0x4c); LinkerReference rl; rl.mObject = nullptr; rl.mOffset = mCode.Size(); rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE; rl.mRefObject = nullptr; rl.mRefOffset = target->mOffset; mRelocations.Push(rl); PutWord(0); return 3; } int NativeCodeBasicBlock::BranchByteSize(NativeCodeBasicBlock* target, int from, int to) { if (to - from >= -126 && to - from <= 129) return 2; else { if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS) return 3; return 5; } } int NativeCodeBasicBlock::JumpByteSize(NativeCodeBasicBlock* target, int offset) { if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS) { if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR()) return 0; else return 1; } #if 1 else if (offset >= -126 && offset <= 129) { if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) return 2; else if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) return 2; else return 3; } #endif else return 3; } int NativeCodeBasicBlock::PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int offset) { if (offset >= -126 && offset <= 129) { PutByte(AsmInsOpcodes[code][ASMIM_RELATIVE]); PutByte(offset - 2); return 2; } else { PutByte(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]); if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS) { PutByte(1); PutByte(0x60); return 3; } else { PutByte(3); PutByte(0x4c); LinkerReference rl; rl.mObject = nullptr; rl.mOffset = mCode.Size(); rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE; rl.mRefObject = nullptr; rl.mRefOffset = mOffset + mCode.Size() + offset - 3; mRelocations.Push(rl); PutWord(0); return 5; } } } void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure * proc, const InterInstruction * ins, InterType type, int reg) { if (type == IT_FLOAT) { union { float f; unsigned int v; } cc; cc.f = ins->mConst.mFloatConst; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (type == IT_POINTER) { if (ins->mConst.mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mConst.mIntConst, ins->mConst.mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mConst.mIntConst, ins->mConst.mLinkerObject, NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mConst.mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mConst.mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mConst.mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mConst.mMemory == IM_FPARAM || ins->mConst.mMemory == IM_FFRAME) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mConst.mVarIndex + ins->mConst.mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mConst.mMemory == IM_FRAME) { int index = ins->mConst.mVarIndex + ins->mConst.mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mConst.mMemory == IM_LOCAL || ins->mConst.mMemory == IM_PARAM) { int index = ins->mConst.mIntConst; int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS; if (ins->mConst.mMemory == IM_LOCAL) index += proc->mLocalVars[ins->mConst.mVarIndex]->mOffset; else index += ins->mConst.mVarIndex + proc->mLocalSize + 2; index += mFrameOffset; CheckFrameIndex(areg, index, 2); if (index != 0) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, areg)); if (index != 0) mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1)); if (index != 0) mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mConst.mMemory == IM_PROCEDURE) { NativeCodeInstruction lins(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mConst.mLinkerObject, NCIF_LOWER); NativeCodeInstruction hins(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mConst.mLinkerObject, NCIF_UPPER); mIns.Push(lins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(hins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } } else if (type == IT_INT32) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mConst.mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mConst.mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mConst.mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mConst.mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mConst.mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); if (InterTypeSize[ins->mDst.mType] > 1) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mConst.mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } } } 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(int& reg, int& index, int size, int treg) { if (index < 0 || index + size > 256) { if (treg == 0) treg = BC_REG_ADDR; mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); index = 0; reg = treg; } } void NativeCodeBasicBlock::StoreValue(InterCodeProcedure* proc, const InterInstruction * ins) { uint32 flags = NCIF_LOWER | NCIF_UPPER; if (ins->mVolatile) flags |= NCIF_VOLATILE; if (ins->mSrc[0].mType == IT_FLOAT) { int stride = ins->mSrc[1].mStride; if (ins->mSrc[1].mTemp < 0) { if (ins->mSrc[0].mTemp < 0) { union { float f; unsigned int v; } cc; cc.f = ins->mSrc[0].mFloatConst; if (ins->mSrc[1].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[0].mFloatConst; int reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; int index = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; if (stride * 4 <= 256) { CheckFrameIndex(reg, index, stride * 4); for (int i = 0; i < 4; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < 4; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; if (stride * 4 <= 256) { CheckFrameIndex(reg, index, stride * 4); for (int i = 0; i < 4; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < 4; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); } } else { if (ins->mSrc[1].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; if (2 * stride <= 256) { CheckFrameIndex(reg, index, 2 * stride); for (int i = 0; i < 2; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < 2; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; if (2 * stride <= 256) { CheckFrameIndex(reg, index, 2 * stride); for (int i = 0; i < 2; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < 2; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); } else if (ins->mSrc[1].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); } else if (ins->mSrc[1].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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 = 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(reg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; int size = InterTypeSize[ins->mSrc[0].mType]; if (stride * size <= 256) { CheckFrameIndex(reg, index, stride * size); for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < size; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[1].mIntConst; int stride = ins->mSrc[1].mStride; int size = InterTypeSize[ins->mSrc[0].mType]; if (stride * size <= 256) { CheckFrameIndex(reg, index, stride * size); for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); } } else { for (int i = 0; i < size; i++) { CheckFrameIndex(reg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, reg)); index += stride; } } } } } } } void NativeCodeBasicBlock::LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp])); uint32 flags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) flags |= NCIF_VOLATILE; for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++) { if (i != 0) mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp])); uint32 flags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) flags |= NCIF_VOLATILE; for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++) { if (i != 0) mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); if (wins->mSrc[0].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags)); } } 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 = rins->mSrc[0].mIntConst; int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS; LinkerObject* rlobject = nullptr; int rstride = rins->mSrc[0].mStride; uint32 rflags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) rflags |= NCIF_VOLATILE; switch (rins->mSrc[0].mMemory) { case IM_PARAM: rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset; break; case IM_LOCAL: rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset; break; case IM_PROCEDURE: case IM_GLOBAL: rmode = ASMIM_ABSOLUTE; rlobject = rins->mSrc[0].mLinkerObject; rindex = rins->mSrc[0].mIntConst; break; case IM_FRAME: rindex = 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 = rins->mSrc[0].mIntConst; break; case IM_FPARAM: case IM_FFRAME: rmode = ASMIM_ZERO_PAGE; rareg = BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst; break; } AsmInsMode wmode = ASMIM_INDIRECT_Y; int windex = wins->mSrc[1].mIntConst; int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS; LinkerObject* wlobject = nullptr; int wstride = wins->mSrc[1].mStride; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; switch (wins->mSrc[1].mMemory) { case IM_PARAM: windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset; break; case IM_LOCAL: windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset; break; case IM_PROCEDURE: case IM_GLOBAL: wmode = ASMIM_ABSOLUTE; wlobject = wins->mSrc[1].mLinkerObject; windex = wins->mSrc[1].mIntConst; break; case IM_FRAME: windex = 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 = wins->mSrc[1].mIntConst; break; case IM_FPARAM: case IM_FFRAME: wmode = ASMIM_ZERO_PAGE; wareg = BC_REG_FPARAMS + wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst; break; } for (int i = 0; i < size; i++) { if (rmode == ASMIM_INDIRECT_Y) CheckFrameIndex(rareg, rindex, 1, BC_REG_ADDR); if (wmode == ASMIM_INDIRECT_Y) CheckFrameIndex(wareg, windex, 1, BC_REG_ACCU); if (rmode == ASMIM_INDIRECT_Y) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rindex)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, rareg, nullptr, rflags)); } else if (rmode == ASMIM_ZERO_PAGE) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, rareg + i)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, rindex, rlobject, rflags)); if (wmode == ASMIM_INDIRECT_Y) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, windex)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, wareg, nullptr, wflags)); } else if (wmode == ASMIM_ZERO_PAGE) mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wareg + i)); else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, windex, wlobject, wflags)); rindex += rstride; windex += wstride; } } void NativeCodeBasicBlock::LoadStoreValue(InterCodeProcedure* proc, const InterInstruction * rins, const InterInstruction * wins) { uint32 rflags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) rflags |= NCIF_VOLATILE; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (rins->mDst.mType == IT_FLOAT) { } else if (rins->mDst.mType == IT_POINTER) { } else { if (InterTypeSize[wins->mSrc[0].mType] == 1) { if (rins->mSrc[0].mTemp < 0) { if (rins->mSrc[0].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, rins->mSrc[0].mLinkerObject, rflags)); } else if (rins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, nullptr, rflags)); } else if (rins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(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 = 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(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(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 = rins->mSrc[0].mIntConst; CheckFrameIndex(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); } } if (wins->mSrc[1].mTemp < 0) { if (wins->mSrc[1].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, wins->mSrc[1].mIntConst, wins->mSrc[1].mLinkerObject, wflags)); } else if (wins->mSrc[1].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(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(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 = 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(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, areg)); } else if (wins->mSrc[1].mMemory == IM_FRAME) { int index = wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(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 = wins->mSrc[1].mIntConst; CheckFrameIndex(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(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) { int size = InterTypeSize[wins->mSrc[0].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(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(ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp])); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp])); } mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp])); if (!wins->mSrc[0].mFinal) mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i)); } return true; } else return false; } bool NativeCodeBasicBlock::LoadUnopStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, const InterInstruction* wins) { int size = InterTypeSize[wins->mSrc[0].mType]; 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(ASMIT_SEC)); imm = 0x00; at = ASMIT_SBC; break; case IA_NOT: imm = 0xff; at = ASMIT_EOR; break; default: return false; } int rindex = 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 + rins->mSrc[0].mIntConst; break; default: return false; } int windex = 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 + wins->mSrc[1].mIntConst; break; default: return false; } uint32 rflags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) rflags |= NCIF_VOLATILE; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (ram == ASMIM_INDIRECT_Y) CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR); if (wam == ASMIM_INDIRECT_Y) CheckFrameIndex(wareg, windex, size, BC_REG_ACCU); for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, imm)); if (ram == ASMIM_INDIRECT_Y) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i)); mIns.Push(NativeCodeInstruction(at, ram, rareg)); } else mIns.Push(NativeCodeInstruction(at, ram, rareg + i)); if (!sfinal) mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_IMMEDIATE, windex + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, wam, wareg)); } else mIns.Push(NativeCodeInstruction(ASMIT_STA, wam, wareg + i)); } return true; } bool NativeCodeBasicBlock::LoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, int oindex, const InterInstruction* wins) { int size = InterTypeSize[wins->mSrc[0].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 = 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 + rins->mSrc[0].mIntConst; break; default: return false; } int windex = 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 + wins->mSrc[1].mIntConst; break; default: return false; } if (rstride * size >= 256 || wstride * size >= 256) return false; uint32 rflags = NCIF_LOWER | NCIF_UPPER; if (rins->mVolatile) rflags |= NCIF_VOLATILE; uint32 wflags = NCIF_LOWER | NCIF_UPPER; if (wins->mVolatile) wflags |= NCIF_VOLATILE; if (ram == ASMIM_INDIRECT_Y && wam == ASMIM_INDIRECT_Y && rareg == wareg && rindex == windex) { CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR); windex = rindex; wareg = rareg; } else { if (ram == ASMIM_INDIRECT_Y) CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR); if (wam == ASMIM_INDIRECT_Y) CheckFrameIndex(wareg, windex, size, BC_REG_ACCU); } switch (oins->mOperator) { case IA_ADD: mIns.Push(NativeCodeInstruction(ASMIT_CLC)); break; case IA_SUB: mIns.Push(NativeCodeInstruction(ASMIT_SEC)); break; } for (int i = 0; i < size; i++) { if (reverse) { if (am == ASMIM_IMPLIED) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMPLIED)); else if (am == ASMIM_IMMEDIATE) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i)); if (ram == ASMIM_INDIRECT_Y) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride)); mIns.Push(NativeCodeInstruction(at, ram, rareg)); } else mIns.Push(NativeCodeInstruction(at, ram, rareg + i)); } else { if (ram == ASMIM_INDIRECT_Y) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ram, rareg)); } else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ram, rareg + i)); if (am == ASMIM_IMPLIED) mIns.Push(NativeCodeInstruction(at, ASMIM_IMPLIED)); else if (am == ASMIM_IMMEDIATE) mIns.Push(NativeCodeInstruction(at, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(at, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i)); } if (!sfinal) mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_IMMEDIATE, windex + i * wstride)); mIns.Push(NativeCodeInstruction(ASMIT_STA, wam, wareg)); } else mIns.Push(NativeCodeInstruction(ASMIT_STA, wam, wareg + i)); } return true; } void NativeCodeBasicBlock::LoadValueToReg(InterCodeProcedure* proc, const InterInstruction * ins, int reg, const NativeCodeInstruction* ainsl, const NativeCodeInstruction* ainsh) { uint32 flags = NCIF_LOWER | NCIF_UPPER; if (ins->mVolatile) flags |= NCIF_VOLATILE; if (ins->mDst.mType == IT_FLOAT) { int stride = ins->mSrc[0].mStride; if (ins->mSrc[0].mTemp < 0) { if (ins->mSrc[0].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM) { int index = 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(areg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[0].mIntConst; int stride = ins->mSrc[0].mStride; if (stride * 4 <= 256) { CheckFrameIndex(areg, index, stride * 4); for (int i = 0; i < 4; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + i)); } } else { for (int i = 0; i < 4; i++) { CheckFrameIndex(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + i)); index += stride; } } } } } else if (ins->mDst.mType == IT_POINTER) { int stride = ins->mSrc[0].mStride; if (ins->mSrc[0].mTemp < 0) { if (ins->mSrc[0].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, ins->mSrc[0].mLinkerObject, flags)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, nullptr, flags)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + stride)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM) { int index = 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(areg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[0].mIntConst; CheckFrameIndex(areg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } if (reg == areg) mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y)); else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); if (reg == areg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags)); } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); } else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM) { int index = 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(areg, index, 1); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); } if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); if (InterTypeSize[ins->mDst.mType] > 1) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM) { int index = 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(areg, index, 2); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); if (ainsh) mIns.Push(*ainsh); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3)); } else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM) { int index = 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(areg, index, 4); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg)); mIns.Push(NativeCodeInstruction(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 = ins->mSrc[0].mIntConst; int stride = ins->mSrc[0].mStride; int size = InterTypeSize[ins->mDst.mType]; bool accu = false; if (size * stride <= 256) { CheckFrameIndex(areg, index, size * stride); accu = reg == areg; for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags)); if (i == 0) { if (ainsl) { if (ainsl->mType == ASMIT_ADC) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); else if (ainsl->mType == ASMIT_SBC) mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(*ainsl); } } else if (ainsh) mIns.Push(*ainsh); if (accu) mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i)); else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + i)); } } else { assert(ainsl == nullptr && ainsh == nullptr); for (int i = 0; i < size; i++) { CheckFrameIndex(areg, index, i * stride); if (reg == areg) accu = true; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags)); if (accu) mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i)); else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + i)); index += stride; } } if (accu) { for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + i)); } } } } } } void NativeCodeBasicBlock::LoadValue(InterCodeProcedure* proc, const InterInstruction * ins) { LoadValueToReg(proc, ins, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], nullptr, nullptr); } NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc) { int size = ins->mConst.mOperandSize; int msize = 4, dstride = ins->mSrc[1].mStride, sstride = ins->mSrc[0].mStride; uint32 flags = NCIF_LOWER | NCIF_UPPER; if (ins->mVolatile) flags |= NCIF_VOLATILE; if (sstride > 1 || dstride > 1) msize = 32; else if (nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) msize = 8; else if (nproc->mGenerator->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 = 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(areg, index, size, BC_REG_ADDR); if (size <= msize) { for (int i = 0; i < size; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags)); } return this; } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - index, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_IMMEDIATE, (index + size) & 255)); lblock->Close(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(ASMIT_LDY, ASMIM_IMMEDIATE, step)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); lblock->Close(lblock, block, ASMIT_BNE); return block; } else if (size < 1024 && !(size & 3)) { int step = size >> 2; mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, step)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 2 * step - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 2 * step - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 3 * step - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 3 * step - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); lblock->Close(lblock, block, ASMIT_BNE); return block; } } mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); this->Close(lblock, nullptr, ASMIT_JMP); while (offset + 255 < size) { lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags)); offset += 256; } lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); lblock->Close(lblock, block, ASMIT_BNE); size &= 255; } if (size <= msize) { for (int i = 0; i < size; i++) { block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags)); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_IMMEDIATE, size)); block->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset - 1, ins->mSrc[0].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset - 1, ins->mSrc[1].mLinkerObject, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); block = eblock; } return block; } } #endif int sreg, dreg; if (ins->mSrc[0].mTemp < 0) { if (ins->mSrc[0].mMemory == IM_GLOBAL) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); sreg = BC_REG_ACCU; } else if (ins->mSrc[0].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); sreg = BC_REG_ACCU; } else if (ins->mSrc[0].mMemory == IM_FPARAM) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(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 = 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(sreg, index, 256, BC_REG_ACCU); } } else if (ins->mSrc[0].mIntConst != 0) { int index = ins->mSrc[0].mIntConst; mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1)); dreg = BC_REG_ADDR; } else if (ins->mSrc[1].mMemory == IM_ABSOLUTE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(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 = 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(dreg, index, 256, BC_REG_ADDR); } else if (ins->mSrc[1].mMemory == IM_FRAME) { int index = ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2; mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1)); dreg = BC_REG_ADDR; } } else if (ins->mSrc[1].mIntConst != 0) { int index = ins->mSrc[1].mIntConst; mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_IMMEDIATE, i * sstride)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, i* dstride)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg)); } return this; } else { NativeCodeBasicBlock* block = this; if (size >= 256) { block = nproc->AllocateBlock(); NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* lblock2 = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); if (size >= 512) mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, size >> 8)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); lblock->Close(lblock, lblock2, ASMIT_BNE); lblock2->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, sreg + 1)); lblock2->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1)); if (size >= 512) { lblock2->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock2->Close(lblock, block, ASMIT_BNE); } else lblock2->Close(block, nullptr, ASMIT_JMP); size &= 0xff; } if (size > 0) { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (size < 128) { block->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, size - 1)); block->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BPL); } else if (size <= 256) { block->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, size - 1)); block->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags)); } block = eblock; } return block; } } 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(ASMIT_LDY, ASMIM_IMMEDIATE, 0xff)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg)); lblock->Close(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::ShiftRegisterLeft(InterCodeProcedure* proc, int reg, int shift) { if (shift == 0) { } else if (shift == 1) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, reg + 1)); } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); for (int i = 8; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else if (shift >= 5) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); for (int i = shift; i < 8; i++) { mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); for (int i = 0; i < shift; i++) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } } void NativeCodeBasicBlock::ShiftRegisterLeftFromByte(InterCodeProcedure* proc, int reg, int shift, int max) { if (shift == 0) { } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); for (int i = 8; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else if (shift == 1) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); if (max >= 128) mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (shift >= 5 && shift < 8 && (max << shift) >= 512) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); for (int i = shift; i < 7; i++) mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TAX)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_TXA)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, (0xff >> (8 - shift)) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } else if (shift == 4 && max >= 128) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xf0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); while (shift > 0 && max < 256) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); shift--; max *= 2; } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); if (max > 255) mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); while (shift > 0) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); shift--; } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); } } void NativeCodeBasicBlock::ShiftRegisterLeftByte(InterCodeProcedure* proc, int reg, int shift) { if (shift == 0) { } else if (shift == 1) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg)); } else if (shift >= 6) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); for (int i = shift; i < 8; i++) mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); for (int i = 0; i < shift; i++) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(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; } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_ROR)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_LSR)); mIns.Push(NativeCodeInstruction(ASMIT_ROR)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_SEC)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, mul)); mIns.Push(NativeCodeInstruction(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(ASMIT_SEC)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); break; case 0xfffe: // -2 mIns.Push(NativeCodeInstruction(ASMIT_SEC)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); break; case 0xfffd: // -3 mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); break; case 0xfffc: // -4 mIns.Push(NativeCodeInstruction(ASMIT_SEC)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDX, ASMIM_ZERO_PAGE, dreg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp])); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, ins->mSrc[index].mRange.mMaxValue + 1, false))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg)); if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, ins->mSrc[index].mRange.mMaxValue + 1, true))); mIns.Push(NativeCodeInstruction(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, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else if (ins->mSrc[index].IsUByte()) ShiftRegisterLeftFromByte(proc, dreg, lshift, ins->mSrc[index].mRange.mMaxValue); else ShiftRegisterLeft(proc, 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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(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, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else if (ins->mSrc[index].IsUByte()) ShiftRegisterLeftFromByte(proc, dreg, lshift, ins->mSrc[index].mRange.mMaxValue); else ShiftRegisterLeft(proc, dreg, lshift); return dreg; case 3: if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 85) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } if (ins->mDst.IsUByte()) { ShiftRegisterLeftByte(proc, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else ShiftRegisterLeft(proc, dreg, lshift); return dreg; case 5: if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 51) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } if (ins->mDst.IsUByte()) { ShiftRegisterLeftByte(proc, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else ShiftRegisterLeft(proc, dreg, lshift); return dreg; case 7: if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 64) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } else if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 128) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); if (ins->mDst.IsUByte()) { ShiftRegisterLeftByte(proc, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else ShiftRegisterLeft(proc, dreg, lshift); return dreg; case 9: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); if (ins->mDst.IsUByte()) { ShiftRegisterLeftByte(proc, dreg, lshift); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else ShiftRegisterLeft(proc, dreg, lshift); return dreg; #if 1 case 25: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TAY, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); ShiftRegisterLeft(proc, dreg, lshift); return dreg; #endif #endif default: if (mul & 0xff00) { if (ins->mSrc[index].IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, mul & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, mul >> 8)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A)); } else { if (dreg != BC_REG_ACCU) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, mul & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, mul >> 8)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); } } else { if (dreg != BC_REG_ACCU) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, mul)); // mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A)); } return BC_REG_WORK + 2; } } static bool IsPowerOf2(unsigned n) { return (n & (n - 1)) == 0; } static int Binlog(unsigned n) { int k = -1; while (n) { n >>= 1; k++; } return k; } void NativeCodeBasicBlock::AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins) { mIns.Push(NativeCodeInstruction(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(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_ROR)); } mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->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; } } int sreg0 = ins->mSrc[sop0].mTemp < 0 ? -1 : BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop0].mTemp]; if (ins->mSrc[sop1].mTemp < 0) { union { float f; unsigned int v; } cc; if (ins->mOperator == IA_SUB && flipop) { changedSign = true; cc.f = -ins->mSrc[sop1].mFloatConst; } else cc.f = ins->mSrc[sop1].mFloatConst; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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 = -ins->mSrc[sop0].mFloatConst; } else cc.f = ins->mSrc[sop0].mFloatConst; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitt"))); mIns.Push(NativeCodeInstruction(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(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, sreg0)); #if 0 mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg0 + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg0 + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg0 + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg0 + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); #endif } switch (ins->mOperator) { case IA_ADD: { NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); } break; case IA_SUB: { if (!changedSign) { if (flipop) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); } } NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub"))); mIns.Push(NativeCodeInstruction(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(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(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); } break; } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } else if (ins->mDst.mType == IT_INT32) { switch (ins->mOperator) { case IA_ADD: case IA_SUB: case IA_OR: case IA_AND: case IA_XOR: { if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr); if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr); AsmInsType atype; switch (ins->mOperator) { case IA_ADD: mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); atype = ASMIT_ADC; break; case IA_SUB: mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + i)); if (ins->mSrc[0].mTemp < 0) mIns.Push(NativeCodeInstruction(atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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(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(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(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(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); reg = BC_REG_WORK + 4; } break; } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); sreg = treg; shift -= 24; } else if (shift >= 16) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); sreg = treg; shift -= 16; } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); sreg = treg; shift -= 8; } if (shift == 0) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } } else if (shift == 1) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3)); } } else if (shift == 2) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3)); } mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3)); } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); } else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, shift)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); return eblock; } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x1f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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 nregs = 4; if (shift >= 24) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 24; nregs = 1; } else if (shift >= 16) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 16; nregs = 2; } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 8; nregs = 3; } if (shift == 0) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } } else if (shift == 1) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); } } else if (shift == 2) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); } mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, shift)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); for(int i=nregs -1; i>0 ; i--) lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1)); // lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); // lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1)); return eblock; } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x1f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 24; nbytes = 1; } else if (shift >= 16) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 16; nbytes = 2; } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 8; nbytes = 3; } if (shift == 0) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } } else if (shift == 1) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + nbytes - 1)); for(int i=nbytes - 2; i >=0; i--) mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i)); } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); } else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1)); int lcost = 8 + 2 * (nbytes - 1); int ucost = shift * (1 + 2 * nbytes); if ((nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost || !(nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost) { mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, shift)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); for (int i = nbytes - 2; i >= 0; i--) lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1)); return eblock; } else { for (int si = 0; si < shift; si++) { mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); for (int i = nbytes - 2; i >= 0; i--) mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1)); } } } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x1f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else { NativeCodeBasicBlock* iblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); this->Close(eblock, iblock, ASMIT_BNE); iblock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, treg + 1)); iblock->Close(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(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(atype, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff); insh = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff); if (sins0) { if (ins->mDst.IsUByte()) insh = NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0); LoadValueToReg(proc, sins0, treg, &insl, &insh); } else { if (ins->mOperator == IA_ADD) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(insl); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(insh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } } } else if (ins->mSrc[0].mTemp < 0) { insl = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff); insh = NativeCodeInstruction(atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff); if (sins1) { if (ins->mDst.IsUByte()) insh = NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0); LoadValueToReg(proc, sins1, treg, &insl, &insh); } else { if (ins->mOperator == IA_ADD) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(insl); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(insh); mIns.Push(NativeCodeInstruction(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 < 255 && sins1->mSrc[0].mIntConst < 255) { if (ins->mOperator == IA_ADD) mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + 0)); mIns.Push(NativeCodeInstruction(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(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y)); else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + 1)); mIns.Push(NativeCodeInstruction(atype, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins1->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } } else mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } else { insl = NativeCodeInstruction(atype, ASMIM_ZERO_PAGE, treg); insh = NativeCodeInstruction(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(atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]); insh = NativeCodeInstruction(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(atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]); insh = NativeCodeInstruction(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(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { #if 1 if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else #endif { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } } } } } break; case IA_SUB: { NativeCodeInstruction insl, insh; if (InterTypeSize[ins->mDst.mType] == 1 && ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 1 && !sins0 && ins->mSrc[0].mTemp == ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_DEC, ASMIM_ZERO_PAGE, treg)); } else if (ins->mSrc[0].mTemp < 0) { insl = NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff); if (ins->mDst.IsUByte()) insh = NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0); else insh = NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff); if (sins1) LoadValueToReg(proc, sins1, treg, &insl, &insh); else { mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(insl); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(insh); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } } else if (ins->mSrc[1].mTemp < 0) { if (sins0) { LoadValueToReg(proc, sins0, treg, nullptr, nullptr); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { if (ins->mDst.IsUByte()) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, treg + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else { mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { if (ins->mDst.IsUByte()) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } } else { if (sins0) { insl = NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 0); if (ins->mDst.IsUByte()) insh = NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0); else insh = NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 1); LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr); } else { insl = NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]); if (ins->mDst.IsUByte()) insh = NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0); else insh = NativeCodeInstruction(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(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(insl); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (InterTypeSize[ins->mDst.mType] > 1) { if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(insh); mIns.Push(NativeCodeInstruction(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, ins->mSrc[1].mIntConst); } else if (ins->mOperator == IA_MUL && ins->mSrc[0].mTemp < 0) { reg = ShortMultiply(proc, nproc, ins, sins1, 1, 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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } if (sins0) { LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); } else mIns.Push(NativeCodeInstruction(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A)); reg = BC_REG_WORK + 2; } else if (ins->mOperator == IA_MUL && ins->mSrc[1].IsUByte()) { if (sins0) LoadValueToReg(proc, sins0, BC_REG_ACCU, nullptr, nullptr); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } if (sins1) { LoadValueToReg(proc, sins1, BC_REG_WORK, nullptr, nullptr); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); } else mIns.Push(NativeCodeInstruction(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A)); reg = BC_REG_WORK + 2; } else if (ins->mOperator == IA_DIVS && ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 2) { reg = ShortSignedDivide(proc, nproc, ins, sins1, ins->mSrc[0].mIntConst); } else { if (sins1) LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr); else if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(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(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(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(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(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); reg = BC_REG_WORK + 2; } break; } } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_ASL, ASMIM_IMPLIED); NativeCodeInstruction insh(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()) { if (shift == 0) { if (sreg != treg) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } } else if (shift == 1) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); } } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else if (shift > 5) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); for(int i=shift; i<8; i++) mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xff << shift)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg )); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { if (shift == 0) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift == 1) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xc0)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else if (shift == 4 && ins->mSrc[1].IsUByte() && ins->mSrc[1].mRange.mMaxValue >= 128) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xf0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); for (int i = 8; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); } int check = 0xffff; if (ins->mSrc[1].IsUByte()) check = ins->mSrc[1].mRange.mMaxValue; check <<= 1; if (check >= 0x100) mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); for (int i = 1; i < shift; i++) { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); check <<= 1; if (check >= 0x100) mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(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(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift"))); if (l < 8) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 8 + l, frt.mLinkerObject)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (ins->mSrc[1].mTemp < 0) { int size = ins->mSrc[0].mRange.mMaxValue + 1; mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); size = 16; } mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, ins->mSrc[1].mIntConst, size, false))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, ins->mSrc[1].mIntConst, size, true))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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()) { if (shift == 0) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift == 7) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else if (shift == 6) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else #endif { if (shift == 0) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift == 1) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg)); } } else if (shift == 15) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else if (shift == 14) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(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(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (shift >= 5) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, treg)); } mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); for (int i = shift; i < 8; i++) { mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); for (int i = 1; i < shift; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); } mIns.Push(NativeCodeInstruction(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(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift"))); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (ins->mSrc[1].mTemp < 0) { int size = ins->mSrc[0].mRange.mMaxValue + 1; mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); size = 16; } mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, ins->mSrc[1].mIntConst, size, false))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, ins->mSrc[1].mIntConst, size, true))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift == 7) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } else if (shift == 6) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (ins->mSrc[1].IsSByte() && shift != 0 && shift < 5) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { if (shift == 0) { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift == 1) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } else if (shift == 7) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(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(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> (shift - 8))); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> (shift - 8))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1)); } for (int i = 0; i < shift; i++) { mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg)); } mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); mIns.Push(NativeCodeInstruction(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(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift"))); if (l == 15) { mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else if (ins->mSrc[1].mTemp < 0) { int size = ins->mSrc[0].mRange.mMaxValue + 1; mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); size = 16; } mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, ins->mSrc[1].mIntConst, size, false))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); if (ins->mDst.IsUByte()) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, ins->mSrc[1].mIntConst, size, true))); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } else { NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(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(ASMIT_AND, ASMIM_IMMEDIATE, 0x0f)); mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); if (ins->mSrc[1].IsUByte()) { if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { if (ins->mSrc[1].mTemp < 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); } else if (ins->mSrc[1].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, 0x00)); this->Close(lblock, eblock, ASMIT_BNE); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); eblock->mIns.Push(NativeCodeInstruction(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 ? ains->mSrc[1].mIntConst : ains->mSrc[0].mIntConst; val -= 128; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[xins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_CLC)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, val & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (val >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 1)); } 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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); } else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); if (ins->mOperator == IA_NEG) mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); else mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x7f)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); break; case IA_FLOOR: case IA_CEIL: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); NativeCodeGenerator::Runtime& frx(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplita"))); mIns.Push(NativeCodeInstruction(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(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(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_SEC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); if (ins->mDst.mType == IT_INT32) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } break; case IA_NOT: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); if (ins->mDst.mType == IT_INT32) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftoi"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } break; case IA_INT2FLOAT: { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromi"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } break; case IA_FLOAT2UINT: { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftou"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } break; case IA_UINT2FLOAT: { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromu"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } break; case IA_EXT8TO16S: mIns.Push(NativeCodeInstruction(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(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); break; case IA_EXT16TO32S: if (ins->mSrc[0].mTemp != ins->mDst.mTemp) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); } mIns.Push(NativeCodeInstruction(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(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); break; case IA_EXT8TO32S: mIns.Push(NativeCodeInstruction(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(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); } mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(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; 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 = ins->mSrc[ci].mFloatConst; int ti = BC_REG_TMP + proc->mTempOffset[ins->mSrc[vi].mTemp]; if (cc.f == 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0x7f)); mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 2)); mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 0)); if (op == IA_CMPEQ) { Close(trueJump, falseJump, ASMIT_BEQ); } else if (op == IA_CMPNE) { Close(trueJump, falseJump, ASMIT_BNE); } else { NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPLES || op == IA_CMPLEU) Close(trueJump, nblock, ASMIT_BEQ); else Close(falseJump, nblock, ASMIT_BEQ); nblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPGS || op == IA_CMPGU) nblock->Close(trueJump, falseJump, ASMIT_BPL); else nblock->Close(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(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); Close(eblock1, falseJump, ASMIT_BEQ); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2)); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); eblock1->Close(eblock2, falseJump, ASMIT_BEQ); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1)); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); eblock2->Close(eblock3, falseJump, ASMIT_BEQ); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0)); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff)); eblock3->Close(trueJump, falseJump, ASMIT_BEQ); return; } else if (op == IA_CMPNE) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); Close(eblock1, trueJump, ASMIT_BEQ); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2)); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); eblock1->Close(eblock2, trueJump, ASMIT_BEQ); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1)); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); eblock2->Close(eblock3, trueJump, ASMIT_BEQ); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0)); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff)); eblock3->Close(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(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); if (cc.f < 0) Close(trueJump, eblock0, ASMIT_BPL); else Close(falseJump, eblock0, ASMIT_BMI); eblock0->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); eblock0->Close(nblock, eblock1, ASMIT_BNE); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2)); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); eblock1->Close(nblock, eblock2, ASMIT_BNE); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1)); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); eblock2->Close(nblock, eblock3, ASMIT_BNE); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0)); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff)); if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU) eblock3->Close(nblock, trueJump, ASMIT_BNE); else eblock3->Close(nblock, falseJump, ASMIT_BNE); if (cc.f < 0) nblock->Close(trueJump, falseJump, ASMIT_BCC); else nblock->Close(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(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3)); if (cc.f < 0) Close(falseJump, eblock0, ASMIT_BPL); else Close(trueJump, eblock0, ASMIT_BMI); eblock0->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); eblock0->Close(nblock, eblock1, ASMIT_BNE); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2)); eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); eblock1->Close(nblock, eblock2, ASMIT_BNE); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1)); eblock2->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); eblock2->Close(nblock, eblock3, ASMIT_BNE); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0)); eblock3->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff)); if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU) eblock3->Close(nblock, trueJump, ASMIT_BNE); else eblock3->Close(nblock, falseJump, ASMIT_BNE); if (cc.f < 0) nblock->Close(trueJump, falseJump, ASMIT_BCS); else nblock->Close(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 = ins->mSrc[li].mFloatConst; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); } if (ins->mSrc[ri].mTemp < 0) { union { float f; unsigned int v; } cc; cc.f = ins->mSrc[ri].mFloatConst; mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); } NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fcmp"))); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_JSRFLAGS)); switch (op) { case IA_CMPEQ: Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: Close(falseJump, trueJump, ASMIT_BEQ); break; case IA_CMPLU: case IA_CMPLS: case IA_CMPGU: case IA_CMPGS: Close(trueJump, falseJump, ASMIT_BMI); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: Close(falseJump, trueJump, ASMIT_BMI); break; } } else if (ins->mSrc[0].mType == IT_INT32) { int li = 1, ri = 0; if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS) { li = 0; ri = 1; } if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS) { if (ins->mSrc[ri].mTemp >= 0) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK)); } if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 24) & 0xff) ^ 0x80)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); } if (ins->mSrc[ri].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ((ins->mSrc[ri].mIntConst >> 24) & 0xff) ^ 0x80)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK)); } else { if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 24) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3)); if (ins->mSrc[ri].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 24) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3)); } NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); this->Close(nblock, eblock3, ASMIT_BNE); if (ins->mSrc[li].mTemp < 0) eblock3->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 16) & 0xff)); else eblock3->mIns.Push(NativeCodeInstruction(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(ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 16) & 0xff)); else eblock3->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2)); eblock3->Close(nblock, eblock2, ASMIT_BNE); if (ins->mSrc[li].mTemp < 0) eblock2->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff)); else eblock2->mIns.Push(NativeCodeInstruction(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(ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 8) & 0xff)); else eblock2->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); eblock2->Close(nblock, eblock1, ASMIT_BNE); if (ins->mSrc[li].mTemp < 0) eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff)); else eblock1->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp])); if (ins->mSrc[ri].mTemp < 0) eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[ri].mIntConst & 0xff)); else eblock1->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); switch (op) { case IA_CMPEQ: nblock->Close(falseJump, nullptr, ASMIT_JMP); eblock1->Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: nblock->Close(trueJump, nullptr, ASMIT_JMP); eblock1->Close(falseJump, trueJump, ASMIT_BEQ); break; case IA_CMPLU: case IA_CMPLS: case IA_CMPGU: case IA_CMPGS: eblock1->Close(nblock, nullptr, ASMIT_JMP); nblock->Close(trueJump, falseJump, ASMIT_BCC); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: eblock1->Close(nblock, nullptr, ASMIT_JMP); nblock->Close(falseJump, trueJump, ASMIT_BCC); break; } } else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0) { int rt = ins->mSrc[1].mTemp; if (rt < 0) { rt = ins->mSrc[0].mTemp; switch (op) { case IA_CMPLEU: op = IA_CMPGEU; break; case IA_CMPGEU: op = IA_CMPLEU; break; case IA_CMPLU: op = IA_CMPGU; break; case IA_CMPGU: op = IA_CMPLU; break; case IA_CMPLES: op = IA_CMPGES; break; case IA_CMPGES: op = IA_CMPLES; break; case IA_CMPLS: op = IA_CMPGS; break; case IA_CMPGS: op = IA_CMPLS; break; } } switch (op) { case IA_CMPEQ: case IA_CMPLEU: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); if (InterTypeSize[ins->mSrc[0].mType] > 1) mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: case IA_CMPGU: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); if (InterTypeSize[ins->mSrc[0].mType] > 1) mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(trueJump, falseJump, ASMIT_BNE); break; case IA_CMPGEU: this->Close(trueJump, nullptr, ASMIT_JMP); break; case IA_CMPLU: this->Close(falseJump, nullptr, ASMIT_JMP); break; case IA_CMPGES: if (InterTypeSize[ins->mSrc[0].mType] == 1) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt])); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(trueJump, falseJump, ASMIT_BPL); break; case IA_CMPLS: if (InterTypeSize[ins->mSrc[0].mType] == 1) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt])); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(trueJump, falseJump, ASMIT_BMI); break; case IA_CMPGS: { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (InterTypeSize[ins->mSrc[0].mType] == 1) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt])); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(eblock, falseJump, ASMIT_BPL); if (InterTypeSize[ins->mSrc[0].mType] != 1) eblock->mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(trueJump, falseJump, ASMIT_BNE); break; } case IA_CMPLES: { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); if (InterTypeSize[ins->mSrc[0].mType] == 1) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt])); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); this->Close(eblock, trueJump, ASMIT_BPL); if (InterTypeSize[ins->mSrc[0].mType] != 1) eblock->mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(trueJump, falseJump, ASMIT_BEQ); break; } } } else if (InterTypeSize[ins->mSrc[0].mType] == 1) { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); int li = 1, ri = 0; if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS) { li = 0; ri = 1; } int iconst = 0; bool rconst = false; if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPGES || op == IA_CMPLS) && int16(ins->mSrc[li].mIntConst) > - 128) { iconst = ins->mSrc[li].mIntConst - 1; rconst = true; li = ri; ri = 1 - li; NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t; } else if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPLES || op == IA_CMPGS) && int16(ins->mSrc[li].mIntConst) < 127) { iconst = 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 = ins->mSrc[ri].mIntConst; rconst = true; } if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS) { if (!rconst) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK)); } if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst & 0xff) ^ 0x80)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); } if (rconst) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (iconst & 0xff) ^ 0x80)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK)); } else { if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp])); if (rconst) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); } switch (op) { case IA_CMPEQ: this->Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: this->Close(falseJump, trueJump, ASMIT_BEQ); break; case IA_CMPLU: case IA_CMPLS: case IA_CMPGU: case IA_CMPGS: this->Close(trueJump, falseJump, ASMIT_BCC); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: this->Close(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 = ins->mSrc[0].mIntConst; bool u8 = ins->mSrc[1].IsUByte(); if (rt < 0) { rt = ins->mSrc[0].mTemp; u8 = ins->mSrc[0].IsUByte();; ival = 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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1)); switch (op) { case IA_CMPEQ: { this->Close(eblock, falseJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(trueJump, falseJump, ASMIT_BEQ); break; } case IA_CMPNE: { this->Close(eblock, trueJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(falseJump, trueJump, ASMIT_BEQ); break; } case IA_CMPLEU: { this->Close(eblock, falseJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ival)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(falseJump, trueJump, ASMIT_BCC); break; } case IA_CMPGEU: { this->Close(eblock, trueJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(falseJump, trueJump, ASMIT_BCC); break; } case IA_CMPLU: { this->Close(eblock, falseJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(trueJump, falseJump, ASMIT_BCC); break; } case IA_CMPGU: { this->Close(eblock, trueJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ival)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(trueJump, falseJump, ASMIT_BCC); break; } case IA_CMPLES: { NativeCodeBasicBlock* sblock = nproc->AllocateBlock(); this->Close(sblock, trueJump, ASMIT_BPL); sblock->Close(eblock, falseJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ival)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(falseJump, trueJump, ASMIT_BCC); break; } case IA_CMPGES: { NativeCodeBasicBlock* sblock = nproc->AllocateBlock(); this->Close(sblock, falseJump, ASMIT_BPL); sblock->Close(eblock, trueJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(falseJump, trueJump, ASMIT_BCC); break; } case IA_CMPLS: { NativeCodeBasicBlock* sblock = nproc->AllocateBlock(); this->Close(sblock, trueJump, ASMIT_BPL); sblock->Close(eblock, falseJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ival)); eblock->Close(trueJump, falseJump, ASMIT_BCC); break; } case IA_CMPGS: { NativeCodeBasicBlock* sblock = nproc->AllocateBlock(); this->Close(sblock, falseJump, ASMIT_BPL); sblock->Close(eblock, trueJump, ASMIT_BEQ); eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ival)); eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0)); eblock->Close(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); this->Close(falseJump, trueJump, ASMIT_BEQ); } #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 = ins->mSrc[ri].mIntConst; rconst = true; } if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp])); if (rconst) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); switch (op) { case IA_CMPEQ: this->Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: this->Close(falseJump, trueJump, ASMIT_BEQ); break; case IA_CMPLU: case IA_CMPLS: case IA_CMPGU: case IA_CMPGS: this->Close(trueJump, falseJump, ASMIT_BCC); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: this->Close(falseJump, trueJump, ASMIT_BCC); break; } } else { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); NativeCodeBasicBlock* cblock = this; 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 = 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 = 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 = 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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); this->Close(falseJump, cblock, ASMIT_BMI); cblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); cblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); } else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES)) { cblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); this->Close(falseJump, cblock, ASMIT_BMI); cblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); cblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); } else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGS || op == IA_CMPLS)) { cblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); this->Close(trueJump, cblock, ASMIT_BMI); cblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); cblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); } else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[li].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES)) { cblock = nproc->AllocateBlock(); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); this->Close(trueJump, cblock, ASMIT_BMI); cblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); cblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); } else { if (!rconst) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK)); } if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 8) & 0xff) ^ 0x80)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); } if (rconst) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ((iconst >> 8) & 0xff) ^ 0x80)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK)); } } else { if (ins->mSrc[li].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1)); if (rconst) mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (iconst >> 8) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1)); } cblock->Close(nblock, eblock, ASMIT_BNE); if (ins->mSrc[li].mTemp < 0) eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff)); else eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp])); if (rconst) eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff)); else eblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp])); switch (op) { case IA_CMPEQ: nblock->Close(falseJump, nullptr, ASMIT_JMP); eblock->Close(trueJump, falseJump, ASMIT_BEQ); break; case IA_CMPNE: nblock->Close(trueJump, nullptr, ASMIT_JMP); eblock->Close(falseJump, trueJump, ASMIT_BEQ); break; case IA_CMPLU: case IA_CMPLS: case IA_CMPGU: case IA_CMPGS: eblock->Close(nblock, nullptr, ASMIT_JMP); nblock->Close(trueJump, falseJump, ASMIT_BCC); break; case IA_CMPLEU: case IA_CMPLES: case IA_CMPGEU: case IA_CMPGES: eblock->Close(nblock, nullptr, ASMIT_JMP); nblock->Close(falseJump, trueJump, ASMIT_BCC); break; } } } void NativeCodeBasicBlock::LoadStoreOpAbsolute2D(InterCodeProcedure* proc, const InterInstruction* lins1, const InterInstruction* lins2, const InterInstruction* mins) { mIns.Push(NativeCodeInstruction(ASMIT_CLC)); if (lins1->mSrc[0].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, lins1->mSrc[0].mIntConst)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins1->mSrc[0].mTemp])); if (lins2->mSrc[0].mTemp < 0) mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, lins2->mSrc[0].mIntConst)); else mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins2->mSrc[0].mTemp])); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, (mins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); else mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[mins->mSrc[0].mTemp] + i)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ABSOLUTE_Y, lins1->mSrc[1].mIntConst + mins->mSrc[0].mIntConst + i, lins1->mSrc[1].mLinkerObject)); mIns.Push(NativeCodeInstruction(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(ASMIT_ADC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff); NativeCodeInstruction ainsh(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(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]); NativeCodeInstruction ainsh(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(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_CLC)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_UPPER)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER)); #if 1 if (ins->mSrc[0].IsUByte()) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else if ((ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].IsUnsigned()) && (ins->mSrc[1].mLinkerObject->mSize < 256 || (addrvalid && ins->mSrc[1].mLinkerObject->mSize <= 256))) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else #endif mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff)); #if 1 if (ins->mSrc[0].IsUByte()) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else #endif mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(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(iop, ASMIM_IMMEDIATE, 0)); else #endif mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); if (ins->mSrc[0].IsUByte()) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(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 = 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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index)); mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, areg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, areg)); mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1)); if (ins->mSrc[0].IsUByte()) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); if (index != 0) { mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1)); } } } } else { if (ins->mSrc[0].mTemp >= 0 || ins->mSrc[0].mIntConst != 0) mIns.Push(NativeCodeInstruction(isub ? ASMIT_SEC : ASMIT_CLC, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(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(iop, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); } else mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg])); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); mIns.Push(NativeCodeInstruction(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(ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); } else if (ins->mSrc[0].IsUByte()) mIns.Push(NativeCodeInstruction(iop, ASMIM_IMMEDIATE, 0)); else mIns.Push(NativeCodeInstruction(iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER); NativeCodeInstruction hins(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER); mIns.Push(lins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mIns.Push(hins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } else { NativeCodeInstruction lins(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff); NativeCodeInstruction hins(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff); mIns.Push(lins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mIns.Push(hins); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); } NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec"))); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); if (InterTypeSize[ins->mDst.mType] > 1) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } if (InterTypeSize[ins->mDst.mType] > 2) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } } } } NativeCodeInstruction NativeCodeBasicBlock::DecodeNative(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 flags |= NCIF_VOLATILE; break; case ASMIM_ZERO_PAGE: case ASMIM_ZERO_PAGE_X: case ASMIM_ZERO_PAGE_Y: case ASMIM_INDIRECT_X: case ASMIM_INDIRECT_Y: lref = lobj->FindReference(offset); address = lobj->mData[offset++]; if (lref && (lref->mFlags & LREF_TEMPORARY)) address += lobj->mTemporaries[lref->mRefOffset]; else if (address >= BC_REG_TMP) flags |= NCIF_VOLATILE; break; case ASMIM_RELATIVE: address = lobj->mData[offset++]; address += offset; break; case ASMIM_IMMEDIATE: lref = lobj->FindReference(offset); address = lobj->mData[offset++]; if (lref) { 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(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 + 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(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->mModule->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER)) { GrowingArray tains(NativeCodeInstruction(ASMIT_INV, ASMIM_IMPLIED)); uint32 uflags = 0; bool simple = true; int i = 0; while (i < ins->mSrc[0].mLinkerObject->mSize) { NativeCodeInstruction dins = DecodeNative(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; } 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) simple = false; if (dins.mFlags & NCIF_VOLATILE) simple = false; if (dins.mMode == ASMIM_ZERO_PAGE && dins.mAddress >= BC_REG_WORK && dins.mAddress < BC_REG_WORK + 8) uflags |= NICF_USE_WORKREGS; if (dins.ChangesAccu()) uflags |= NCIF_USE_CPU_REG_A; if (dins.ChangesXReg()) uflags |= NCIF_USE_CPU_REG_X; if (dins.ChangesYReg()) uflags |= NCIF_USE_CPU_REG_Y; tains.Push(dins); } if (simple) { for (int i = 0; i + 1 < tains.Size(); i++) mIns.Push(tains[i]); } else mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); } else mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags)); lf = ins->mSrc[0].mLinkerObject->mFlags; } else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec"))); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3)); } else { if (!(lf & LOBJF_RET_REG_A)) mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(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(ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); else { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } } if (InterTypeSize[ins->mDst.mType] > 2) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mIns.Push(NativeCodeInstruction(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 = NumberSet(NUM_REGS); mLocalProvidedRegs = NumberSet(NUM_REGS); mEntryRequiredRegs = NumberSet(NUM_REGS); mEntryProvidedRegs = NumberSet(NUM_REGS); mExitRequiredRegs = NumberSet(NUM_REGS); mExitProvidedRegs = NumberSet(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; NumberSet newRequiredRegs(mExitRequiredRegs); if (mTrueJump && mTrueJump->BuildGlobalRequiredRegSet(newRequiredRegs)) revisit = true; if (mFalseJump && mFalseJump->BuildGlobalRequiredRegSet(newRequiredRegs)) revisit = true; if (!(newRequiredRegs <= mExitRequiredRegs)) { revisit = true; mExitRequiredRegs = newRequiredRegs; newRequiredRegs -= mLocalProvidedRegs; mEntryRequiredRegs |= newRequiredRegs; } } 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) { if (from == this) return; else if (!mDominator) mDominator = from; else if (from == mDominator) return; else { GrowingArray< NativeCodeBasicBlock * > d1(nullptr), d2(nullptr); NativeCodeBasicBlock* b = mDominator; while (b) { d1.Push(b); b = b->mDominator; } b = from; while (b) { d2.Push(b); b = b->mDominator; } b = nullptr; while (d1.Size() > 0 && d2.Size() > 0 && d1.Last() == d2.Last()) { b = d1.Pop(); d2.Pop(); } if (mDominator == b) return; mDominator = b; } if (mTrueJump) mTrueJump->BuildDominatorTree(this); if (mFalseJump) mFalseJump->BuildDominatorTree(this); } 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) { 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 (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; } 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; } while (mTrueJump && mTrueJump->mIns.Size() == 0 && !mTrueJump->mFalseJump && !mTrueJump->mLocked && mTrueJump != this && mTrueJump->mTrueJump != mTrueJump) { mTrueJump->mNumEntries--; mTrueJump = mTrueJump->mTrueJump; mTrueJump->mNumEntries++; changed = true; } while (mFalseJump && mFalseJump->mTrueJump && mFalseJump->mIns.Size() == 0 && !mFalseJump->mFalseJump && !mFalseJump->mLocked && mFalseJump != this && mFalseJump->mTrueJump != mFalseJump) { mFalseJump->mNumEntries--; mFalseJump = mFalseJump->mTrueJump; mFalseJump->mNumEntries++; changed = true; } if (mTrueJump && mTrueJump == mFalseJump) { mBranch = ASMIT_JMP; mFalseJump = nullptr; changed = true; } } if (mTrueJump) mTrueJump->MergeBasicBlocks(); if (mFalseJump) mFalseJump->MergeBasicBlocks(); 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); if (mTrueJump) mTrueJump->BuildEntryDataSet(mNDataSet); if (mFalseJump) mFalseJump->BuildEntryDataSet(mNDataSet); } } bool NativeCodeBasicBlock::ApplyEntryDataSet(void) { bool changed = false; if (!mVisited) { mVisited = true; mNDataSet = mEntryRegisterDataSet; for (int i = 0; i < mIns.Size(); i++) { if (mIns[i].ApplySimulation(mNDataSet)) changed = true; mIns[i].Simulate(mNDataSet); } if (mTrueJump && mTrueJump->ApplyEntryDataSet()) changed = true; if (mFalseJump && mFalseJump->ApplyEntryDataSet()) changed = true; } return changed; } void NativeCodeBasicBlock::FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu) { if (!mVisited) { mVisited = true; if (mNumEntries > 1) accu = -1; for (int i = 0; i < mIns.Size(); i++) { if (mIns[i].mMode == ASMIM_ZERO_PAGE) { if (mIns[i].mType == ASMIT_LDA) accu = mIns[i].mAddress; else if (mIns[i].mType == ASMIT_STA) { if (accu < 0 || !statics[accu]) invalid += mIns[i].mAddress; else if (alias[mIns[i].mAddress]) { if (alias[mIns[i].mAddress] != accu) invalid += mIns[i].mAddress; } else { alias[mIns[i].mAddress] = accu; } } else if (mIns[i].ChangesAccu()) accu = -1; else if (mIns[i].ChangesAddress()) invalid += mIns[i].mAddress; } else if (mIns[i].ChangesAccu()) accu = -1; } if (mTrueJump) mTrueJump->FindZeroPageAlias(statics, invalid, alias, accu); if (mFalseJump) mFalseJump->FindZeroPageAlias(statics, invalid, alias, accu); } } void NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global) { 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) && !(mIns[i].mFlags & NCIF_FEXEC)) { 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; global |= lo->mZeroPageSet; } } break; } } if (mTrueJump) mTrueJump->CollectZeroPageSet(locals, global); if (mFalseJump) mFalseJump->CollectZeroPageSet(locals, global); } } void NativeCodeBasicBlock::CollectZeroPageUsage(NumberSet& used, NumberSet &modified, NumberSet& pairs) { if (!mVisited) { mVisited = true; for (int i = 0; i < mIns.Size(); i++) { switch (mIns[i].mMode) { case ASMIM_ZERO_PAGE: used += mIns[i].mAddress; if (mIns[i].ChangesAddress()) modified += mIns[i].mAddress; break; case ASMIM_INDIRECT_Y: used += mIns[i].mAddress + 0; used += mIns[i].mAddress + 1; pairs += mIns[i].mAddress; break; case ASMIM_ABSOLUTE: if (mIns[i].mType == ASMIT_JSR) { if (mIns[i].mFlags & NCIF_RUNTIME) { for (int j = 0; j < 4; j++) { used += BC_REG_ACCU + j; used += BC_REG_WORK + j; modified += BC_REG_ACCU + j; modified += BC_REG_WORK + j; } } if (mIns[i].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(); 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; pblock->mIns[pz - 1].mType = ASMIT_LDX; 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::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 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) { 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(ASMIT_INY)); mIns.Insert(i + 1, NativeCodeInstruction(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 && !(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 { 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 && 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 + 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++; 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 && 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 + 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++; 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++; 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(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(ASMIT_INY)); mIns.Insert(i + 1, NativeCodeInstruction(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; } #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(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::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 (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 (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::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; } void NativeCodeBasicBlock::BuildUseChangeSets(int start, int end, unsigned & used, unsigned & changed) { used = 0; changed = 0; for (int i = start; i < end; i++) { 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::CanExchangeSegments(int start, int mid, int end) { unsigned usedFront, changedFront, usedBack, changedBack; BuildUseChangeSets(start, mid, usedFront, changedFront); BuildUseChangeSets(mid, end, usedBack, changedBack); 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 + 1 < 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 (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(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(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 i = at; while (i > 0) { i--; if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress) { 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 && 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; } } 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)) { 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_JSR) { 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(); 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; mFalseJump = mTrueJump->mFalseJump; mTrueJump = mTrueJump->mTrueJump; 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) const { for (int i = 0; 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 (mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) { mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(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 (mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) { mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(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; 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; mTrueJump->mIns.Insert(0, mIns[sz]); mIns.Remove(sz); 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* 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; NativeCodeInstruction ilow(mIns[sz - 7]); NativeCodeInstruction ihigh(mIns[sz - 4]); mIns.SetSize(sz - 8); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ilow.mMode, ilow.mAddress, ilow.mLinkerObject)); hblock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, ihigh.mMode, ihigh.mAddress, ihigh.mLinkerObject)); dblock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, ilow.mMode, ilow.mAddress, ilow.mLinkerObject)); zblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ihigh.mMode, ihigh.mAddress, ihigh.mLinkerObject)); } } #endif if (mTrueJump && mTrueJump->Split16BitLoopCount(proc)) changed = true; if (mFalseJump && mFalseJump->Split16BitLoopCount(proc)) changed = true; } return changed; } bool NativeCodeBasicBlock::CrossBlockStoreLoadBypass(NativeCodeProcedure* proc) { bool changed = false; if (!mVisited) { mVisited = true; if (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); 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->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this)); mTrueJump->mNumEntries--; 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::ExpandADCToBranch(NativeCodeProcedure* proc) { bool changed = false; if (!mVisited) { mVisited = true; for (int i = 0; i < mIns.Size(); i++) { #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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(rblock, nullptr, ASMIT_JMP); break; } 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(ASMIT_ASL)); mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BCS; eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(rblock, nullptr, ASMIT_JMP); break; } } #endif #if 1 if (i + 6 < mIns.Size()) { if (mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) && mIns[i + 4].mType == ASMIT_LDA && mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 && mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) && !(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; if (mIns[i + 6].mLive & LIVE_CPU_REG_A) fblock->mIns.Push(mIns[i + 4]); for (int j = i + 7; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 6]); mIns.SetSize(i + 4); iblock->mIns[0].mType = ASMIT_INC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BNE; break; } if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) && mIns[i + 4].mType == ASMIT_LDA && mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 && mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 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_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; for (int j = i + 7; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 6]); mIns.SetSize(i + 4); iblock->mIns[0].mType = ASMIT_INC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BNE; break; } if (mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) && mIns[i + 4].mType == ASMIT_LDA && mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff && mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 3].mMode) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 6].mMode) && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; fblock->mIns.Push(mIns[i + 1]); fblock->mIns[0].mType = ASMIT_DEC; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; for (int j = i + 7; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 6]); mIns.SetSize(i + 4); iblock->mIns[0].mType = ASMIT_DEC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BNE; break; } } #endif #if 1 if (i + 5 < mIns.Size() && mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 && mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mType == ASMIT_EOR && mIns[i + 5].mMode == ASMIM_IMMEDIATE) { uint8 veq = mIns[i + 4].mAddress ^ mIns[i + 5].mAddress, vne = mIns[i + 5].mAddress; changed = true; NativeCodeBasicBlock* eblock = proc->AllocateBlock(); NativeCodeBasicBlock* neblock = proc->AllocateBlock(); NativeCodeBasicBlock* rblock = proc->AllocateBlock(); rblock->mTrueJump = mTrueJump; rblock->mFalseJump = mFalseJump; rblock->mBranch = mBranch; for (int j = i + 6; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i + 1); mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BNE; if (veq != 0) eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, veq)); neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, vne)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(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; for (int j = i + 5; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); mTrueJump = iblock; mFalseJump = rblock; mBranch = ASMIT_BCS; iblock->mIns.Push(NativeCodeInstruction(ASMIT_INY)); iblock->Close(rblock, nullptr, ASMIT_JMP); break; } #endif #if 1 if (i + 3 < mIns.Size() && mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 && mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED) { changed = true; NativeCodeBasicBlock* eblock = proc->AllocateBlock(); NativeCodeBasicBlock* neblock = proc->AllocateBlock(); NativeCodeBasicBlock* rblock = proc->AllocateBlock(); rblock->mTrueJump = mTrueJump; rblock->mFalseJump = mFalseJump; rblock->mBranch = mBranch; for (int j = i + 4; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i + 1); mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BNE; neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 1)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(rblock, nullptr, ASMIT_JMP); break; } #endif #if 1 if (i + 4 < mIns.Size() && (mIns[i + 0].mType == ASMIT_CPX || mIns[i + 0].mType == ASMIT_CPY) && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x01 && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff && mIns[i + 3].mType == ASMIT_AND && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE) { uint8 veq = mIns[i + 3].mAddress ^ mIns[i + 4].mAddress, vne = mIns[i + 4].mAddress; changed = true; NativeCodeBasicBlock* eblock = proc->AllocateBlock(); NativeCodeBasicBlock* neblock = proc->AllocateBlock(); NativeCodeBasicBlock* rblock = proc->AllocateBlock(); rblock->mTrueJump = mTrueJump; rblock->mFalseJump = mFalseJump; rblock->mBranch = mBranch; for (int j = i + 5; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i + 1); if (mIns[i + 0].mType == ASMIT_CPX) mIns[i + 0].mType = ASMIT_TXA; else if (mIns[i + 0].mType == ASMIT_CPY) mIns[i + 0].mType = ASMIT_TYA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BNE; if (veq != 0) eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, veq)); neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, vne)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(rblock, nullptr, ASMIT_JMP); break; } #endif #if 1 if (i + 4 < mIns.Size() && mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 && mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE) { uint8 veq = mIns[i + 4].mAddress, vne = 0; changed = true; NativeCodeBasicBlock* eblock = proc->AllocateBlock(); NativeCodeBasicBlock* neblock = proc->AllocateBlock(); NativeCodeBasicBlock* rblock = proc->AllocateBlock(); rblock->mTrueJump = mTrueJump; rblock->mFalseJump = mFalseJump; rblock->mBranch = mBranch; for (int j = i + 5; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i + 1); mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BNE; if (veq != 0) eblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, veq)); neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, vne)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(rblock, nullptr, ASMIT_JMP); break; } #endif #if 1 if (i + 4 < mIns.Size() && mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 && mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff) { changed = true; NativeCodeBasicBlock* eblock = proc->AllocateBlock(); NativeCodeBasicBlock* neblock = proc->AllocateBlock(); NativeCodeBasicBlock* rblock = proc->AllocateBlock(); rblock->mTrueJump = mTrueJump; rblock->mFalseJump = mFalseJump; rblock->mBranch = mBranch; for (int j = i + 5; j < mIns.Size(); j++) rblock->mIns.Push(mIns[j]); mIns.SetSize(i + 1); mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mTrueJump = neblock; mFalseJump = eblock; mBranch = ASMIT_BNE; neblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0xff)); eblock->Close(rblock, nullptr, ASMIT_JMP); neblock->Close(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(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(ASMIT_INX)); iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = ablock; mFalseJump = dblock; mBranch = ASMIT_BPL; fblock->mIns.Push(NativeCodeInstruction(ASMIT_STX, mIns[i + 12])); for (int j = i + 13; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); mIns.Insert(i, NativeCodeInstruction(ASMIT_LDX, mIns[i + 11])); mIns[i + 1].mLive |= LIVE_CPU_REG_X; mIns.SetSize(i + 2); break; } } } } } } } #endif if (i + 2 < mIns.Size()) { if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock * iblock = proc->AllocateBlock(); NativeCodeBasicBlock * fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 2]); mIns.SetSize(i); iblock->mIns[0].mType = ASMIT_INC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 2].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 2]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 2]); mIns.SetSize(i); iblock->mIns[0].mType = ASMIT_INC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 2]); mIns.SetSize(i); iblock->mIns[0].mType = ASMIT_DEC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCS; break; } else if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); mIns.SetSize(i); iblock->mIns.Push(NativeCodeInstruction(ASMIT_INX)); iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; 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(ASMIT_INY)); iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; 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(ASMIT_INX)); iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); mIns.SetSize(i); iblock->mIns.Push(NativeCodeInstruction(ASMIT_INY)); iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCC; break; } else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { changed = true; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); NativeCodeBasicBlock* fblock = proc->AllocateBlock(); fblock->mTrueJump = mTrueJump; fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; for (int j = i + 3; j < mIns.Size(); j++) fblock->mIns.Push(mIns[j]); iblock->mIns.Push(mIns[i + 2]); mIns.SetSize(i); iblock->mIns[0].mType = ASMIT_DEC; iblock->mTrueJump = fblock; iblock->mBranch = ASMIT_JMP; mTrueJump = fblock; mFalseJump = iblock; mBranch = ASMIT_BCS; break; } } } if (mIns.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; NativeCodeBasicBlock* iblock = proc->AllocateBlock(); iblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, addr)); mIns.SetSize(sz - 2); mIns.Push(NativeCodeInstruction(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() >= 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 && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && 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))) { changed = true; NativeCodeBasicBlock* cblock = proc->AllocateBlock(); cblock->Close(mFalseJump, mTrueJump, mBranch); mIns[sz - 1].mAddress = mIns[sz - 2].mAddress; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED; if (mBranch == ASMIT_BCC) { mBranch = ASMIT_BNE; mTrueJump = cblock; } else { mBranch = ASMIT_BEQ; mFalseJump = cblock; } } } 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; hblock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, mIns[sz - 4])); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, mIns[sz - 5])); oblock->mIns.Push(NativeCodeInstruction(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 1 if (mIns.Size() >= 1 && mFalseJump) { int sz = mIns.Size(); if (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY) { if (mBranch == ASMIT_BEQ) { if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0) { if (mFalseJump->mIns.Size() == 0) { if (mFalseJump->mBranch == ASMIT_BCC) { mFalseJump = mFalseJump->mFalseJump; changed = true; } else if (mFalseJump->mBranch == ASMIT_BCS) { mFalseJump = mFalseJump->mTrueJump; changed = true; } } if (mTrueJump->mIns.Size() == 0) { if (mTrueJump->mBranch == ASMIT_BCC) { mTrueJump = mTrueJump->mFalseJump; changed = true; } else if (mTrueJump->mBranch == ASMIT_BCS) { mTrueJump = mTrueJump->mTrueJump; changed = true; } } } if (mFalseJump->mNumEntries == 1/* && mTrueJump->mNumEntries == 2*/ && mFalseJump->mIns.Size() == 0) { if (mFalseJump->mBranch == ASMIT_BCC) { if (mFalseJump->mFalseJump == mTrueJump) { mBranch = ASMIT_BCS; mFalseJump = mFalseJump->mFalseJump; changed = true; } } else if (mFalseJump->mBranch == ASMIT_BCS) { if (mFalseJump->mTrueJump == mTrueJump) { mBranch = ASMIT_BCS; mFalseJump = mFalseJump->mTrueJump; changed = true; } } } } else if (mBranch == ASMIT_BNE) { if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0) { if (mFalseJump->mIns.Size() == 0) { if (mFalseJump->mBranch == ASMIT_BCC) { mFalseJump = mFalseJump->mFalseJump; changed = true; } else if (mFalseJump->mBranch == ASMIT_BCS) { mFalseJump = mFalseJump->mTrueJump; changed = true; } } if (mTrueJump->mIns.Size() == 0) { if (mTrueJump->mBranch == ASMIT_BCC) { mTrueJump = mTrueJump->mFalseJump; changed = true; } else if (mTrueJump->mBranch == ASMIT_BCS) { mTrueJump = mTrueJump->mTrueJump; changed = true; } } } if (mTrueJump->mNumEntries == 1/* && mFalseJump->mNumEntries == 2*/ && mTrueJump->mIns.Size() == 0) { if (mTrueJump->mBranch == ASMIT_BCC) { if (mTrueJump->mFalseJump == mFalseJump) { mBranch = ASMIT_BCC; mTrueJump = mTrueJump->mTrueJump; changed = true; } } else if (mTrueJump->mBranch == ASMIT_BCS) { if (mTrueJump->mTrueJump == mFalseJump) { mBranch = ASMIT_BCC; mTrueJump = mTrueJump->mFalseJump; changed = true; } } } } } } #endif 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 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; 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; else if (ins.ChangesZeroPage(r1)) valid1 = false; i++; } return changed; } bool NativeCodeBasicBlock::RemoveDoubleZPStore(void) { bool changed = false; if (!mVisited) { mVisited = true; 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)) 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)) 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)) changed = true; } } if (mTrueJump && mTrueJump->RemoveDoubleZPStore()) changed = true; if (mFalseJump && mFalseJump->RemoveDoubleZPStore()) 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; } void NativeCodeBasicBlock::GlobalRegisterXYCheck(int* xregs, int* yregs) { if (!mVisited) { mVisited = true; int yreg = -1; int xreg = -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]++; if (xregs[ins.mAddress] >= 0) xregs[ins.mAddress]++; break; case ASMIT_LDY: if (yregs[ins.mAddress] >= 0) { yregs[ins.mAddress] += 2; 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; 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]++; if (xregs[ins.mAddress] >= 0) xregs[ins.mAddress]++; } 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; if (xregs[ins.mAddress] >= 0) xregs[ins.mAddress] += 3; 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::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) { int i = 0; while (i < mEntryBlocks.Size() && mEntryBlocks[i] != block) i++; if (i == mEntryBlocks.Size()) mEntryBlocks.Push(block); } void NativeCodeBasicBlock::RemEntryBlock(NativeCodeBasicBlock* block) { int i = 0; while (i < mEntryBlocks.Size() && mEntryBlocks[i] != block) i++; if (i < mEntryBlocks.Size()) mEntryBlocks.Remove(i); } 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; } bool NativeCodeBasicBlock::PropagateSinglePath(void) { bool changed = false; if (!mVisited) { mVisited = true; CheckLive(); #if 1 if (mTrueJump && mFalseJump && mTrueJump->mEntryProvidedRegs.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; } } } #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 (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_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 (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 (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())) { if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y]) mTrueJump->PrependInstruction(mIns[i - 1]); else mFalseJump->PrependInstruction(mIns[i - 1]); mIns.Remove(i - 1); 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; 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) { 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) { 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::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::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::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(ASMIT_TAX)); mIns.Insert(8, NativeCodeInstruction(ASMIT_TXA)); } changed = true; } } } } while (eb->mIns.Size() > 0) { 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; 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; b->mIns.SetSize(b->mIns.Size() - 1); } changed = true; } else { int addr, index, taddr, tindex; if (eb->HasTailSTA(addr, index)) { i = 1; while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTA(taddr, tindex) && taddr == addr) i++; if (i == mEntryBlocks.Size()) { 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); 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()) { 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); 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()) { 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); 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 && !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()) { if (!mEntryRequiredRegs[CPU_REG_A]) { mIns.Insert(0, NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, saddr)); mIns.Insert(1, NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, daddr)); changed = true; } else if (!mEntryRequiredRegs[CPU_REG_X]) { mIns.Insert(0, NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, saddr)); mIns.Insert(1, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, daddr)); changed = true; } } } } } } 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; } } } } 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(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 if (mTrueJump && mFalseJump) { int addr, index, taddr; 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 (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); 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); pblock->mExitRequiredRegs += CPU_REG_Y; mEntryRequiredRegs += CPU_REG_Y; mExitRequiredRegs += CPU_REG_Y; changed = true; } } else if (mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_A)) { if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress && lblock->mIns[ls - 1].mType == ASMIT_CMP && !(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A)) { lblock->mIns[ls - 2].mType = ASMIT_LDX; lblock->mIns[ls - 2].mLive |= LIVE_CPU_REG_X; lblock->mIns[ls - 1].mType = ASMIT_CPX; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_X; pblock = AddDominatorBlock(proc, pblock); pblock->mIns.Push(mIns[0]); mIns.Remove(0); pblock->mExitRequiredRegs += CPU_REG_X; mEntryRequiredRegs += CPU_REG_X; mExitRequiredRegs += CPU_REG_X; changed = true; } } else if (mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE) { if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress && lblock->mIns[ls - 1].mType == ASMIT_CMP) { pblock = AddDominatorBlock(proc, pblock); pblock->mIns.Push(mIns[0]); mIns.Remove(0); 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 (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(); } } } #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(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(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 #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 1 if (mIns.Size() >= 2) { int ns = mIns.Size(); const NativeCodeInstruction& ins(mIns[ns - 2]); if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && mTrueJump && mFalseJump && !mIns[ns-1].UsesZeroPage(ins.mAddress) && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size()) { if (!mIns[ns - 1].ChangesAccu()) { if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1) { mTrueJump->mIns.Insert(0, ins); mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Remove(ns - 2); 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(ns - 2); 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)) { if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1) { mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X; mIns[ns - 2].mType = ASMIT_STX; mTrueJump->mIns.Insert(0, ins); mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Remove(ns - 2); mTrueJump->mEntryRequiredRegs += CPU_REG_X; mTrueJump->CheckLive(); changed = true; } else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1) { mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X; mIns[ns - 2].mType = ASMIT_STX; mFalseJump->mIns.Insert(0, ins); mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C; mIns.Remove(ns - 2); mFalseJump->mEntryRequiredRegs += CPU_REG_X; mFalseJump->CheckLive(); changed = true; } } } } #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->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->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(); } } } } #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; mTrueJump->mEntryProvidedRegs += 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; mTrueJump->mEntryProvidedRegs += 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; if (mIns[s - 1].RequiresYReg()) live |= LIVE_CPU_REG_Y; 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; 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; } } } } } CheckLive(); if (mTrueJump && mTrueJump->JoinTailCodeSequences(proc, loops)) changed = true; if (mFalseJump && mFalseJump->JoinTailCodeSequences(proc, loops)) 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(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(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::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::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::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 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(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(ASMIT_TXA)); mIns.Remove(i); changed = true; mExitRequiredRegs -= CPU_REG_A; mExitRequiredRegs += 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(ASMIT_TYA)); mIns.Remove(i); changed = true; mExitRequiredRegs -= CPU_REG_A; mExitRequiredRegs += 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(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(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; 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::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 (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; } 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 (mTrueJump && mTrueJump->PatchSingleUseGlobalLoad(block, reg, 0, ains)) changed = true; if (mFalseJump && mFalseJump->PatchSingleUseGlobalLoad(block, reg, 0, ains)) changed = true; } return changed; } bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval) { if (!mPatched) { mPatched = true; if (at == 0) { if (!mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1]) return true; if (mNumEntries > 1) { for (int i = 0; i < mEntryBlocks.Size(); i++) if (!mEntryBlocks[i]->IsDominatedBy(block)) return false; yval = -1; } } 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 (yval < 0 || yval > 3) 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.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(base) || ins.ChangesZeroPage(base + 1) || iins.MayBeChangedOnAddress(ins)) return false; yval = -1; } 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)) return false; if (mFalseJump && !mFalseJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval)) 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; if (ins.mLive & LIVE_CPU_REG_Y) mIns.Insert(at + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yval)); mIns.Insert(at, NativeCodeInstruction(ASMIT_LDY, iins)); at++; for (int i = 0; i < yval; i++) { mIns.Insert(at, NativeCodeInstruction(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::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; } bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const { if (this == block) return true; #if 0 if (mEntryBlocks.Size()) { if (mLoopHead) return false; for (int i = 0; i < mEntryBlocks.Size(); i++) if (!mEntryBlocks[i]->IsDominatedBy(block)) return false; return true; } return false; #else else { NativeCodeBasicBlock* dom = mDominator; while (dom) { if (dom == block) return true; dom = dom->mDominator; } return false; } #endif } bool NativeCodeBasicBlock::CheckPatchFailLoop(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg, bool changed) { if (!mPatchLoop || (changed && !mPatchLoopChanged)) { mPatchLoop = true; mPatchLoopChanged = changed; if (this == block) return true; if (!changed) { for (int i = 0; i < mIns.Size(); i++) { if (mIns[i].ChangesZeroPage(reg)) 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 (ins.mMode == ASMIM_ZERO_PAGE) { if (ins.mAddress == index && ins.ChangesAddress()) return false; else if (ins.mAddress == reg || ins.mAddress == reg + 1) { if (ins.ChangesAddress() || reg == index) return false; } } else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg) { if (yval < 0) return false; else if (!(ins.mLive & LIVE_MEM)) { mPatchChecked = true; return !mPatchFail; } } if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE) yval = ins.mAddress; else if (ins.mType == ASMIT_INY && yval >= 0) yval = (yval + 1) & 255; else if (ins.mType == ASMIT_DEY && yval >= 0) yval = (yval - 1) & 255; else if (ins.mType == ASMIT_JSR) { if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(index)) return false; yval = -1; } else if (ins.ChangesYReg()) yval = -1; at++; } if (mTrueJump && !mTrueJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval)) return false; if (mFalseJump && !mFalseJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval)) return false; } return true; } bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject* lobj, int address, uint32 flags) { bool changed = false; if (!mPatched) { mPatched = true; if (at == 0 && !mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1]) return false; while (at < mIns.Size()) { NativeCodeInstruction& ins(mIns[at]); assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1) && reg == index)); if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg) { assert(yval >= 0); bool done = !(ins.mLive & LIVE_MEM); ins.mMode = ASMIM_ABSOLUTE_Y; ins.mLinkerObject = lobj; ins.mAddress = address + yval; ins.mFlags = (ins.mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | flags; if (ins.mLive & LIVE_CPU_REG_Y) mIns.Insert(at + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yval)); mIns.Insert(at, NativeCodeInstruction(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.ChangesYReg()) yval = -1; else if (at + 6 < mIns.Size() && mIns[at + 0].mType == ASMIT_CLC && mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg + 0 && mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 && mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE && mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE) { int add = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress; mIns[at + 1].mAddress = index; mIns[at + 2].mMode = ASMIM_IMMEDIATE_ADDRESS; mIns[at + 2].mLinkerObject = lobj; mIns[at + 2].mAddress = address + add; mIns[at + 2].mFlags = NCIF_LOWER; mIns[at + 4].mMode = ASMIM_IMMEDIATE; mIns[at + 4].mAddress = 0; mIns[at + 5].mMode = ASMIM_IMMEDIATE_ADDRESS; mIns[at + 5].mLinkerObject = lobj; mIns[at + 5].mAddress = address + add; mIns[at + 5].mFlags = NCIF_UPPER; changed = true; } at++; } if (mTrueJump && mTrueJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags)) changed = true; if (mFalseJump && mFalseJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags)) changed = true; } return changed; } bool NativeCodeBasicBlock::FindGlobalAddressSumY(int at, int reg, bool direct, int& apos, const NativeCodeInstruction*& ains, const NativeCodeInstruction*& iins, uint32& flags, int& addr) { flags = 0; int j = at - 7; while (j >= 0) { if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 1]); iins = &(mIns[j + 2]); apos = j + 0; int ireg = iins->mAddress; if (reg == ireg) { if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; int k = j + 7; while (k < at) { if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else { int k = j + 7; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } return true; } } else if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = &(mIns[j + 1]); apos = j + 0; int ireg = iins->mAddress; if (reg == ireg) { if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; int k = j + 7; while (k < at) { if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else { int k = j + 7; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } return true; } } else if ( mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mType == ASMIT_CLC && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = &(mIns[j + 0]); apos = j + 1; int ireg = iins->mAddress; if (reg == ireg) { if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; int k = j + 7; while (k < at) { if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else { int k = j + 7; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } return true; } } else if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ABSOLUTE && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 1]); iins = &(mIns[j + 2]); apos = j + 0; int k = j + 7; while (k < at) { if (mIns[k].ChangesGlobalMemory()) return false; k++; } return true; } #if 1 else if ( mIns[j + 1].mType == ASMIT_CLC && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = nullptr; apos = j + 1; if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; if (mIns[j + 0].mType == ASMIT_TAX) flags |= LIVE_CPU_REG_X; if (mIns[j + 0].mType == ASMIT_TAY) flags |= LIVE_CPU_REG_Y; int k = j + 7; while (k < at) { assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA); if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else if ( mIns[j + 1].mType == ASMIT_CLC && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 5].mFlags & NCIF_UPPER) && mIns[j + 5].mLinkerObject == mIns[j + 2].mLinkerObject && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = nullptr; apos = j + 1; if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; if (mIns[j + 0].mType == ASMIT_TAX) flags |= LIVE_CPU_REG_X; if (mIns[j + 0].mType == ASMIT_TAY) flags |= LIVE_CPU_REG_Y; int k = j + 7; while (k < at) { assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA); if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = &(mIns[j + 1]); apos = j + 0; addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress); int ireg = iins->mAddress; if (reg == ireg) { if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; int k = j + 7; while (k < at) { if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else { int k = j + 7; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } return true; } } else if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 1]); iins = &(mIns[j + 2]); apos = j + 0; addr = mIns[j + 1].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress); int ireg = iins->mAddress; if (reg == ireg) { if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; int k = j + 7; while (k < at) { if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } else { int k = j + 7; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } return true; } } else if ( mIns[j + 1].mType == ASMIT_CLC && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE && mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) { ains = &(mIns[j + 2]); iins = nullptr; apos = j + 1; addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress); if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; if (mIns[j + 0].mType == ASMIT_TAX) flags |= LIVE_CPU_REG_X; if (mIns[j + 0].mType == ASMIT_TAY) flags |= LIVE_CPU_REG_Y; int k = j + 7; while (k < at) { assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA); if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } #endif if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress()) return false; j--; } if (at >= 6 && mIns[0].mType == ASMIT_CLC && mIns[1].mType == ASMIT_ADC && mIns[1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[1].mFlags & NCIF_LOWER) && mIns[1].mLinkerObject && mIns[2].mType == ASMIT_STA && mIns[2].mMode == ASMIM_ZERO_PAGE && mIns[2].mAddress == reg && mIns[3].mType == ASMIT_LDA && mIns[3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[3].mFlags & NCIF_UPPER) && mIns[3].mLinkerObject == mIns[1].mLinkerObject && mIns[4].mType == ASMIT_ADC && mIns[4].mMode == ASMIM_IMMEDIATE && mIns[4].mAddress == 0 && mIns[5].mType == ASMIT_STA && mIns[5].mMode == ASMIM_ZERO_PAGE && mIns[5].mAddress == reg + 1) { ains = &(mIns[1]); iins = nullptr; apos = 0; if (!direct) return false; flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[0].mLive; int k = 6; while (k < at) { assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA); if (mIns[k].ChangesYReg()) flags &= ~LIVE_CPU_REG_Y; if (mIns[k].ChangesXReg()) flags &= ~LIVE_CPU_REG_X; k++; } return flags != 0; } if (mFromJump) { while (j >= -6) { if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress()) return false; j--; } if (mFromJump->FindGlobalAddressSumY(mFromJump->mIns.Size(), reg, false, apos, ains, iins, flags, addr)) { if (iins->mMode == ASMIM_ZERO_PAGE) { int ireg = iins->mAddress; int k = 0; while (k < at) { if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress()) return false; k++; } } else { int k = 0; while (k < at) { if (mIns[k].ChangesGlobalMemory()) return false; k++; } } return true; } } return false; } bool NativeCodeBasicBlock::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(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; } 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].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; } 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; } } } 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; } 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::RetrieveYValue(int at) const { while (at > 0 && !mIns[at].ChangesYReg()) at--; if (mIns[at].mType == ASMIT_LDY && mIns[at].mMode == ASMIM_IMMEDIATE) return mIns[at].mAddress; else return -1; } void NativeCodeBasicBlock::InsertLoadYImmediate(int at, int val) { while (at < mIns.Size() && !mIns[at].ReferencesYReg() && !(mIns[at].mLive & LIVE_CPU_REG_Z)) at++; mIns.Insert(at, NativeCodeInstruction(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; if (mIns[last].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(last + 1, yindex); // mIns.Insert(last + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yindex)); // mIns[last + 1].mLive |= CPU_REG_Y; } 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; if (mIns[last].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(last + 1, yindex); // mIns.Insert(last + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yindex)); // mIns[last + 1].mLive |= CPU_REG_Y; } 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::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::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(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) { 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; } 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 intervall 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) { 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(ASMIT_TYA)); mIns.Insert(j + 3, NativeCodeInstruction(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) { 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(ASMIT_TYA)); mIns.Insert(j + 3, NativeCodeInstruction(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) { mIns[at + 1].mLive |= mIns[j].mLive; mIns[at + 2].mLive |= mIns[j].mLive; 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].ReferencesYReg()) 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_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]); if (j > 0) { mIns[j].mLive |= mIns[j - 1].mLive; mIns[j + 1].mLive |= mIns[j - 1].mLive; } 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[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[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; 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; } 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; } } 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; iResetPatched(); 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 + 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); return true; } } } } return false; } bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair) { if (at == 0 && mVisited) return false; if (!mPatched) { mPatched = true; if (at == 0) { mPatched = true; if (mNumEntries > 1) { for (int i = 0; i < mEntryBlocks.Size(); i++) if (!mEntryBlocks[i]->IsDominatedBy(block)) return false; } } while (at < mIns.Size()) { if (mIns[at].mMode == ASMIM_ZERO_PAGE) { if (mIns[at].mAddress == to) return false; if (pair && mIns[at].mAddress == to + 1) return false; } else if (mIns[at].mMode == ASMIM_INDIRECT_Y) { if (mIns[at].mAddress == to) 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) { 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)) return false; if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair)) return false; } 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)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) 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)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) changed = true; nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 4, mIns[i + 3].mAddress, mIns[i + 2].mAddress)) 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)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress)) changed = true; nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 6, mIns[i + 5].mAddress, mIns[i + 3].mAddress)) 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)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) changed = true; nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 5, mIns[i + 4].mAddress, mIns[i + 2].mAddress)) 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::ForwardReplaceZeroPage(int at, int from, int to) { 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)) changed = true; if (mFalseJump && mFalseJump->ForwardReplaceZeroPage(0, from, to)) changed = true; } 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::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 NativeCodeBasicBlock::Propagate16BitSum(void) { bool changed = false; if (!mVisited) { mVisited = true; GrowingArray infos(NativeRegisterSum16Info{}); for (int i = 0; i < mIns.Size(); i++) { NativeRegisterSum16Info info; if (Check16BitSum(i, info)) { for (int j = 0; j < infos.Size(); j++) { if (info.mSrcL->mAddress == infos[j].mDstL->mAddress && info.mSrcH->mAddress == infos[j].mDstH->mAddress) { if (!info.mLinkerObject && !infos[j].mLinkerObject) { info.mAddress += infos[j].mAddress; info.mAddL->mAddress = info.mAddress & 0xff; info.mAddH->mAddress = info.mAddress >> 8; info.mSrcL->mAddress = infos[j].mSrcL->mAddress; info.mSrcH->mAddress = infos[j].mSrcH->mAddress; info.mSrcH->mMode = infos[j].mSrcH->mMode; changed = true; } else if (!infos[j].mLinkerObject) { info.mAddress += infos[j].mAddress; info.mAddL->mAddress = info.mAddress; info.mAddH->mAddress = info.mAddress; info.mSrcL->mAddress = infos[j].mSrcL->mAddress; info.mSrcH->mAddress = infos[j].mSrcH->mAddress; info.mSrcH->mMode = infos[j].mSrcH->mMode; changed = true; } else if (!info.mLinkerObject) { info.mAddress += infos[j].mAddress; info.mLinkerObject = infos[j].mLinkerObject; 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 = infos[j].mSrcL->mAddress; info.mSrcH->mAddress = infos[j].mSrcH->mAddress; info.mSrcH->mMode = infos[j].mSrcH->mMode; changed = true; } } } if (info.mSrcL->mAddress != info.mDstL->mAddress && (info.mSrcH->mMode == ASMIM_IMMEDIATE || info.mSrcH->mAddress != info.mDstH->mAddress)) infos.Push(info); } int j = 0; while (j < infos.Size()) { if (infos[j].mDstL != &(mIns[i]) && infos[j].mDstH != &(mIns[i])) { if ( infos[j].mSrcL->MayBeChangedOnAddress(mIns[i]) || infos[j].mSrcH->MayBeChangedOnAddress(mIns[i]) || infos[j].mDstL->MayBeChangedOnAddress(mIns[i]) || infos[j].mDstH->MayBeChangedOnAddress(mIns[i])) { infos.Remove(j); } else j++; } else j++; } } if (mTrueJump && mTrueJump->Propagate16BitSum()) changed = true; if (mFalseJump && mFalseJump->Propagate16BitSum()) changed = true; } return changed; } bool NativeCodeBasicBlock::MoveLoadXUp(int at) { int i = at - 1; while (i >= 0) { if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress) { mIns[i].mType = ASMIT_TAX; mIns[i].mMode = ASMIM_IMPLIED; mIns[at].mType = ASMIT_NOP; mIns[at].mMode = ASMIM_IMPLIED; while (i < at) { mIns[i].mLive |= LIVE_CPU_REG_X; i++; } return true; } else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress) { mIns[i].mType = ASMIT_LDX; mIns[i].mLive |= LIVE_MEM; mIns[at].mType = ASMIT_INX; mIns[at].mMode = ASMIM_IMPLIED; while (i < at) { mIns[i].mLive |= LIVE_CPU_REG_X; i++; } return true; } if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X) || mIns[i].UsesZeroPage(mIns[at].mAddress)) return false; i--; } return false; } bool NativeCodeBasicBlock::MoveStoreXUp(int at) { bool done = false; int n = 0, inc = 0;; int reg = mIns[at].mAddress; while (at > 0) { if (mIns[at - 1].mType == ASMIT_INX) { n++; inc++; } else if (mIns[at - 1].mType == ASMIT_DEX) { n++; inc--; } else { if (mIns[at - 1].mType == ASMIT_LDX || mIns[at - 1].mType == ASMIT_TAX || mIns[at - 1].mType == ASMIT_TXA) return done; else if (mIns[at - 1].ChangesXReg() || mIns[at - 1].mType == ASMIT_STX) return done; else if (mIns[at + n].mMode == ASMIM_ZERO_PAGE) { if ((mIns[at - 1].mMode == ASMIM_ZERO_PAGE || mIns[at - 1].mMode == ASMIM_INDIRECT_Y) && mIns[at - 1].mAddress == reg) return done; if (mIns[at - 1].mMode == ASMIM_INDIRECT_Y && mIns[at - 1].mAddress + 1 == reg) return done; } else { if (mIns[at - 1].mMode == ASMIM_ABSOLUTE && mIns[at - 1].mLinkerObject == mIns[at + n].mLinkerObject && mIns[at - 1].mAddress == mIns[at + n].mAddress) return done; else if ((mIns[at - 1].mMode == ASMIM_ABSOLUTE_X || mIns[at - 1].mMode == ASMIM_ABSOLUTE_Y) && mIns[at - 1].mLinkerObject == mIns[at + n].mLinkerObject) return done; } if (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; 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++; NativeCodeInstruction sins = mIns[at + 1]; mIns.Remove(at + 1); if (!(sins.mLive & LIVE_CPU_REG_A)) mIns.Remove(at); if (sins.ReferencesXReg()) sins.mLive |= LIVE_CPU_REG_X; if (sins.ReferencesYReg()) sins.mLive |= LIVE_CPU_REG_Y; mIns.Insert(j, sins); return true; } else if (mIns[j - 1].mMode == mIns[at + 1].mMode && mIns[j - 1].mAddress == mIns[at + 1].mAddress) return false; j--; } else if (mIns[j - 1].mType == ASMIT_STA && mIns[j - 1].mMode == mIns[at + 1].mMode && !(mIns[j - 1].mLinkerObject == mIns[at + 1].mLinkerObject && mIns[j - 1].mAddress == mIns[at + 1].mAddress)) j--; else return false; } return false; } bool NativeCodeBasicBlock::MoveLoadStoreUp(int at) { int j = at; while (j > 0 && !((mIns[j - 1].mType == ASMIT_STA || mIns[j - 1].mType == ASMIT_LDA) && mIns[j - 1].mMode == ASMIM_ZERO_PAGE && mIns[j - 1].mAddress == mIns[at].mAddress)) { j--; if ((mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_INDIRECT_Y) && mIns[j].mAddress == mIns[at + 1].mAddress) return false; if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress + 1 == mIns[at + 1].mAddress) return false; if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress && mIns[j].ChangesAddress()) return false; if (mIns[j].mMode == ASMIM_ABSOLUTE_Y && mIns[j].mAddress <= mIns[at + 1].mAddress && mIns[j].mType == ASMIT_LDA && !mIns[j].mLinkerObject) return false; if (mIns[j].mType == ASMIT_JSR) return false; } if (j > 0 && j < at) { mIns.Insert(j, mIns[at + 1]); mIns[j - 1].mLive |= LIVE_CPU_REG_A; mIns[j].mLive |= LIVE_CPU_REG_A; mIns[j].mLive |= mIns[j - 1].mLive; mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; return true; } return false; } 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].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].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].mFlags & NCIF_UPPER) mIns[at + 1].mAddress += val * 256; else mIns[at + 1].mAddress += val; mIns.Remove(i - 2, 2); return true; } } return false; } if (mIns[i].ReferencesZeroPage(addr)) return false; } return false; } bool NativeCodeBasicBlock::MoveTXADCDown(int at) { int i = at + 4; while (i < mIns.Size()) { if (mIns[i].ChangesXReg()) return false; if (mIns[i].ReferencesZeroPage(mIns[at + 3].mAddress)) return false; if (!(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) { mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, mIns[at + 3].mAddress)); switch (mIns[at + 2].mAddress) { case -2: case 254: mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_DEX)); case -1: case 255: mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_DEX)); break; case 2: mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_INX)); case 1: mIns.Insert(i + 1, NativeCodeInstruction(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].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(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) { mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4); mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4); mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4); mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4); return true; } else return false; } bool NativeCodeBasicBlock::MoveLoadAddImmStoreUp(int at) { int j = at - 1; while (j > 0) { if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 1].mAddress) { if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) return false; 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::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) { if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) return false; 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].ChangesZeroPage(mIns[at + 2].mAddress)) return false; if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress)) return false; if (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::MoveLDSTXOutOfRange(int at) { 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 (mIns[at + 1].mMode == ASMIM_ABSOLUTE && (mIns[j].mFlags & NCIF_VOLATILE)) return false; if (mIns[j].mType == ASMIT_JSR) return false; if (!(mIns[j].mLive & LIVE_CPU_REG_A)) { mIns.Insert(j + 1, NativeCodeInstruction(ASMIT_STA, mIns[at + 1])); mIns.Insert(j + 1, NativeCodeInstruction(ASMIT_LDA, mIns[at])); mIns.Remove(at, 2); return true; } 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[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.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) { 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]); // 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[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::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; } #endif if (mIns[i].BitFieldForwarding(mNDataSet, carryop)) changed = true; if (carryop != ASMIT_NOP) mIns.Insert(i + 1, NativeCodeInstruction(carryop)); } if (mFalseJump) { mFDataSet = mNDataSet; if (mIns.Size() > 0) { const NativeCodeInstruction& lins(mIns[mIns.Size() - 1]); if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA) { switch (mBranch) { case ASMIT_BEQ: if (mNDataSet.mRegs[lins.mAddress].mMask == 0xff) { if (mNDataSet.mRegs[lins.mAddress].mValue != 0) { mTrueJump->RemoveEntryBlock(this); mTrueJump = mFalseJump; mFalseJump = nullptr; } else { mFalseJump->RemoveEntryBlock(this); mFalseJump = nullptr; } mBranch = ASMIT_JMP; changed = true; } else { mNDataSet.mRegs[CPU_REG_A].mMask = 0xff; mNDataSet.mRegs[CPU_REG_A].mValue = 0x00; mNDataSet.mRegs[lins.mAddress].mMask = 0xff; mNDataSet.mRegs[lins.mAddress].mValue = 0x00; } break; case ASMIT_BNE: if (mNDataSet.mRegs[lins.mAddress].mMask == 0xff) { if (mNDataSet.mRegs[lins.mAddress].mValue == 0) { mTrueJump->RemoveEntryBlock(this); mTrueJump = mFalseJump; mFalseJump = nullptr; } else { mFalseJump->RemoveEntryBlock(this); mFalseJump = nullptr; } mBranch = ASMIT_JMP; changed = true; } else { mFDataSet.mRegs[CPU_REG_A].mMask = 0xff; mFDataSet.mRegs[CPU_REG_A].mValue = 0x00; mFDataSet.mRegs[lins.mAddress].mMask = 0xff; mFDataSet.mRegs[lins.mAddress].mValue = 0x00; } break; case ASMIT_BPL: if (mNDataSet.mRegs[lins.mAddress].mMask & 0x80) { if (mNDataSet.mRegs[lins.mAddress].mValue & 0x80) { mTrueJump->RemoveEntryBlock(this); mTrueJump = mFalseJump; mFalseJump = nullptr; } else { mFalseJump->RemoveEntryBlock(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; 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[lins.mAddress].mMask & 0x80) { if (!(mNDataSet.mRegs[lins.mAddress].mValue & 0x80)) { mTrueJump->RemoveEntryBlock(this); mTrueJump = mFalseJump; mFalseJump = nullptr; } else { mFalseJump->RemoveEntryBlock(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; 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(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 (mIns[i].ValueForwarding(mDataSet, carryop, true, final)) changed = true; if (carryop != ASMIT_NOP) mIns.Insert(i + 1, NativeCodeInstruction(carryop)); } if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding(final)) changed = true; if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding(final)) changed = true; } return changed; } bool NativeCodeBasicBlock::ValueForwarding(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; } } } // Single block loop for (int i = 0; i < mIns.Size(); i++) { NativeCodeInstruction& ins(mIns[i]); if (ins.ChangesAccu()) mNDataSet.mRegs[CPU_REG_A].Reset(); if (ins.ChangesXReg()) mNDataSet.mRegs[CPU_REG_X].Reset(); if (ins.ChangesYReg()) mNDataSet.mRegs[CPU_REG_Y].Reset(); if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress()) mNDataSet.ResetZeroPage(ins.mAddress); if (ins.mType == ASMIT_JSR) { mNDataSet.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++) mNDataSet.ResetZeroPage(i); } else { for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) mNDataSet.ResetZeroPage(i); } for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) mNDataSet.ResetZeroPage(i); } // mNDataSet.Reset(); // break; } } 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 #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(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(ASMIT_LDY, ASMIM_IMMEDIATE, mNDataSet.mRegs[CPU_REG_Y].mValue)); mIns.Insert(i + 3, NativeCodeInstruction(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)) changed = true; if (carryop != ASMIT_NOP) mIns.Insert(i + 1, NativeCodeInstruction(carryop)); } #if 1 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_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; } } 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_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; } } 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; } mTrueJump->mEntryBlocks.RemoveAll(this); mTrueJump->mNumEntries--; target->mEntryBlocks.Push(this); target->mNumEntries++; mTrueJump = target; } } 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; } mTrueJump->mEntryBlocks.RemoveAll(this); mTrueJump->mNumEntries--; target->mEntryBlocks.Push(this); target->mNumEntries++; mTrueJump = target; } } } #endif assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size()); if (this->mTrueJump && this->mTrueJump->ValueForwarding(mNDataSet, global, final)) changed = true; if (this->mFalseJump && this->mFalseJump->ValueForwarding(mFDataSet, global, final)) changed = true; } return changed; } bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, bool full) { NativeCodeBasicBlock* lblock = proc->AllocateBlock(); NativeCodeBasicBlock* eblock = proc->AllocateBlock(); 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 = mExitRequiredRegs; eblock->mExitRequiredRegs = mExitRequiredRegs; 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::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; } } #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; } bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prevBlock, NativeCodeBasicBlock* exitBlock, bool full) { bool changed = false; if (mBranch == ASMIT_JMP) return false; assert(mEntryRequiredRegs.Size()); CheckLive(); 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]); 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 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); 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; 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; 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; 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++; } prevBlock->mIns.Push(mIns[si]); mIns.Remove(si); mEntryRequiredRegs += CPU_REG_Y; mExitRequiredRegs += CPU_REG_Y; 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); 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].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); mEntryRequiredRegs += CPU_REG_X; mExitRequiredRegs += CPU_REG_X; 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)) { 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); prevBlock->mIns.Push(mIns[si]); exitBlock->mIns.Insert(0, NativeCodeInstruction(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; mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; mIns.Insert(ei + 1, NativeCodeInstruction(t)); for (int i = 0; i < mIns.Size(); i++) mIns[i].mLive |= LIVE_CPU_REG_X; 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); 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); 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); 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); 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 (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); prevBlock->mIns.Push(mIns[0]); prevBlock->mIns.Push(mIns[1]); exitBlock->mIns.Insert(0, mIns[i + 0]); exitBlock->mIns.Insert(1, mIns[i + 1]); mIns.Remove(i); mIns.Remove(i); mIns.Remove(0); mIns.Remove(0); CheckLive(); return true; } } } int ai = 0; while (ai < mIns.Size() && !mIns[ai].ChangesAccu()) ai++; if (ai < mIns.Size() && !(mIns[ai].mLive & LIVE_CPU_REG_Z)) { if (mIns[ai].mType == ASMIT_LDA && mIns[ai].mMode == ASMIM_IMMEDIATE) { int i = ai + 1; while (i < mIns.Size() && !mIns[i].ChangesAccu()) i++; if (i == mIns.Size()) { if (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); 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 = ai + 1; while (i < mIns.Size() && !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); 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); changed = true; } } } ai = 0; while (ai < mIns.Size() && !mIns[ai].ChangesYReg()) ai++; if (ai < mIns.Size()) { if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_IMMEDIATE) { int i = ai + 1; while (i < mIns.Size() && !mIns[i].ChangesYReg()) i++; if (i == mIns.Size()) { if (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); for (int i = 0; i < mIns.Size(); i++) mIns[i].mLive |= LIVE_CPU_REG_Y; prevBlock->mIns.Push(mIns[ai]); mIns.Remove(ai); mEntryRequiredRegs += CPU_REG_Y; prevBlock->mExitRequiredRegs += CPU_REG_Y; changed = true; } } else if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_ZERO_PAGE && !(mIns[ai].mLive & LIVE_CPU_REG_Z)) { int i = 0; while (i < mIns.Size() && (i == ai || !mIns[i].ChangesYReg())) i++; if (i == mIns.Size()) { int addr = mIns[ai].mAddress; bool fail = false, changey = false; 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; 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(ASMIT_LDY, ASMIM_ZERO_PAGE, addr)); exitBlock->mIns.Push(NativeCodeInstruction(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; } } } } } } } if (mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_A]) { 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); prevBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress)); prevBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress)); mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; } } } } CheckLive(); 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_BCC && !mExitRequiredRegs[CPU_REG_C]) { NativeCodeBasicBlock* lb = mTrueJump; 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; changed = true; CheckLive(); } } else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE) { 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; 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; 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; changed = true; CheckLive(); } } else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE) { 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; 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; changed = true; CheckLive(); } } } } } } if (mTrueJump && mTrueJump->SimpleLoopReversal(proc)) changed = true; if (mFalseJump && mFalseJump->SimpleLoopReversal(proc)) 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(ASMIT_INX)); sz++; 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(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV); bool changed = false; int sz = mIns.Size(); assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); CheckLive(); #if 1 if (sz > 3 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A)) { if (mBranch == ASMIT_BCS && mIns[sz - 2].mAddress < 0xff) { int val = mIns[sz - 2].mAddress + 1; mBranch = ASMIT_BCC; mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val; } else if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff) { int val = mIns[sz - 2].mAddress + 1; mBranch = ASMIT_BCS; mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val; } 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; } } #endif if (mFalseJump == this) { mBranch = InvertBranchCondition(mBranch); mFalseJump = mTrueJump; mTrueJump = this; } if (sz == 2 && 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++; 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(ASMIT_TYA, ASMIM_IMPLIED)); else if (mIns[i].mType == ASMIT_LDY) { if (yinc > 0) lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY)); else if (yinc < 0) lblock->mIns.Push(NativeCodeInstruction(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(ASMIT_INY, ASMIM_IMPLIED)); linc++; } while (linc > 0) { lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); linc--; } lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_IMMEDIATE, limit)); lblock->mBranch = mBranch; lblock->mTrueJump = lblock; lblock->mFalseJump = eblock; eblock->mIns.Push(NativeCodeInstruction(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(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++; 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(ASMIT_TXA, ASMIM_IMPLIED)); else if (mIns[i].mType == ASMIT_LDX) { if (xinc > 0) lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX)); else if (xinc < 0) lblock->mIns.Push(NativeCodeInstruction(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(ASMIT_INX, ASMIM_IMPLIED)); linc++; } while (linc > 0) { lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); linc--; } lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, limit)); lblock->mBranch = mBranch; lblock->mTrueJump = lblock; lblock->mFalseJump = eblock; eblock->mIns.Push(NativeCodeInstruction(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(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; int zreg = mIns[sz - 1].mAddress; int yinc = 0, xinc = 0; 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 (!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(ASMIT_TYA, ASMIM_IMPLIED)); else if (mIns[i].mType == ASMIT_LDY) { if (yinc > 0) lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY)); else if (yinc < 0) lblock->mIns.Push(NativeCodeInstruction(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(ASMIT_CPY, ASMIM_IMMEDIATE, 0)); } else { while (linc < 0) { lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); linc++; } while (linc > 0) { lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); linc--; } } lblock->mBranch = mBranch; lblock->mTrueJump = lblock; lblock->mFalseJump = eblock; eblock->mIns.Push(NativeCodeInstruction(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(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 (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]; 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(ASMIT_TYA, ASMIM_IMPLIED)); else if (mIns[i].mType != ASMIT_LDY) lblock->mIns.Push(mIns[i]); } lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, lins)); lblock->mBranch = mBranch; lblock->mTrueJump = lblock; lblock->mFalseJump = eblock; eblock->mIns.Push(NativeCodeInstruction(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(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(ASMIT_TXA, ASMIM_IMPLIED)); else if (mIns[i].mType != ASMIT_LDX) lblock->mIns.Push(mIns[i]); } lblock->mIns.Push(NativeCodeInstruction(ASMIT_INX, ASMIM_IMPLIED)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPX, lins)); lblock->mBranch = mBranch; lblock->mTrueJump = lblock; lblock->mFalseJump = eblock; eblock->mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, zreg)); eblock->mBranch = ASMIT_JMP; eblock->mTrueJump = mFalseJump; eblock->mFalseJump = nullptr; mIns.SetSize(0); mIns.Push(NativeCodeInstruction(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) changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr, full); 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::OptimizeInnerLoop(NativeCodeProcedure* proc, NativeCodeBasicBlock* head, NativeCodeBasicBlock* tail, GrowingArray& 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_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(); 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(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; } } } tail->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); tail->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_IMMEDIATE, limit)); lblock->mBranch = head->mBranch; lblock->mTrueJump = head->mTrueJump; lblock->mFalseJump = head->mFalseJump; eblock->mIns.Push(NativeCodeInstruction(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(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; lblock->CheckLive(); return true; } else #endif if (!xother) { NativeCodeBasicBlock* lblock = proc->AllocateBlock(); NativeCodeBasicBlock* eblock = proc->AllocateBlock(); 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(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; } } } tail->mIns.Push(NativeCodeInstruction(ASMIT_INX, ASMIM_IMPLIED)); tail->mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, limit)); lblock->mBranch = head->mBranch; lblock->mTrueJump = head->mTrueJump; lblock->mFalseJump = head->mFalseJump; eblock->mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, zreg)); eblock->mBranch = ASMIT_JMP; eblock->mTrueJump = tail->mFalseJump; eblock->mFalseJump = nullptr; tail->mTrueJump = lblock; tail->mFalseJump = eblock; head->mIns.SetSize(0); head->mIns.Push(NativeCodeInstruction(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, GrowingArray& lblocks) { if (mLoopHeadBlock != head) { mLoopHeadBlock = head; lblocks.Push(this); if (mTrueJump != head && mFalseJump != head) { 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) { GrowingArray lblocks(nullptr); 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->mExitRequiredRegs; 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) { GrowingArray lblocks(nullptr); proc->ResetPatched(); if (CollectGenericLoop(proc, lblocks)) { int yreg = -1, xreg = -1; int zyreg[256], zxreg[256]; for (int i = 0; i < 256; i++) { zyreg[i] = 0; zxreg[i] = 0; } if (mEntryRequiredRegs[CPU_REG_Y]) yreg = -2; if (mEntryRequiredRegs[CPU_REG_X]) xreg = -2; for (int i = 0; i < lblocks.Size(); i++) { NativeCodeBasicBlock* block = lblocks[i]; int yoffset = 0, xoffset = 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; yoffset = 0; 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; xoffset = 0; break; case ASMIT_STY: if (ins.mMode == ASMIM_ZERO_PAGE) zxreg[ins.mAddress] = -1; break; case ASMIT_STX: if (ins.mMode == ASMIM_ZERO_PAGE) zyreg[ins.mAddress] = -1; break; case ASMIT_INY: yoffset++; break; case ASMIT_DEY: yoffset--; break; case ASMIT_INX: xoffset++; break; case ASMIT_DEX: xoffset--; break; case ASMIT_INC: case ASMIT_DEC: if (ins.mMode == ASMIM_ZERO_PAGE) { if (zxreg[ins.mAddress] >= 0) zxreg[ins.mAddress] += 3; if (zyreg[ins.mAddress] >= 0) zyreg[ins.mAddress] += 3; } break; case ASMIT_LDA: if (ins.mMode == ASMIM_ZERO_PAGE) { 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]++; } 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; break; case ASMIT_TXA: if (xoffset) xreg = -2; break; case ASMIT_TAY: yreg = -2; break; case ASMIT_TAX: xreg = -2; break; case ASMIT_JSR: yreg = -2; xreg = -2; 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; } break; default: if (ins.mMode == ASMIM_ZERO_PAGE) { zxreg[ins.mAddress] = -1; zyreg[ins.mAddress] = -1; } } if (!(ins.mLive & LIVE_CPU_REG_Y)) yoffset = 0; if (!(ins.mLive & LIVE_CPU_REG_X)) xoffset = 0; if (ins.mMode == ASMIM_INDIRECT_Y) { zxreg[ins.mAddress] = -1; zyreg[ins.mAddress] = -1; zxreg[ins.mAddress + 1] = -1; zyreg[ins.mAddress + 1] = -1; } } #if 1 if (yoffset && block->mExitRequiredRegs[CPU_REG_Y]) yreg = -2; if (xoffset && block->mExitRequiredRegs[CPU_REG_X]) xreg = -2; #endif } 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) { GrowingArray entries(nullptr); GrowingArray exits(nullptr); 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 (block->mTrueJump && !lblocks.Contains(block->mTrueJump)) { block->mTrueJump = block->BuildSingleEntry(proc, block->mTrueJump); if (yreg >= 0 && block->mTrueJump->mEntryRequiredRegs[yreg]) { block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); block->mTrueJump->mEntryRequiredRegs += CPU_REG_Y; } if (xreg >= 0 && block->mTrueJump->mEntryRequiredRegs[xreg]) { block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); block->mTrueJump->mEntryRequiredRegs += CPU_REG_X; } } if (block->mFalseJump && !lblocks.Contains(block->mFalseJump)) { block->mFalseJump = block->BuildSingleEntry(proc, block->mFalseJump); if (yreg >= 0 && block->mFalseJump->mEntryRequiredRegs[yreg]) { block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); block->mFalseJump->mEntryRequiredRegs += CPU_REG_Y; } if (xreg >= 0 && block->mFalseJump->mEntryRequiredRegs[xreg]) { block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); block->mFalseJump->mEntryRequiredRegs += CPU_REG_X; } } 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 (yreg >= 0 && mEntryRequiredRegs[yreg]) { block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, yreg)); block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Y; } if (xreg >= 0 && mEntryRequiredRegs[xreg]) { block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, xreg)); block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_X; } } } int yoffset = 0, xoffset = 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.mAddress == yreg) { ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED; yoffset = 0; } break; case ASMIT_LDX: case ASMIT_STX: if (ins.mAddress == xreg) { ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED; xoffset = 0; } break; case ASMIT_INC: if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) { ins.mType = ASMIT_INY; ins.mMode = ASMIM_IMPLIED; } else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) { ins.mType = ASMIT_INX; ins.mMode = ASMIM_IMPLIED; } break; case ASMIT_DEC: if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) { ins.mType = ASMIT_DEY; ins.mMode = ASMIM_IMPLIED; } else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) { ins.mType = ASMIT_DEX; ins.mMode = ASMIM_IMPLIED; } break; case ASMIT_LDA: 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 == 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; } if (yoffset && yreg >= 0 && !(ins.mLive & LIVE_CPU_REG_Y)) { while (yoffset > 0) { j++; block->mIns.Insert(j, NativeCodeInstruction(ASMIT_DEY)); yoffset--; } while (yoffset < 0) { j++; block->mIns.Insert(j, NativeCodeInstruction(ASMIT_INY)); yoffset++; } if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag()) block->mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_IMMEDIATE, 0)); } if (xoffset && xreg >= 0 && !(ins.mLive & LIVE_CPU_REG_X)) { while (xoffset > 0) { j++; block->mIns.Insert(j, NativeCodeInstruction(ASMIT_DEX)); xoffset--; } while (xoffset < 0) { j++; block->mIns.Insert(j, NativeCodeInstruction(ASMIT_INX)); xoffset++; } if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag()) block->mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_IMMEDIATE, 0)); } if (yreg >= 0) ins.mLive |= LIVE_CPU_REG_Y; if (xreg >= 0) ins.mLive |= LIVE_CPU_REG_X; } block->CheckLive(); } changed = true; } } } mVisited = true; if (mTrueJump && mTrueJump->OptimizeGenericLoop(proc)) changed = true; if (mFalseJump && mFalseJump->OptimizeGenericLoop(proc)) changed = true; } return changed; } void NativeCodeBasicBlock::CollectReachable(GrowingArray& lblock) { if (!mVisited && !mPatched) { lblock.Push(this); mPatched = true; if (mTrueJump) mTrueJump->CollectReachable(lblock); if (mFalseJump) mFalseJump->CollectReachable(lblock); } } bool NativeCodeBasicBlock::CollectGenericLoop(NativeCodeProcedure* proc, GrowingArray& lblocks) { GrowingArray rblocks(nullptr); 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::OptimizeFindLoop(NativeCodeProcedure* proc) { bool changed = false; if (!mVisited) { mVisited = true; CheckLive(); if (mLoopHead && mNumEntries == 2) { if (mTrueJump && mFalseJump && mFalseJump->mNumEntries == 1 && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == this && mTrueJump->mNumEntries == 1) { NativeCodeBasicBlock * pred = mEntryBlocks[0]; if (pred == mFalseJump) pred = mEntryBlocks[0]; NativeCodeBasicBlock * succ = mTrueJump; NativeCodeBasicBlock * body = 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(ASMIT_STY, mIns[0])); body->mIns[fsz - 1].mType = ASMIT_INY; body->mIns[fsz - 1].mMode = ASMIM_IMPLIED; mIns.Remove(0); 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; } } } } } } 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.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, vt ^ vf)); mIns.Push(NativeCodeInstruction(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 GrowingArray& 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->mGenerator->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)) { if (si + 1 < mIns.Size() && mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) && mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE)) { int i = 1; while (si + 2 * i + 1 < mIns.Size() && mIns[si + 2 * i + 0].mType == ASMIT_LDA && mIns[si + 2 * i + 0].mMode == mIns[si + 0].mMode && mIns[si + 2 * i + 0].mAddress == mIns[si + 0].mAddress + i && mIns[si + 2 * i + 1].mType == ASMIT_STA && mIns[si + 2 * i + 1].mMode == mIns[si + 1].mMode && mIns[si + 2 * i + 1].mAddress == mIns[si + 1].mAddress + i && !(mIns[si + 2 * i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { i++; } if (i > 2) { if (!(mIns[si + 0].mLive & LIVE_CPU_REG_X)) { int k = 1; while (CheckBlockCopySequence(mIns, si + 2 * k * i, i)) k++; int sz = 3 + 4 * k; for (int j = 0; j < k; j++) { NativeCodeInstruction lins = mIns[si + 2 * i * j + 0]; NativeCodeInstruction sins = mIns[si + 2 * i * j + 1]; if (lins.mMode == ASMIM_ZERO_PAGE) lins.mMode = ASMIM_ZERO_PAGE_X; else { lins.mMode = ASMIM_ABSOLUTE_X; sz++; } if (sins.mMode == ASMIM_ZERO_PAGE) sins.mMode = ASMIM_ZERO_PAGE_X; else { sins.mMode = ASMIM_ABSOLUTE_X; sz++; } if (j == 0) mIns[di++] = NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, i - 1); mIns[di++] = lins; mIns[di++] = sins; } mIns[di++] = NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED); mIns[di++] = NativeCodeInstruction(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(ASMIT_LDX, ASMIM_IMMEDIATE, i - 1); mIns[di++] = lins; mIns[di++] = sins0; mIns[di++] = sins1; mIns[di++] = NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED); mIns[di++] = NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -sz); si += 3 * i; return true; } } } } return false; } // Size reduction violating various assumptions such as no branches in basic blocks // must be last step before actual assembly void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc, int xenter, int yenter) { if (!mVisited) { mVisited = true; CheckLive(); int i = 0; int j = 0; if (mEntryBlocks.Size() == 1 && mEntryBlocks[0]->mIns.Size() > 0 && mIns.Size() > 0 && mIns[0].mType == ASMIT_CMP && mIns[0].mMode == ASMIM_IMMEDIATE && mEntryBlocks[0]->mIns.Last().mType == ASMIT_CMP && mEntryBlocks[0]->mIns.Last().mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == mEntryBlocks[0]->mIns.Last().mAddress) { // Skip initial compare if same as last of entry block i++; } while (i < mIns.Size()) { if (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].mAddress == mIns[i + 1].mAddress && 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].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_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; 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].mAddress == mIns[i + 1].mAddress && 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].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_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; 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].mAddress == mIns[i + 0].mAddress && 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].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_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; 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].mAddress == mIns[i + 0].mAddress && 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].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_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; 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_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; 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; 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_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 && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) { mIns[j + 0] = NativeCodeInstruction(ASMIT_LDX, mIns[i + 1]); mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED; mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; mIns[j + 2].mLinkerObject = nullptr; 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 && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) { mIns[j + 0] = NativeCodeInstruction(ASMIT_LDX, mIns[i + 1]); mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED; mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; mIns[j + 2].mLinkerObject = nullptr; 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 == 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 == 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(ASMIT_SEC); mIns[j + 1] = mIns[i + 3]; j += 2; i += 4; } #endif else if (i + 1 < mIns.Size() && mIns[i + 0].ChangesZFlag() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_A)) { mIns[j++] = mIns[i++]; i++; } else if (BlockSizeCopyReduction(proc, i, j)) { } else mIns[j++] = mIns[i++]; } mIns.SetSize(j); #if 1 bool yimm = false, ximm = false, aimm = false, afail = false; int yval = 0, xval = 0, aval = 0; if (mNumEntries == 1) { if (yenter >= 0) { yval = yenter; yimm = true; } if (xenter >= 0) { xval = xenter; ximm = true; } } for(int i = 0; i < mIns.Size(); i++) { if (afail) aimm = false; if (mIns[i].mType == ASMIT_LDA) { if (mIns[i].mMode == ASMIM_IMMEDIATE) { if (yimm && mIns[i].mAddress == yval) { mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED; } else if (ximm && mIns[i].mAddress == xval) { mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED; } aimm = true; aval = mIns[i].mAddress; } else aimm = false; } else if (mIns[i].mType == ASMIT_TYA) { if (yimm) { aimm = true; aval = yval; } else aimm = false; } else if (mIns[i].mType == ASMIT_TXA) { if (ximm) { aimm = true; aval = xval; } else aimm = false; } else if (mIns[i].mType == ASMIT_LDY) { if (mIns[i].mMode == ASMIM_IMMEDIATE) { if (yimm && mIns[i].mAddress == ((yval + 1) & 0xff)) { yval = mIns[i].mAddress; mIns[i].mType = ASMIT_INY; mIns[i].mMode = ASMIM_IMPLIED; } else if (yimm && mIns[i].mAddress == ((yval - 1) & 0xff)) { yval = mIns[i].mAddress; mIns[i].mType = ASMIT_DEY; mIns[i].mMode = ASMIM_IMPLIED; } else if (aimm && mIns[i].mAddress == aval) { mIns[i].mType = ASMIT_TAY; mIns[i].mMode = ASMIM_IMPLIED; yimm = true; yval = aval; } else { yimm = true; yval = mIns[i].mAddress; } } else yimm = false; } else if (yimm && mIns[i].mType == ASMIT_INY) { yval = (yval + 1) & 0xff; } else if (yimm && mIns[i].mType == ASMIT_DEY) { yval = (yval - 1) & 0xff; } else if (mIns[i].mType == ASMIT_TAY) { if (aimm) { yimm = true; yval = aval; } else yimm = false; } else if (mIns[i].mType == ASMIT_LDX) { if (mIns[i].mMode == ASMIM_IMMEDIATE) { if (ximm && mIns[i].mAddress == ((xval + 1) & 0xff)) { xval = mIns[i].mAddress; mIns[i].mType = ASMIT_INX; mIns[i].mMode = ASMIM_IMPLIED; } else if (ximm && mIns[i].mAddress == ((xval - 1) & 0xff)) { xval = mIns[i].mAddress; mIns[i].mType = ASMIT_DEX; mIns[i].mMode = ASMIM_IMPLIED; } else if (aimm && mIns[i].mAddress == aval) { mIns[i].mType = ASMIT_TAX; mIns[i].mMode = ASMIM_IMPLIED; ximm = true; xval = aval; } else { ximm = true; xval = mIns[i].mAddress; } } else ximm = false; } else if (ximm && mIns[i].mType == ASMIT_INX) { xval = (xval + 1) & 0xff; } else if (ximm && mIns[i].mType == ASMIT_DEX) { xval = (xval - 1) & 0xff; } else if (mIns[i].mType == ASMIT_TAX) { if (aimm) { ximm = true; xval = aval; } else ximm = false; } else if (mIns[i].mType == ASMIT_JSR) yimm = ximm = aimm = false; else if (mIns[i].mMode == ASMIM_RELATIVE) { if (mIns[i].mAddress < 0) yimm = ximm = aimm = false; else afail = true; } else if (mIns[i].ChangesAccu()) aimm = false; } #endif bool carrySet = false, carryClear = false; if (mEntryBlocks.Size() > 0) { carrySet = true; carryClear = true; } for (int i = 0; i < mEntryBlocks.Size(); i++) { if (mEntryBlocks[i]->mBranch == ASMIT_BCC) { if (mEntryBlocks[i]->mTrueJump == this) carrySet = false; else carryClear = false; } else if (mEntryBlocks[i]->mBranch == ASMIT_BCS) { if (mEntryBlocks[i]->mTrueJump == this) carryClear = false; else carrySet = false; } else carryClear = carrySet = false; } #if 1 i = 0; j = 0; int accuVal = 0, accuMask = 0; bool accuFlags = false; while (i < mIns.Size()) { bool skip = false; switch (mIns[i].mType) { case ASMIT_CLC: if (carryClear) skip = true; else if (carrySet && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress > 0) { // convert CLC before const add into SEC and reduce immediate skip = true; mIns[i + 2].mAddress--; } else { carryClear = true; carrySet = false; } break; case ASMIT_SEC: if (carrySet) skip = true; else { carryClear = false; carrySet = true; } break; case ASMIT_ADC: case ASMIT_SBC: accuMask = 0; accuFlags = true; carryClear = false; carrySet = false; break; case ASMIT_CMP: carryClear = false; carrySet = false; accuFlags = false; break; case ASMIT_AND: if (mIns[i].mMode == ASMIM_IMMEDIATE) { int clear = mIns[i].mAddress ^ 0xff; if (mIns[i].mAddress == 0xff && accuFlags) skip = true; else if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && !(clear & (accuMask ^ 0xff)) && !(accuVal & clear)) skip = true; else accuFlags = true; accuVal &= ~clear; accuMask |= clear; } else { accuMask = 0; accuFlags = true; } break; case ASMIT_ORA: if (mIns[i].mMode == ASMIM_IMMEDIATE) { int set = mIns[i].mAddress; if (mIns[i].mAddress == 0 && accuFlags) skip = true; else if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && !(set & (accuMask ^ 0xff)) && !(~accuVal & set)) skip = true; else accuFlags = true; accuVal |= set; accuMask |= set; } else { accuMask = 0; accuFlags = true; } break; case ASMIT_LDA: if (mIns[i].mMode == ASMIM_IMMEDIATE) { accuVal = mIns[i].mAddress; accuMask = 0xff; } else accuMask = 0x00; accuFlags = true; break; case ASMIT_ASL: if (mIns[i].mMode == ASMIM_IMPLIED) { accuVal <<= 1; accuMask = (accuMask << 1) | 1; if (accuMask & 0x100) { if (accuVal & 0x100) { carryClear = false; carrySet = true; } else { carryClear = true; carrySet = false; } } else { carryClear = false; carrySet = false; } accuMask &= 0xff; accuVal &= 0xff; } else { carryClear = false; carrySet = false; } accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_LSR: if (mIns[i].mMode == ASMIM_IMPLIED) { if (accuMask & 0x01) { if (accuVal & 0x01) { carryClear = false; carrySet = true; } else { carryClear = true; carrySet = false; } } else { carryClear = false; carrySet = false; } accuVal >>= 1; accuMask = (accuMask >> 1) | 0x80; } else { carryClear = false; carrySet = false; } accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_ROL: if (mIns[i].mMode == ASMIM_IMPLIED) { accuVal <<= 1; accuMask <<= 1; if (accuMask & 0x100) { if (accuVal & 0x100) { carryClear = false; carrySet = true; } else { carryClear = true; carrySet = false; } } else { carryClear = false; carrySet = false; } accuVal &= 0xff; accuMask &= 0xff; } else { carryClear = false; carrySet = false; } accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_ROR: if (mIns[i].mMode == ASMIM_IMPLIED) { if (accuMask & 0x01) { if (accuVal & 0x01) { carryClear = false; carrySet = true; } else { carryClear = true; carrySet = false; } } else { carryClear = false; carrySet = false; } accuVal >>= 1; accuMask >>= 1; } else { carryClear = false; carrySet = false; } accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_TAX: case ASMIT_TAY: accuFlags = true; break; default: if (mIns[i].ChangesCarry()) { carryClear = false; carrySet = false; } if (mIns[i].ChangesAccu()) { accuMask = 0; accuFlags = false; } else if (mIns[i].ChangesZFlag()) { accuFlags = false; } } if (!skip) { if (i != j) mIns[j] = mIns[i]; j++; } i++; } mIns.SetSize(j); #endif if (mTrueJump) mTrueJump->BlockSizeReduction(proc, ximm ? xval : -1, yimm ? yval: -1); if (mFalseJump) mFalseJump->BlockSizeReduction(proc, ximm ? xval : -1, yimm ? yval : -1); } } bool NativeCodeBasicBlock::ReferencesAccu(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ReferencesAccu()) return true; return false; } bool NativeCodeBasicBlock::ReferencesYReg(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ReferencesYReg()) return true; return false; } bool NativeCodeBasicBlock::ReferencesXReg(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ReferencesXReg()) return true; return false; } bool NativeCodeBasicBlock::ChangesAccu(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ChangesAccu()) return true; return false; } bool NativeCodeBasicBlock::ChangesYReg(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ChangesYReg()) return true; return false; } bool NativeCodeBasicBlock::ChangesXReg(int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ChangesXReg()) return true; return false; } bool NativeCodeBasicBlock::ChangesZeroPage(int address, int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].ChangesZeroPage(address)) return true; return false; } bool NativeCodeBasicBlock::UsesZeroPage(int address, int from) const { for (int i = from; i < mIns.Size(); i++) if (mIns[i].UsesZeroPage(address)) return true; return false; } bool NativeCodeBasicBlock::ReferencesZeroPage(int address, int from) const { for (int i = from; i < mIns.Size(); 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::PeepHoleOptimizer(NativeCodeProcedure* proc, 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(); mVisited = true; CheckLive(); if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); #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 #if 1 // Combine ADC with immediate for (int i = 4; i + 1 < mIns.Size(); i++) { if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { if (CombineImmediateADCUp(i)) changed = true; } else if (mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_X) && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { if (CombineImmediateADCUpX(i)) changed = true; } } CheckLive(); #endif #if 1 // move load store pairs up to initial store for (int i = 2; i + 1 < mIns.Size(); i++) { if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) { if (MoveLoadStoreXUp(i)) changed = true; } } CheckLive(); #endif // move sta zp, tax, lda abs,x , sta zp down to use #if 1 for (int i = 0; i + 4 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_TAX && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) { if (MoveStaTaxLdaStaDown(i)) changed = true; } } CheckLive(); #endif #if 1 // move load - store (),y up to initial store // for (int i = 2; i + 2 < mIns.Size(); i++) { if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y) { if (MoveIndirectLoadStoreUp(i)) changed = true; } } CheckLive(); #endif #if 1 // move load (),y store zp down to potential user for (int i = 0; i + 2 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mFlags & NICT_ZPFLIPPED) && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { if (MoveLoadIndirectTempStoreUp(i)) changed = true; } else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { if (MoveIndirectLoadStoreDown(i)) changed = true; } #if 1 if (pass > 0 && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { if (MoveIndirectLoadStoreDownY(i)) changed = true; } #endif } CheckLive(); #endif #if 1 // move load (),y store zp up to potential user for (int i = 4; i + 1 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y))) { if (MoveLoadIndirectBypassYUp(i)) changed = true; } } CheckLive(); #endif #if 1 // 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)) { 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) && !(mIns[i + 1].mFlags & NCIF_VOLATILE)) { 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 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 && (mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0) { if (MoveCLCLoadAddZPStoreUp(i)) changed = true; } 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; } #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 // 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 // // shorten x/y register livetime #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)) { 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)) { if (mIns[i].mMode != ASMIM_ABSOLUTE_Y || !mIns[i + 1].ChangesYReg()) { if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1])) { if (mIns[i + 1].SameEffectiveAddress(mIns[i])) mIns[i + 1].mLive |= LIVE_MEM; NativeCodeInstruction ins = mIns[i]; mIns[i] = mIns[i + 1]; mIns[i].mLive &= ~LIVE_CPU_REG_X; mIns[i + 1] = ins; mIns[i + 1].mLive |= mIns[i].mLive; if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y) mIns[i].mLive |= LIVE_CPU_REG_Y; } } } } #endif } CheckLive(); #endif #if 1 // move stx up for (int i = 1; i < mIns.Size(); i++) { if (!(mIns[i].mFlags & NCIF_VOLATILE)) { if (mIns[i].mType == ASMIT_STX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE)) { if (MoveStoreXUp(i)) changed = true; } else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) { if (MoveLoadXUp(i)) changed = true; } else if (mIns[i].mType == ASMIT_STY && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE)) { if (i > 1 || mIns[0].mType != ASMIT_STX) { if (MoveStoreYUp(i)) changed = true; } } else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) { if (MoveLoadYUp(i)) changed = true; } } } CheckLive(); #endif #if 1 // move ldy, sty down if live for (int i = 0; i + 2 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) && mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && (mIns[i + 2].mLive & LIVE_CPU_REG_Y)) { int j = i; while (j + 2 < mIns.Size() && !mIns[j + 2].ReferencesYReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z)) { mIns[j + 0].mLive |= mIns[j + 2].mLive; mIns[j + 1].mLive |= mIns[j + 2].mLive; mIns[j + 2].mLive &= ~LIVE_CPU_REG_Y; mIns.Insert(j, mIns[j + 2]); mIns.Remove(j + 3); j++; } } else if (mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) && mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && (mIns[i + 2].mLive & LIVE_CPU_REG_X)) { int j = i; while (j + 2 < mIns.Size() && !mIns[j + 2].ReferencesXReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z)) { mIns[j + 0].mLive |= mIns[j + 2].mLive; mIns[j + 1].mLive |= mIns[j + 2].mLive; mIns[j + 2].mLive &= ~LIVE_CPU_REG_X; mIns.Insert(j, mIns[j + 2]); mIns.Remove(j + 3); j++; } } } #endif #if 1 // move clc and sec down for (int i = 0; i + 1 < mIns.Size(); i++) { if ((mIns[i].mType == ASMIT_CLC || mIns[i].mType == ASMIT_SEC) && !mIns[i + 1].RequiresCarry() && !mIns[i + 1].ChangesCarry()) { if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && mIns[i + 2].RequiresCarry()) ; else if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mMode == ASMIM_INDIRECT_Y) ; else { NativeCodeInstruction pins = mIns[i]; mIns[i] = mIns[i + 1]; mIns[i + 1] = pins; mIns[i + 1].mLive |= mIns[i].mLive; // changed = true; } } } CheckLive(); #endif #if 1 // move iny/dey/inx/dex down for (int i = 0; i + 1 < mIns.Size(); i++) { if ((mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY) && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z)) { if (!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 (!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 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 taxPos = -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; for (int k = 0; k < j; k += 2) { mIns[i + k + 0] = NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED); mIns[i + k + 1] = NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, addrl); } mIns[i + j] = NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, addrh); mIns[i + j + 1].mType = ASMIT_NOP; mIns[i + j + 1].mMode = ASMIM_IMPLIED; mIns[i + j + 2].mType = ASMIT_NOP; mIns[i + j + 2].mMode = ASMIM_IMPLIED; changed = true; } } } CheckLive(); #endif #if 1 for (int i = 0; i + 4 < mIns.Size(); i++) { if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress >= -2 && mIns[i + 2].mAddress <= 2 || mIns[i + 2].mAddress >= 254 && mIns[i + 2].mAddress < 256) && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) { if (MoveTXADCDown(i)) changed = true; } } CheckLive(); #endif #if 1 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 1 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; } } #endif 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 1 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; } } #endif for (int i = 0; i < mIns.Size(); i++) { #if 1 #if 1 if (mIns[i].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0) { mIns[i].mType = ASMIT_LDA; progress = 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;; progress = true; } else if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0xff) { mIns[i].mType = ASMIT_LDA; progress = 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;; progress = 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;; progress = 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; progress = 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; progress = true; } #endif #if 1 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; progress = true; } #endif #if 1 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 1 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; } if (mIns[i + 0].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 1, 0); // mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); // mIns[i + 1].mLive |= LIVE_CPU_REG_Y; } mIns.Insert(i + 0, NativeCodeInstruction(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(); } #endif } #if 1 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)) { if (mIns[i + 0].mLive & LIVE_CPU_REG_Y) { if (mIns[i + 0].mLive & LIVE_CPU_REG_Z) { mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); mIns[i + 1].mLive |= LIVE_CPU_REG_Y; mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_ORA, ASMIM_IMMEDIATE, 0)); mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z; } else { InsertLoadYImmediate(i + 1, 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(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(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(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(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(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(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(); } } #endif else if (FindExternAddressSumY(i, sreg, breg, ireg)) { #if 1 if (mIns[i + 0].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 1, 0); // mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); // mIns[i + 1].mLive |= LIVE_CPU_REG_Y; } mIns.Insert(i + 0, NativeCodeInstruction(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(); #endif } #if 1 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(ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i].mAddress)); mIns[i + 0].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_X; 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(); } } #endif } #endif CheckLive(); #if 1 if (i + 1 < mIns.Size()) { if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_LDA) { mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;; progress = 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;; progress = 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 + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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 + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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++; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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(ASMIT_TAY, ASMIM_IMPLIED)); mIns[i + 2].mLive = mIns[i + 1].mLive; mIns[i + 1].mLive |= LIVE_CPU_REG_A; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } #if 1 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } #endif 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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 + 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; progress = 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 + 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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++; progress = 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++; progress = 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; progress = 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; progress = 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; mIns[i + 0].mAddress = (mIns[i + 0].mAddress >> 1) & 0x7f; mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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; mIns[i + 0].mAddress = (mIns[i + 0].mAddress << 1) & 0xfe; mIns[i + 1].mType = ASMIT_ROR; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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; progress = 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; progress = 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)) { if (mIns[i + 1].mLive & LIVE_CPU_REG_Y) { if (mIns[i + 1].mLive & LIVE_CPU_REG_Z) { mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, mIns[i + 0].mAddress)); mIns[i + 2].mLive |= LIVE_CPU_REG_Y; mIns.Insert(i + 3, NativeCodeInstruction(ASMIT_ORA, ASMIM_IMMEDIATE, 0)); mIns[i + 3].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z; } else { InsertLoadYImmediate(i + 2, 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(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(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(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(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(); progress = true; } } } CheckLive(); #if 1 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]); 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; progress = true; CheckLive(); } } #endif #if 1 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)) { progress = true; CheckLive(); } } } #endif #if 1 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) { const NativeCodeInstruction* ains, * iins; int sreg = mIns[i + 0].mAddress; int apos, breg, ireg; uint32 flags; 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; } if (mIns[i + 1].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 2, 0); // mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); // mIns[i + 2].mLive |= LIVE_CPU_REG_Y; } mIns.Insert(i + 0, NativeCodeInstruction(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; progress = true; CheckLive(); } } } #endif #if 1 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; } if (mIns[i + 1].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 2, 0); // mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yoffset)); // mIns[i + 2].mLive |= LIVE_CPU_REG_Y; } mIns[i + 0].mMode = ASMIM_ZERO_PAGE; mIns[i + 0].mAddress = ireg; mIns[i + 0].mLive |= LIVE_MEM; mIns[i + 1].mAddress = breg; for(int j=0; j= 256) mIns[i + 0].mType = ASMIT_SEC; progress = true; } else if ( 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; progress = true; } else 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 == 0) { mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = 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; progress = 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; progress = 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; progress = true; } else if ( mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 && mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x80 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) { mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = true; } 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } else if ( mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 && mIns[i + 1].mType == ASMIT_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; progress = true; } #if 1 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; progress = true; } #endif 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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 + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM)) { 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; progress = 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; progress = 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; progress = 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(ASMIT_LDA, ASMIM_ZERO_PAGE, addr)); mIns.Insert(i + 4, NativeCodeInstruction(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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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 + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = 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 + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = 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; progress = 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; progress = 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; progress = 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); progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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); progress = 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; } if (mIns[i + 2].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 3, yoffset); // mIns.Insert(i + 3, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yoffset)); // mIns[i + 3].mLive |= LIVE_CPU_REG_Y; } 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(ASMIT_LDY, ASMIM_ZERO_PAGE, ireg)); mIns[i + 2].mLive = mIns[i + 3].mLive | LIVE_CPU_REG_Y | LIVE_MEM; ypos = i + 2; mIns[i + 3].mAddress = breg; } if (yoffset == 1) { mIns.Insert(ypos + 1, NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); mIns[ypos + 1].mLive = mIns[ypos].mLive; } progress = 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(ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 2].mAddress)); mIns[i + 2].mLive = mIns[i + 3].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; } progress = true; } } } #endif CheckLive(); #if 1 if (i + 3 < mIns.Size()) { 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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 + 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; progress = 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; progress = 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; } progress = true; } else if ( mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].UsesZeroPage(mIns[i + 3].mAddress)) { mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns.Insert(i + 1, NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 3].mAddress)); mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; progress = 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; progress = 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 + 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; progress = 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 + 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; } progress = 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 + 3].mType = ASMIT_ADC; mIns[i + 3].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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 + 3].mType = ASMIT_ADC; mIns[i + 3].mAddress = mIns[i + 2].mAddress; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = 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 + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = 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; progress = 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; progress = 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; progress = true; } else if ( mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress && mIns[i + 3].mAddress && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & LIVE_MEM) && (mIns[i + 2].mType == ASMIT_ASL || mIns[i + 2].mType == ASMIT_LSR || mIns[i + 2].mType == ASMIT_ROL || mIns[i + 2].mType == ASMIT_ROR) && (mIns[i + 3].mType == ASMIT_ORA || mIns[i + 3].mType == ASMIT_AND || mIns[i + 3].mType == ASMIT_EOR || mIns[i + 3].mType == ASMIT_ADC || mIns[i + 3].mType == ASMIT_SBC)) { mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 3].mMode = mIns[i + 0].mMode; mIns[i + 3].mAddress = mIns[i + 0].mAddress; mIns[i + 3].mLinkerObject = mIns[i + 0].mLinkerObject; mIns[i + 3].mFlags = mIns[i + 0].mFlags; if (mIns[i + 3].RequiresYReg()) { mIns[i + 0].mLive |= LIVE_CPU_REG_Y; mIns[i + 2].mLive |= LIVE_CPU_REG_Y; } if (mIns[i + 3].RequiresXReg()) { mIns[i + 0].mLive |= LIVE_CPU_REG_X; mIns[i + 2].mLive |= LIVE_CPU_REG_X; } progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } #if 1 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; progress = true; } #endif 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } #if 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 && 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; progress = 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; progress = true; } #endif #if 1 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; progress = 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; progress = true; } #endif 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } #if 1 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; progress = true; } #endif #if 1 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; progress = true; } #endif #if 1 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; progress = 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; progress = 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].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; progress = true; } #endif #if 1 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; progress = 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; progress = true; } #endif #if 1 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; progress = 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(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; progress = true; } #endif 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; progress = 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; progress = 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; } if (mIns[i + 3].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 4, 0); // mIns.Insert(i + 4, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); // mIns[i + 4].mLive |= LIVE_CPU_REG_Y; } 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; progress = true; } } } #endif CheckLive(); #if 1 if (i + 4 < mIns.Size()) { 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].mMode = ASMIM_ZERO_PAGE; mIns[i + 2].mAddress = mIns[i + 0].mAddress; progress = 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; mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mLive |= LIVE_CPU_REG_A; progress = 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; mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mLive |= LIVE_CPU_REG_A; progress = 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]); } progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = 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; } if (mIns[i + 4].mLive & LIVE_CPU_REG_Y) { InsertLoadYImmediate(i + 5, 0); // mIns.Insert(i + 5, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); // mIns[i + 5].mLive |= LIVE_CPU_REG_Y; } 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; progress = 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; progress = 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; progress = 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; progress = 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; progress = true; } } #if 1 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; progress = 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 + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; progress = 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 + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; progress = true; } #endif } #endif CheckLive(); #if 1 if (i + 3 < mIns.Size()) { 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++; progress = 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; progress = 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++; progress = 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; progress = true; } } CheckLive(); if (i + 4 < 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_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; progress = 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; progress = 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; progress = true; } #if 1 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(ASMIT_STA, ASMIM_ZERO_PAGE, a1)); mIns.Insert(i + 1, NativeCodeInstruction(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; progress = true; } #endif #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; progress = true; } #endif } CheckLive(); #if 1 if (pass > 2 && i + 4 < mIns.Size()) { 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; progress = 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; progress = true; } } #endif CheckLive(); if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); #if 1 if (pass < 7 && 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].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))) { proc->ResetPatched(); if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n)) { proc->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].mFlags & NCIF_VOLATILE) n = 1; if (mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)) n--; if (n > 0) { proc->ResetPatched(); if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n)) { proc->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) { proc->ResetPatched(); if (CheckSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1], 2)) { proc->ResetPatched(); if (PatchSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1])) progress = true; CheckLive(); if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); } } } #endif CheckLive(); if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); if (i + 5 < mIns.Size()) { 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; progress = true; } #if 1 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; progress = 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; progress = true; } #endif 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; progress = 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)) { proc->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; proc->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)) progress = true; } } #endif #if 1 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)) { proc->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; proc->ResetPatched(); if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, 256 * mIns[i + 3].mAddress)) progress = true; } } #endif #if 1 else if (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)) { proc->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; proc->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) { proc->ResetPatched(); if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1)) { proc->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 (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(ASMIT_DEY)); progress = 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; progress = 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; progress = 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)) { proc->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; proc->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)) progress = true; } else if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress) { proc->ResetPatched(); if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1)) { proc->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)) progress = 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)) { proc->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; proc->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)) progress = true; } else if (mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 3].mAddress) { proc->ResetPatched(); if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, i + 7, -1)) { proc->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)) progress = 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)) { proc->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; proc->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)) progress = 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)) { proc->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; proc->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)) progress = 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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) { proc->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; progress = true; if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); } } } #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 + 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_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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) { proc->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; progress = true; } if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); } } #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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval)) progress = true; 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(); } } #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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval)) progress = true; 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(); } } #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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) progress = true; 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(); } } #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); proc->ResetPatched(); if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) progress = true; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; if (mTrueJump) mTrueJump->CheckLive(); if (mFalseJump) mFalseJump->CheckLive(); } } #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; } progress = true; } } #endif } #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(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(); #endif #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 #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(); int sz = mIns.Size(); #if 1 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; } } } #endif 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 >= 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 = proc->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; 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 >= 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 = proc->AllocateBlock(); tblock->mTrueJump = mTrueJump->mFalseJump; tblock->mFalseJump = mTrueJump->mTrueJump; tblock->mBranch = ASMIT_BMI; tblock->mTrueJump->mNumEntries++; tblock->mTrueJump->mEntryBlocks.Push(tblock); tblock->mFalseJump->mNumEntries++; tblock->mFalseJump->mEntryBlocks.Push(tblock); mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this)); mTrueJump->mNumEntries--; mTrueJump = tblock; tblock->mNumEntries++; tblock->mEntryBlocks.Push(this); mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED; mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED; mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED; mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; CheckLive(); } } else if (sz >= 3 && mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 && mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x01 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C]) { if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) { mIns.SetSize(sz - 3); sz -= 3; changed = true; } } else if (sz >= 2 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 && mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z]) { if (mBranch == ASMIT_BNE) { mBranch = ASMIT_BCC; mIns.SetSize(sz - 2); changed = true; } else if (mBranch == ASMIT_BEQ) { mBranch = ASMIT_BCS; mIns.SetSize(sz - 2); changed = true; } sz -= 2; CheckLive(); } else if (pass >= 7 && sz >= 2 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 2].mLive & LIVE_MEM) && mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z]) { if (mBranch == ASMIT_BNE) { mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C; mBranch = ASMIT_BCS; mIns.SetSize(sz - 1); changed = true; } else if (mBranch == ASMIT_BEQ) { mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C; mBranch = ASMIT_BCC; mIns.SetSize(sz - 1); changed = true; } sz -= 1; CheckLive(); } if (sz >= 1 && mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE)) { mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0x00; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; if (mBranch == ASMIT_BEQ) mBranch = ASMIT_BPL; else mBranch = ASMIT_BMI; changed = true; } if (sz == 1 && mBranch == ASMIT_BNE && mTrueJump == this) { if (mIns[0].mType == ASMIT_DEX || mIns[0].mType == ASMIT_INX) { mIns[0] = NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, 0); changed = true; } else if (mIns[0].mType == ASMIT_DEY || mIns[0].mType == ASMIT_INY) { mIns[0] = NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0); 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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C; mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C; mIns.Push(NativeCodeInstruction(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(); #endif assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size()); if (this->mTrueJump && this->mTrueJump->PeepHoleOptimizer(proc, pass)) changed = true; if (this->mFalseJump && this->mFalseJump->PeepHoleOptimizer(proc, 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::CheckBlocks(bool sequence) { #if _DEBUG if (!mVisited) { mVisited = true; 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; 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]); } for (int j = mIns.Size() - 1; j >= 0; j--) { assert(mIns[j].mType != ASMIT_INV); if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ZERO_PAGE) assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0); if (mIns[j].mType != ASMIT_NOP) { assert(!(live & ~mIns[j].mLive)); if (mIns[j].mType == ASMIT_JSR) { assert(!(live & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y))); if (!(mIns[j].mFlags & NCIF_JSRFLAGS)) assert(!(live & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z))); } if (mIns[j].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].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_X) assert(mEntryRequiredRegs[CPU_REG_X]); if (live & LIVE_CPU_REG_Y) assert(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(NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch) { this->mTrueJump = trueJump; this->mFalseJump = falseJump; this->mBranch = branch; } void NativeCodeBasicBlock::RemoveEntryBlock(NativeCodeBasicBlock* block) { int i = mEntryBlocks.IndexOf(block); assert(i >= 0); mEntryBlocks.Remove(i); mNumEntries--; } 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 6; else if (mTrueJump == block || mFalseJump == block) return dist; else if (dist < 5) { int d0 = mTrueJump ? mTrueJump->LeadsInto(block, dist + 1) : 6; int d1 = mFalseJump ? mFalseJump->LeadsInto(block, dist + 1) : 6; if (d0 < d1) return d0; else return d1; } return 6; } void NativeCodeBasicBlock::BuildPlacement(GrowingArray& 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) { 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->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->BuildPlacement(placement); } } } void NativeCodeBasicBlock::InitialOffset(int& total) { mOffset = total; total += mCode.Size(); if (mFalseJump) { total += 5; if (mFalseJump->mPlace != mPlace + 1 && mTrueJump->mPlace != mPlace + 1) total += 3; } else if (mTrueJump) { if (mTrueJump->mPlace != mPlace + 1) total += 3; } mSize = total - mOffset; } bool NativeCodeBasicBlock::CalculateOffset(int& total) { bool changed = total != mOffset; mOffset = total; total += mCode.Size(); if (mFalseJump) { if (mFalseJump->mPlace == mPlace + 1) total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset); else if (mTrueJump->mPlace == mPlace + 1) total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset); else if ( mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace || mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace) { total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset); total += JumpByteSize(mTrueJump, mTrueJump->mOffset - total); } else { total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset); total += JumpByteSize(mFalseJump, mFalseJump->mOffset - total); } } else if (mTrueJump) { if (mTrueJump->mPlace != mPlace + 1) total += JumpByteSize(mTrueJump, mTrueJump->mOffset - total); } if (mOffset + mSize != total) changed = true; mSize = total - mOffset; return changed; } void NativeCodeBasicBlock::ShortcutTailRecursion() { if (!mVisited) { mVisited = true; if (!mFalseJump && mTrueJump && mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_RTS && mIns.Size() > 0 && mIns.Last().IsSimpleJSR()) { this->mCode[this->mCode.Size() - 3] = 0x4c; mTrueJump->mNumEntries--; mTrueJump = nullptr; } 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; } } 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 (mFalseJump->mPlace == mPlace + 1) end += PutBranch(proc, mTrueJump, mBranch, mTrueJump->mOffset - end); else if (mTrueJump->mPlace == mPlace + 1) end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), mFalseJump->mOffset - end); else if ( mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace || mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace) { end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), mFalseJump->mOffset - end); end += PutJump(proc, mTrueJump, mTrueJump->mOffset - end); } else { end += PutBranch(proc, mTrueJump, mBranch, mTrueJump->mOffset - end); end += PutJump(proc, mFalseJump, mFalseJump->mOffset - end); } } else if (mTrueJump) { if (mTrueJump->mPlace != mPlace + 1) end += PutJump(proc, mTrueJump, mTrueJump->mOffset - end); 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 (i = 0; i < mCode.Size(); i++) { target[i + mOffset] = mCode[i]; } } NativeCodeBasicBlock::NativeCodeBasicBlock(void) : mIns(NativeCodeInstruction(ASMIT_INV, ASMIM_IMPLIED)), mRelocations({ 0 }), mEntryBlocks(nullptr), mCode(0) { mBranch = ASMIT_RTS; 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; } NativeCodeBasicBlock::~NativeCodeBasicBlock(void) { } NativeCodeProcedure::NativeCodeProcedure(NativeCodeGenerator* generator) : mGenerator(generator), mRelocations({ 0 }), mBlocks(nullptr) { mTempBlocks = 1000; } NativeCodeProcedure::~NativeCodeProcedure(void) { } void NativeCodeProcedure::CompressTemporaries(void) { 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) { 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(ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } else if (tempSave > 0) { for (int i = 0; i < tempSave; i++) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject)); } } } } void NativeCodeProcedure::LoadTempsFromStack(int tempSave) { if (mInterProc->mSaveTempsLinkerObject) { if (tempSave > 3) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } else if (tempSave > 0) { for (int i = 0; i < tempSave; i++) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i)); } } } } void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; for (int i = 0; i < nblocks; i++) tblocks[i] = nullptr; mIndex = proc->mID; 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 (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 mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTS, ASMIM_IMPLIED, 0, nullptr, 0)); mEntryBlock->mTrueJump = CompileBlock(mInterProc, mInterProc->mBlocks[0]); mEntryBlock->mBranch = ASMIT_JMP; if (proc->mLeafProcedure && proc->mFastCallProcedure && !proc->mInterrupt && mNoFrame && mStackExpand == 0 && commonFrameSize == 0 && (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(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS)); mEntryBlock->mEntryRegA = true; } #endif #if 1 if (mExitBlock->mIns[0].mFlags == NCIF_LOWER) if (mExitBlock->mIns[0].mFlags == NCIF_LOWER) { mExitBlock->mIns[0].mFlags = 0; mExitBlock->mIns.Insert(0, NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mExitBlock->mExitRegA = true; proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A; } #endif } 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(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(); mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal); zpLocal |= zpGlobal; if (proc->mHardwareInterrupt) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_TXA)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_TYA)); mEntryBlock->mIns.Push(NativeCodeInstruction(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(ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } for (int i = 2; i < 256; i++) { if (zpLocal[i]) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, i)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); } } for (int i = 255; i >= 2; i--) { if (zpLocal[i]) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, i)); } } if (usesStack) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } if (proc->mHardwareInterrupt) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_TAY)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_TAX)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); } } else { if (mNoFrame) { if (mStackExpand > 0) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCS, ASMIM_RELATIVE, 2)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); ignoreExpandCommonFrame = true; if (proc->mSaveTempsLinkerObject) SaveTempsToStack(tempSave); else if (tempSave) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1)); if (tempSave == 1) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); } else if (tempSave == 2) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); } else if (commonFrameSize > 0) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } else { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } } } else if (proc->mSaveTempsLinkerObject) SaveTempsToStack(tempSave); } else { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, mStackExpand & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); if (proc->mSaveTempsLinkerObject) mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); else mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, tempSave)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); if (proc->mSaveTempsLinkerObject) SaveTempsToStack(tempSave); else if (tempSave) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK)); if (tempSave > 1) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } } mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, frameSpace + 2)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1)); } if (!proc->mLeafProcedure && commonFrameSize > 0 && !ignoreExpandCommonFrame) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); if (commonFrameSize >= 256) { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } else { mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCS, ASMIM_RELATIVE, 2)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); if (commonFrameSize >= 256) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } else { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCC, ASMIM_RELATIVE, 2)); mExitBlock->mIns.Push(NativeCodeInstruction(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(ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1)); if (tempSave == 1) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED)); } else if (tempSave == 2) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED)); } else if (commonFrameSize > 0) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } else { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } } mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCC, ASMIM_RELATIVE, 2)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } else if (proc->mSaveTempsLinkerObject) LoadTempsFromStack(tempSave); } else { if (proc->mSaveTempsLinkerObject) mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); else mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, tempSave)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1)); if (proc->mSaveTempsLinkerObject) LoadTempsFromStack(tempSave); else if (tempSave) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED)); if (tempSave > 1) { mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BPL, ASMIM_RELATIVE, -8)); } } mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, mStackExpand & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } ZeroPageSet zpLocal, zpGlobal; ResetVisited(); mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal); zpLocal |= zpGlobal; proc->mLinkerObject->mZeroPageSet = zpLocal; } if (proc->mHardwareInterrupt) mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTI, ASMIM_IMPLIED)); else mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTS, ASMIM_IMPLIED)); mEntryBlock->Assemble(); mEntryBlock = mEntryBlock->BypassEmptyBlocks(); ResetVisited(); mEntryBlock->ShortcutTailRecursion(); proc->mLinkerObject->mType = LOT_NATIVE_CODE; GrowingArray placement(nullptr); int total; total = 0; mEntryBlock->BuildPlacement(placement); for (int i = 0; i < placement.Size(); i++) placement[i]->InitialOffset(total); bool progress; do { progress = false; total = 0; for (int i = 0; i < placement.Size(); i++) if (placement[i]->CalculateOffset(total)) progress = true; } while (progress); uint8* data = proc->mLinkerObject->AddSpace(total); for (int i = 0; i < placement.Size(); i++) placement[i]->CopyCode(this, data); for (int i = 0; i < mRelocations.Size(); i++) { LinkerReference& rl(mRelocations[i]); rl.mObject = proc->mLinkerObject; if (!rl.mRefObject) rl.mRefObject = proc->mLinkerObject; proc->mLinkerObject->AddReference(rl); } } 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; } } 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); mEntryBlock->BuildDominatorTree(nullptr); } void NativeCodeProcedure::Optimize(void) { CheckFunc = !strcmp(mInterProc->mIdent->mString, "tile_draw_p"); #if 1 int step = 0; int cnt = 0; #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif bool changed, xmapped = false, ymapped = false; do { changed = false; RebuildEntry(); #if 1 if (step > 3) { ResetVisited(); if (mEntryBlock->FindSameBlocks(this)) { ResetVisited(); changed = mEntryBlock->MergeSameBlocks(this); } } #endif if (step == 4) { ResetVisited(); mEntryBlock->Split16BitLoopCount(this); } RebuildEntry(); #if 1 if (step > 3) { NativeRegisterDataSet data; bool bchanged; do { ResetVisited(); bchanged = mEntryBlock->BitFieldForwarding(data); if (!bchanged) { ResetPatched(); mEntryBlock->CheckVisited(); } } while (bchanged); } #endif if (step >= 3) { ResetVisited(); mEntryBlock->RegisterValueForwarding(); } #if 1 if (step == 2) { ResetVisited(); mEntryBlock->ReplaceFinalZeroPageUse(this); } #endif #if 1 do { RebuildEntry(); BuildDataFlowSets(); ResetVisited(); changed = mEntryBlock->RemoveUnusedResultInstructions(); if (step == 0) { ResetVisited(); if (mEntryBlock->Propagate16BitSum()) changed = true; } if (!changed) { ResetVisited(); NativeRegisterDataSet data; if (mEntryBlock->ValueForwarding(data, step > 0, step == 7)) { changed = true; } else { #if 1 ResetPatched(); mEntryBlock->CheckVisited(); if (step > 1) { ResetVisited(); if (mEntryBlock->GlobalValueForwarding(step == 7)) changed = true; } #endif } } } while (changed); #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif #if 1 ResetVisited(); if (mEntryBlock->PeepHoleOptimizer(this, step)) changed = true; #endif #if 1 if (step >= 3) { ResetVisited(); if (mEntryBlock->ReverseBitfieldForwarding()) changed = true; } #endif #if 1 if (step < 6) { 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 == 4) { ResetVisited(); if (mEntryBlock->RemoveDoubleZPStore()) changed = true; } #if 1 if (step > 0) { ResetVisited(); if (mEntryBlock->OptimizeSimpleLoop(this, step > 4)) changed = true; ResetVisited(); if (mEntryBlock->SimpleLoopReversal(this)) changed = true; } #endif #if 1 ResetVisited(); if (mEntryBlock->MergeBasicBlocks()) changed = true; #endif ResetEntryBlocks(); ResetVisited(); mEntryBlock->CollectEntryBlocks(nullptr); #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(true); #endif #if 1 if (step == 2) { if (MapFastParamsToTemps()) changed = true; } #endif #if 1 if (step > 4 && !changed) { ResetVisited(); if (mEntryBlock->ShortcutCrossBlockMoves(this)) changed = true; } #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(true); #endif #if 1 if (step > 2 && !changed) { ResetVisited(); if (mEntryBlock->JoinTailCodeSequences(this, step > 3)) changed = true; ResetVisited(); if (mEntryBlock->PropagateSinglePath()) changed = true; } #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(true); #endif #if 1 if (step == 3) { #if 1 ResetVisited(); if (mEntryBlock->OptimizeInnerLoops(this)) changed = true; #endif #if 1 ResetVisited(); if (mEntryBlock->OptimizeFindLoop(this)) changed = true; #endif #if 1 ResetVisited(); if (mEntryBlock->ReduceLocalYPressure()) changed = true; #endif #if 1 ResetVisited(); if (!changed && mEntryBlock->OptimizeGenericLoop(this)) changed = true; #endif #if 1 ResetVisited(); if (!changed && mEntryBlock->ShortcutZeroPageCopyUp(this)) changed = true; #endif #if 1 ResetVisited(); if (!changed && mEntryBlock->CrossBlockXYShortcut()) changed = true; #endif #if 1 ResetVisited(); if (!changed && mEntryBlock->CrossBlockXYPreservation()) changed = true; #endif } #endif if (step > 3 && !changed) { ResetVisited(); if (mEntryBlock->OptimizeXYSimpleLoop()) changed = true; } #if 1 if (step == 4 || step == 5) { #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] > 0) { ResetVisited(); mEntryBlock->GlobalRegisterXMap(j); if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA) mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(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] > 0) { ResetVisited(); mEntryBlock->GlobalRegisterYMap(j); if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA) mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, j)); changed = true; ymapped = true; continue; } } #endif if (!changed) { if (step == 4) { ResetVisited(); mEntryBlock->ReduceLocalXPressure(); } else { ResetVisited(); if (mEntryBlock->LocalRegisterXYMap()) changed = true; } } } #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif #if 1 ResetVisited(); NativeRegisterDataSet data; mEntryBlock->BuildEntryDataSet(data); ResetVisited(); if (mEntryBlock->ApplyEntryDataSet()) changed = true; #endif #if 1 if (step >= 4) { if (step == 8) { ResetVisited(); mEntryBlock->ReduceLocalYPressure(); } ResetVisited(); if (mEntryBlock->MoveAccuTrainsUp()) changed = true; ResetVisited(); if (mEntryBlock->MoveAccuTrainsDown()) changed = true; } #endif #if 1 if (step == 5) { ResetVisited(); if (mEntryBlock->AlternateXYUsage()) changed = true; ResetVisited(); if (mEntryBlock->OptimizeXYPairUsage()) changed = true; } #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif #if 1 ResetVisited(); if (mEntryBlock->ForwardAccuAddSub()) changed = true; #endif #if 1 ResetVisited(); if (mEntryBlock->ForwardZpYIndex(step >= 4)) changed = true; #endif #if 1 ResetVisited(); if (mEntryBlock->ForwardZpXIndex(step >= 4)) changed = true; #endif #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif #if 1 if (step == 5) { ResetVisited(); if (mEntryBlock->SimplifyDiamond(this)) changed = true; ResetVisited(); if (mEntryBlock->SimplifyLoopEnd(this)) changed = true; } #endif if (step >= 5) { ResetVisited(); if (mEntryBlock->BypassRegisterConditionBlock()) changed = true; } #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif if (step == 7) { ResetVisited(); if (mEntryBlock->SimplifyDiamond(this)) changed = true; } #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); #endif #if 1 if (step == 7) { ResetVisited(); if (mEntryBlock->CrossBlockXYFlood(this)) changed = true; } #endif #if 1 if (step == 7) { ResetVisited(); if (mEntryBlock->CrossBlockY2XFlood(this)) changed = true; } #endif #if 1 if (step >= 6) { ResetVisited(); if (mEntryBlock->ExpandADCToBranch(this)) changed = true; } #endif #if 1 if (step == 2 && !changed) { ResetVisited(); if (mEntryBlock->CrossBlockStoreLoadBypass(this)) changed = true; } #endif #endif #if 1 if (cnt > 190) { printf("Opps\n"); } #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 < 9) { cnt = 0; step++; changed = true; } #endif else cnt++; } while (changed); #if 1 ResetVisited(); mEntryBlock->ReduceLocalYPressure(); #endif #if 1 CompressTemporaries(); #endif #if 1 do { RebuildEntry(); BuildDataFlowSets(); ResetVisited(); changed = mEntryBlock->RemoveUnusedResultInstructions(); if (!changed) { ResetVisited(); NativeRegisterDataSet data; if (mEntryBlock->ValueForwarding(data, true, true)) { changed = true; } else { #if 1 ResetPatched(); mEntryBlock->CheckVisited(); ResetVisited(); if (mEntryBlock->GlobalValueForwarding(true)) changed = true; #endif } } if (!changed) { ResetVisited(); changed = mEntryBlock->PeepHoleOptimizer(this, 10); } if (!changed) { ResetVisited(); changed = mEntryBlock->JoinTailCodeSequences(this, true); } } while (changed); #endif #if 1 ResetVisited(); mEntryBlock->BlockSizeReduction(this, -1, -1); #endif #endif } void NativeCodeProcedure::BuildDataFlowSets(void) { // // Build set with local provided/required temporaries // ResetVisited(); mBlocks[0]->BuildLocalRegSets(); // // Build set of globaly provided temporaries // ResetVisited(); mBlocks[0]->BuildGlobalProvidedRegSet(NumberSet(NUM_REGS)); // // Build set of globaly 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(); 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(); 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::ResetPatched(void) { for (int i = 0; i < mBlocks.Size(); i++) { mBlocks[i]->mPatched = false; mBlocks[i]->mPatchFail = false; mBlocks[i]->mPatchChecked = false; mBlocks[i]->mPatchStart = false; mBlocks[i]->mPatchLoop = false; mBlocks[i]->mPatchLoopChanged = false; mBlocks[i]->mPatchExit = 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: 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].mFinal && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && 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].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].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].mFinal && iblock->mInstructions[i + 2]->mSrc[1].mTemp == ins->mDst.mTemp && 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].mFinal && iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && 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].mFinal) { block->LoadEffectiveAddress(iproc, iblock->mInstructions[i + 1], ins, nullptr, false); i++; } else block->LoadValue(iproc, ins); break; case IC_COPY: block = block->CopyValue(iproc, ins, this); break; case IC_STRCPY: block = block->StrcpyValue(iproc, ins, this); 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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + i)); block->mIns.Push(NativeCodeInstruction(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 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 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 && (InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] == 1 || ins->mSrc[1].mTemp != iblock->mInstructions[i + 1]->mDst.mTemp) && (InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] == 1 || iblock->mInstructions[i + 1]->mSrc[0].mStride == 1)) { block->LoadByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); i++; } else if (i + 1 < iblock->mInstructions.Size() && iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 && iblock->mInstructions[i + 1]->mSrc[1].mIntConst == 0 && (iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) && (InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] == 1 || iblock->mInstructions[i + 1]->mSrc[1].mStride == 1)) { block->StoreByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); i++; } else if (i + 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_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(ASMIT_SEC, ASMIM_IMPLIED)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); block->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); block->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } break; case IC_POP_FRAME: { block->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); block->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); block->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff)); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, 1)); tblock->Close(rblock, nullptr, ASMIT_JMP); fblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); fblock->Close(rblock, nullptr, ASMIT_JMP); rblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp])); if (InterTypeSize[ins->mDst.mType] > 1) { rblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); rblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + 1)); } block = rblock; } break; case IC_RETURN_VALUE: { if (ins->mSrc[0].mTemp < 0) { if (ins->mSrc[0].mType == IT_FLOAT) { union { float f; unsigned int v; } cc; cc.f = ins->mSrc[0].mFloatConst; block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mExitBlock->mIns[0].mFlags |= NCIF_LOWER | NCIF_UPPER | NCIF_LONG; } else { block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mExitBlock->mIns[0].mFlags |= NCIF_LONG; } } } } else { block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp])); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1)); block->mIns.Push(NativeCodeInstruction(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(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3)); mExitBlock->mIns[0].mFlags |= NCIF_LONG; } } } block->Close(mExitBlock, nullptr, ASMIT_JMP); return; } case IC_RETURN: block->Close(mExitBlock, nullptr, ASMIT_JMP); return; case IC_TYPECAST: if (ins->mSrc[0].mTemp != ins->mDst.mTemp) { block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp])); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp])); if (InterTypeSize[ins->mDst.mType] > 1) { block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1)); block->mIns.Push(NativeCodeInstruction(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(CompileBlock(iproc, iblock->mFalseJump), nullptr, ASMIT_JMP); else block->Close(CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP); } else { block->mIns.Push(NativeCodeInstruction(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(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(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2)); block->mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3)); } block->Close(CompileBlock(iproc, iblock->mTrueJump), CompileBlock(iproc, iblock->mFalseJump), ASMIT_BNE); } return; case IC_UNREACHABLE: block->Close(mExitBlock, nullptr, ASMIT_JMP); return; } i++; } block->Close(CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP); } NativeCodeGenerator::NativeCodeGenerator(Errors* errors, Linker* linker, LinkerSection* runtimeSection) : mErrors(errors), mLinker(linker), mRuntimeSection(runtimeSection), mCompilerOptions(COPT_DEFAULT), mRuntime({ 0 }), mMulTables({nullptr}) { } NativeCodeGenerator::~NativeCodeGenerator(void) { } void NativeCodeGenerator::CompleteRuntime(void) { for (int i = 0; i < mMulTables.Size(); i++) { const MulTable& m(mMulTables[i]); 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); } } } LinkerObject* NativeCodeGenerator::AllocateShortMulTable(InterOperator op, int factor, int size, bool msb) { 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.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, "Undefied runtime function", ident->mString); return mRuntime[i]; } void NativeCodeGenerator::RegisterRuntime(const Ident* ident, LinkerObject* object, int offset) { Runtime rt; rt.mIdent = ident; rt.mLinkerObject = object; rt.mOffset = offset; mRuntime.Push(rt); }